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 local_player: PlayerColor,
  551    pub text: TextStyle,
  552    pub scrollbar_width: Pixels,
  553    pub syntax: Arc<SyntaxTheme>,
  554    pub status: StatusColors,
  555    pub inlay_hints_style: HighlightStyle,
  556    pub inline_completion_styles: InlineCompletionStyles,
  557    pub unnecessary_code_fade: f32,
  558    pub show_underlines: bool,
  559}
  560
  561impl Default for EditorStyle {
  562    fn default() -> Self {
  563        Self {
  564            background: Hsla::default(),
  565            local_player: PlayerColor::default(),
  566            text: TextStyle::default(),
  567            scrollbar_width: Pixels::default(),
  568            syntax: Default::default(),
  569            // HACK: Status colors don't have a real default.
  570            // We should look into removing the status colors from the editor
  571            // style and retrieve them directly from the theme.
  572            status: StatusColors::dark(),
  573            inlay_hints_style: HighlightStyle::default(),
  574            inline_completion_styles: InlineCompletionStyles {
  575                insertion: HighlightStyle::default(),
  576                whitespace: HighlightStyle::default(),
  577            },
  578            unnecessary_code_fade: Default::default(),
  579            show_underlines: true,
  580        }
  581    }
  582}
  583
  584pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  585    let show_background = language_settings::language_settings(None, None, cx)
  586        .inlay_hints
  587        .show_background;
  588
  589    HighlightStyle {
  590        color: Some(cx.theme().status().hint),
  591        background_color: show_background.then(|| cx.theme().status().hint_background),
  592        ..HighlightStyle::default()
  593    }
  594}
  595
  596pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  597    InlineCompletionStyles {
  598        insertion: HighlightStyle {
  599            color: Some(cx.theme().status().predictive),
  600            ..HighlightStyle::default()
  601        },
  602        whitespace: HighlightStyle {
  603            background_color: Some(cx.theme().status().created_background),
  604            ..HighlightStyle::default()
  605        },
  606    }
  607}
  608
  609type CompletionId = usize;
  610
  611pub(crate) enum EditDisplayMode {
  612    TabAccept,
  613    DiffPopover,
  614    Inline,
  615}
  616
  617enum InlineCompletion {
  618    Edit {
  619        edits: Vec<(Range<Anchor>, String)>,
  620        edit_preview: Option<EditPreview>,
  621        display_mode: EditDisplayMode,
  622        snapshot: BufferSnapshot,
  623    },
  624    Move {
  625        target: Anchor,
  626        snapshot: BufferSnapshot,
  627    },
  628}
  629
  630struct InlineCompletionState {
  631    inlay_ids: Vec<InlayId>,
  632    completion: InlineCompletion,
  633    completion_id: Option<SharedString>,
  634    invalidation_range: Range<Anchor>,
  635}
  636
  637enum EditPredictionSettings {
  638    Disabled,
  639    Enabled {
  640        show_in_menu: bool,
  641        preview_requires_modifier: bool,
  642    },
  643}
  644
  645enum InlineCompletionHighlight {}
  646
  647#[derive(Debug, Clone)]
  648struct InlineDiagnostic {
  649    message: SharedString,
  650    group_id: usize,
  651    is_primary: bool,
  652    start: Point,
  653    severity: lsp::DiagnosticSeverity,
  654}
  655
  656pub enum MenuInlineCompletionsPolicy {
  657    Never,
  658    ByProvider,
  659}
  660
  661pub enum EditPredictionPreview {
  662    /// Modifier is not pressed
  663    Inactive { released_too_fast: bool },
  664    /// Modifier pressed
  665    Active {
  666        since: Instant,
  667        previous_scroll_position: Option<ScrollAnchor>,
  668    },
  669}
  670
  671impl EditPredictionPreview {
  672    pub fn released_too_fast(&self) -> bool {
  673        match self {
  674            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  675            EditPredictionPreview::Active { .. } => false,
  676        }
  677    }
  678
  679    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  680        if let EditPredictionPreview::Active {
  681            previous_scroll_position,
  682            ..
  683        } = self
  684        {
  685            *previous_scroll_position = scroll_position;
  686        }
  687    }
  688}
  689
  690pub struct ContextMenuOptions {
  691    pub min_entries_visible: usize,
  692    pub max_entries_visible: usize,
  693    pub placement: Option<ContextMenuPlacement>,
  694}
  695
  696#[derive(Debug, Clone, PartialEq, Eq)]
  697pub enum ContextMenuPlacement {
  698    Above,
  699    Below,
  700}
  701
  702#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  703struct EditorActionId(usize);
  704
  705impl EditorActionId {
  706    pub fn post_inc(&mut self) -> Self {
  707        let answer = self.0;
  708
  709        *self = Self(answer + 1);
  710
  711        Self(answer)
  712    }
  713}
  714
  715// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  716// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  717
  718type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  719type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  720
  721#[derive(Default)]
  722struct ScrollbarMarkerState {
  723    scrollbar_size: Size<Pixels>,
  724    dirty: bool,
  725    markers: Arc<[PaintQuad]>,
  726    pending_refresh: Option<Task<Result<()>>>,
  727}
  728
  729impl ScrollbarMarkerState {
  730    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  731        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  732    }
  733}
  734
  735#[derive(Clone, Copy, PartialEq, Eq)]
  736pub enum MinimapVisibility {
  737    Disabled,
  738    Enabled {
  739        /// The configuration currently present in the users settings.
  740        setting_configuration: bool,
  741        /// Whether to override the currently set visibility from the users setting.
  742        toggle_override: bool,
  743    },
  744}
  745
  746impl MinimapVisibility {
  747    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  748        if mode.is_full() {
  749            Self::Enabled {
  750                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  751                toggle_override: false,
  752            }
  753        } else {
  754            Self::Disabled
  755        }
  756    }
  757
  758    fn hidden(&self) -> Self {
  759        match *self {
  760            Self::Enabled {
  761                setting_configuration,
  762                ..
  763            } => Self::Enabled {
  764                setting_configuration,
  765                toggle_override: setting_configuration,
  766            },
  767            Self::Disabled => Self::Disabled,
  768        }
  769    }
  770
  771    fn disabled(&self) -> bool {
  772        match *self {
  773            Self::Disabled => true,
  774            _ => false,
  775        }
  776    }
  777
  778    fn settings_visibility(&self) -> bool {
  779        match *self {
  780            Self::Enabled {
  781                setting_configuration,
  782                ..
  783            } => setting_configuration,
  784            _ => false,
  785        }
  786    }
  787
  788    fn visible(&self) -> bool {
  789        match *self {
  790            Self::Enabled {
  791                setting_configuration,
  792                toggle_override,
  793            } => setting_configuration ^ toggle_override,
  794            _ => false,
  795        }
  796    }
  797
  798    fn toggle_visibility(&self) -> Self {
  799        match *self {
  800            Self::Enabled {
  801                toggle_override,
  802                setting_configuration,
  803            } => Self::Enabled {
  804                setting_configuration,
  805                toggle_override: !toggle_override,
  806            },
  807            Self::Disabled => Self::Disabled,
  808        }
  809    }
  810}
  811
  812#[derive(Clone, Debug)]
  813struct RunnableTasks {
  814    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  815    offset: multi_buffer::Anchor,
  816    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  817    column: u32,
  818    // Values of all named captures, including those starting with '_'
  819    extra_variables: HashMap<String, String>,
  820    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  821    context_range: Range<BufferOffset>,
  822}
  823
  824impl RunnableTasks {
  825    fn resolve<'a>(
  826        &'a self,
  827        cx: &'a task::TaskContext,
  828    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  829        self.templates.iter().filter_map(|(kind, template)| {
  830            template
  831                .resolve_task(&kind.to_id_base(), cx)
  832                .map(|task| (kind.clone(), task))
  833        })
  834    }
  835}
  836
  837#[derive(Clone)]
  838pub struct ResolvedTasks {
  839    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  840    position: Anchor,
  841}
  842
  843#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  844struct BufferOffset(usize);
  845
  846// Addons allow storing per-editor state in other crates (e.g. Vim)
  847pub trait Addon: 'static {
  848    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  849
  850    fn render_buffer_header_controls(
  851        &self,
  852        _: &ExcerptInfo,
  853        _: &Window,
  854        _: &App,
  855    ) -> Option<AnyElement> {
  856        None
  857    }
  858
  859    fn to_any(&self) -> &dyn std::any::Any;
  860
  861    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  862        None
  863    }
  864}
  865
  866/// A set of caret positions, registered when the editor was edited.
  867pub struct ChangeList {
  868    changes: Vec<Vec<Anchor>>,
  869    /// Currently "selected" change.
  870    position: Option<usize>,
  871}
  872
  873impl ChangeList {
  874    pub fn new() -> Self {
  875        Self {
  876            changes: Vec::new(),
  877            position: None,
  878        }
  879    }
  880
  881    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  882    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  883    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  884        if self.changes.is_empty() {
  885            return None;
  886        }
  887
  888        let prev = self.position.unwrap_or(self.changes.len());
  889        let next = if direction == Direction::Prev {
  890            prev.saturating_sub(count)
  891        } else {
  892            (prev + count).min(self.changes.len() - 1)
  893        };
  894        self.position = Some(next);
  895        self.changes.get(next).map(|anchors| anchors.as_slice())
  896    }
  897
  898    /// Adds a new change to the list, resetting the change list position.
  899    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  900        self.position.take();
  901        if pop_state {
  902            self.changes.pop();
  903        }
  904        self.changes.push(new_positions.clone());
  905    }
  906
  907    pub fn last(&self) -> Option<&[Anchor]> {
  908        self.changes.last().map(|anchors| anchors.as_slice())
  909    }
  910}
  911
  912#[derive(Clone)]
  913struct InlineBlamePopoverState {
  914    scroll_handle: ScrollHandle,
  915    commit_message: Option<ParsedCommitMessage>,
  916    markdown: Entity<Markdown>,
  917}
  918
  919struct InlineBlamePopover {
  920    position: gpui::Point<Pixels>,
  921    hide_task: Option<Task<()>>,
  922    popover_bounds: Option<Bounds<Pixels>>,
  923    popover_state: InlineBlamePopoverState,
  924}
  925
  926enum SelectionDragState {
  927    /// State when no drag related activity is detected.
  928    None,
  929    /// State when the mouse is down on a selection that is about to be dragged.
  930    ReadyToDrag {
  931        selection: Selection<Anchor>,
  932        click_position: gpui::Point<Pixels>,
  933        mouse_down_time: Instant,
  934    },
  935    /// State when the mouse is dragging the selection in the editor.
  936    Dragging {
  937        selection: Selection<Anchor>,
  938        drop_cursor: Selection<Anchor>,
  939        hide_drop_cursor: bool,
  940    },
  941}
  942
  943enum ColumnarSelectionState {
  944    FromMouse {
  945        selection_tail: Anchor,
  946        display_point: Option<DisplayPoint>,
  947    },
  948    FromSelection {
  949        selection_tail: Anchor,
  950    },
  951}
  952
  953/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  954/// a breakpoint on them.
  955#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  956struct PhantomBreakpointIndicator {
  957    display_row: DisplayRow,
  958    /// There's a small debounce between hovering over the line and showing the indicator.
  959    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  960    is_active: bool,
  961    collides_with_existing_breakpoint: bool,
  962}
  963
  964/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  965///
  966/// See the [module level documentation](self) for more information.
  967pub struct Editor {
  968    focus_handle: FocusHandle,
  969    last_focused_descendant: Option<WeakFocusHandle>,
  970    /// The text buffer being edited
  971    buffer: Entity<MultiBuffer>,
  972    /// Map of how text in the buffer should be displayed.
  973    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  974    pub display_map: Entity<DisplayMap>,
  975    pub selections: SelectionsCollection,
  976    pub scroll_manager: ScrollManager,
  977    /// When inline assist editors are linked, they all render cursors because
  978    /// typing enters text into each of them, even the ones that aren't focused.
  979    pub(crate) show_cursor_when_unfocused: bool,
  980    columnar_selection_state: Option<ColumnarSelectionState>,
  981    add_selections_state: Option<AddSelectionsState>,
  982    select_next_state: Option<SelectNextState>,
  983    select_prev_state: Option<SelectNextState>,
  984    selection_history: SelectionHistory,
  985    defer_selection_effects: bool,
  986    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  987    autoclose_regions: Vec<AutocloseRegion>,
  988    snippet_stack: InvalidationStack<SnippetState>,
  989    select_syntax_node_history: SelectSyntaxNodeHistory,
  990    ime_transaction: Option<TransactionId>,
  991    pub diagnostics_max_severity: DiagnosticSeverity,
  992    active_diagnostics: ActiveDiagnostic,
  993    show_inline_diagnostics: bool,
  994    inline_diagnostics_update: Task<()>,
  995    inline_diagnostics_enabled: bool,
  996    diagnostics_enabled: bool,
  997    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  998    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  999    hard_wrap: Option<usize>,
 1000
 1001    // TODO: make this a access method
 1002    pub project: Option<Entity<Project>>,
 1003    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1004    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1005    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1006    blink_manager: Entity<BlinkManager>,
 1007    show_cursor_names: bool,
 1008    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1009    pub show_local_selections: bool,
 1010    mode: EditorMode,
 1011    show_breadcrumbs: bool,
 1012    show_gutter: bool,
 1013    show_scrollbars: ScrollbarAxes,
 1014    minimap_visibility: MinimapVisibility,
 1015    offset_content: bool,
 1016    disable_expand_excerpt_buttons: bool,
 1017    show_line_numbers: Option<bool>,
 1018    use_relative_line_numbers: Option<bool>,
 1019    show_git_diff_gutter: Option<bool>,
 1020    show_code_actions: Option<bool>,
 1021    show_runnables: Option<bool>,
 1022    show_breakpoints: Option<bool>,
 1023    show_wrap_guides: Option<bool>,
 1024    show_indent_guides: Option<bool>,
 1025    placeholder_text: Option<Arc<str>>,
 1026    highlight_order: usize,
 1027    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1028    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1029    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1030    scrollbar_marker_state: ScrollbarMarkerState,
 1031    active_indent_guides_state: ActiveIndentGuidesState,
 1032    nav_history: Option<ItemNavHistory>,
 1033    context_menu: RefCell<Option<CodeContextMenu>>,
 1034    context_menu_options: Option<ContextMenuOptions>,
 1035    mouse_context_menu: Option<MouseContextMenu>,
 1036    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1037    inline_blame_popover: Option<InlineBlamePopover>,
 1038    inline_blame_popover_show_task: Option<Task<()>>,
 1039    signature_help_state: SignatureHelpState,
 1040    auto_signature_help: Option<bool>,
 1041    find_all_references_task_sources: Vec<Anchor>,
 1042    next_completion_id: CompletionId,
 1043    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1044    code_actions_task: Option<Task<Result<()>>>,
 1045    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1046    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1047    document_highlights_task: Option<Task<()>>,
 1048    linked_editing_range_task: Option<Task<Option<()>>>,
 1049    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1050    pending_rename: Option<RenameState>,
 1051    searchable: bool,
 1052    cursor_shape: CursorShape,
 1053    current_line_highlight: Option<CurrentLineHighlight>,
 1054    collapse_matches: bool,
 1055    autoindent_mode: Option<AutoindentMode>,
 1056    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1057    input_enabled: bool,
 1058    use_modal_editing: bool,
 1059    read_only: bool,
 1060    leader_id: Option<CollaboratorId>,
 1061    remote_id: Option<ViewId>,
 1062    pub hover_state: HoverState,
 1063    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1064    gutter_hovered: bool,
 1065    hovered_link_state: Option<HoveredLinkState>,
 1066    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1067    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1068    active_inline_completion: Option<InlineCompletionState>,
 1069    /// Used to prevent flickering as the user types while the menu is open
 1070    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1071    edit_prediction_settings: EditPredictionSettings,
 1072    inline_completions_hidden_for_vim_mode: bool,
 1073    show_inline_completions_override: Option<bool>,
 1074    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1075    edit_prediction_preview: EditPredictionPreview,
 1076    edit_prediction_indent_conflict: bool,
 1077    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1078    inlay_hint_cache: InlayHintCache,
 1079    next_inlay_id: usize,
 1080    _subscriptions: Vec<Subscription>,
 1081    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1082    gutter_dimensions: GutterDimensions,
 1083    style: Option<EditorStyle>,
 1084    text_style_refinement: Option<TextStyleRefinement>,
 1085    next_editor_action_id: EditorActionId,
 1086    editor_actions: Rc<
 1087        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1088    >,
 1089    use_autoclose: bool,
 1090    use_auto_surround: bool,
 1091    auto_replace_emoji_shortcode: bool,
 1092    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1093    show_git_blame_gutter: bool,
 1094    show_git_blame_inline: bool,
 1095    show_git_blame_inline_delay_task: Option<Task<()>>,
 1096    git_blame_inline_enabled: bool,
 1097    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1098    serialize_dirty_buffers: bool,
 1099    show_selection_menu: Option<bool>,
 1100    blame: Option<Entity<GitBlame>>,
 1101    blame_subscription: Option<Subscription>,
 1102    custom_context_menu: Option<
 1103        Box<
 1104            dyn 'static
 1105                + Fn(
 1106                    &mut Self,
 1107                    DisplayPoint,
 1108                    &mut Window,
 1109                    &mut Context<Self>,
 1110                ) -> Option<Entity<ui::ContextMenu>>,
 1111        >,
 1112    >,
 1113    last_bounds: Option<Bounds<Pixels>>,
 1114    last_position_map: Option<Rc<PositionMap>>,
 1115    expect_bounds_change: Option<Bounds<Pixels>>,
 1116    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1117    tasks_update_task: Option<Task<()>>,
 1118    breakpoint_store: Option<Entity<BreakpointStore>>,
 1119    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1120    hovered_diff_hunk_row: Option<DisplayRow>,
 1121    pull_diagnostics_task: Task<()>,
 1122    in_project_search: bool,
 1123    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1124    breadcrumb_header: Option<String>,
 1125    focused_block: Option<FocusedBlock>,
 1126    next_scroll_position: NextScrollCursorCenterTopBottom,
 1127    addons: HashMap<TypeId, Box<dyn Addon>>,
 1128    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1129    load_diff_task: Option<Shared<Task<()>>>,
 1130    /// Whether we are temporarily displaying a diff other than git's
 1131    temporary_diff_override: bool,
 1132    selection_mark_mode: bool,
 1133    toggle_fold_multiple_buffers: Task<()>,
 1134    _scroll_cursor_center_top_bottom_task: Task<()>,
 1135    serialize_selections: Task<()>,
 1136    serialize_folds: Task<()>,
 1137    mouse_cursor_hidden: bool,
 1138    minimap: Option<Entity<Self>>,
 1139    hide_mouse_mode: HideMouseMode,
 1140    pub change_list: ChangeList,
 1141    inline_value_cache: InlineValueCache,
 1142    selection_drag_state: SelectionDragState,
 1143    drag_and_drop_selection_enabled: bool,
 1144    next_color_inlay_id: usize,
 1145    colors: Option<LspColorData>,
 1146}
 1147
 1148#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1149enum NextScrollCursorCenterTopBottom {
 1150    #[default]
 1151    Center,
 1152    Top,
 1153    Bottom,
 1154}
 1155
 1156impl NextScrollCursorCenterTopBottom {
 1157    fn next(&self) -> Self {
 1158        match self {
 1159            Self::Center => Self::Top,
 1160            Self::Top => Self::Bottom,
 1161            Self::Bottom => Self::Center,
 1162        }
 1163    }
 1164}
 1165
 1166#[derive(Clone)]
 1167pub struct EditorSnapshot {
 1168    pub mode: EditorMode,
 1169    show_gutter: bool,
 1170    show_line_numbers: Option<bool>,
 1171    show_git_diff_gutter: Option<bool>,
 1172    show_code_actions: Option<bool>,
 1173    show_runnables: Option<bool>,
 1174    show_breakpoints: Option<bool>,
 1175    git_blame_gutter_max_author_length: Option<usize>,
 1176    pub display_snapshot: DisplaySnapshot,
 1177    pub placeholder_text: Option<Arc<str>>,
 1178    is_focused: bool,
 1179    scroll_anchor: ScrollAnchor,
 1180    ongoing_scroll: OngoingScroll,
 1181    current_line_highlight: CurrentLineHighlight,
 1182    gutter_hovered: bool,
 1183}
 1184
 1185#[derive(Default, Debug, Clone, Copy)]
 1186pub struct GutterDimensions {
 1187    pub left_padding: Pixels,
 1188    pub right_padding: Pixels,
 1189    pub width: Pixels,
 1190    pub margin: Pixels,
 1191    pub git_blame_entries_width: Option<Pixels>,
 1192}
 1193
 1194impl GutterDimensions {
 1195    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1196        Self {
 1197            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1198            ..Default::default()
 1199        }
 1200    }
 1201
 1202    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1203        -cx.text_system().descent(font_id, font_size)
 1204    }
 1205    /// The full width of the space taken up by the gutter.
 1206    pub fn full_width(&self) -> Pixels {
 1207        self.margin + self.width
 1208    }
 1209
 1210    /// The width of the space reserved for the fold indicators,
 1211    /// use alongside 'justify_end' and `gutter_width` to
 1212    /// right align content with the line numbers
 1213    pub fn fold_area_width(&self) -> Pixels {
 1214        self.margin + self.right_padding
 1215    }
 1216}
 1217
 1218#[derive(Debug)]
 1219pub struct RemoteSelection {
 1220    pub replica_id: ReplicaId,
 1221    pub selection: Selection<Anchor>,
 1222    pub cursor_shape: CursorShape,
 1223    pub collaborator_id: CollaboratorId,
 1224    pub line_mode: bool,
 1225    pub user_name: Option<SharedString>,
 1226    pub color: PlayerColor,
 1227}
 1228
 1229#[derive(Clone, Debug)]
 1230struct SelectionHistoryEntry {
 1231    selections: Arc<[Selection<Anchor>]>,
 1232    select_next_state: Option<SelectNextState>,
 1233    select_prev_state: Option<SelectNextState>,
 1234    add_selections_state: Option<AddSelectionsState>,
 1235}
 1236
 1237#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1238enum SelectionHistoryMode {
 1239    Normal,
 1240    Undoing,
 1241    Redoing,
 1242    Skipping,
 1243}
 1244
 1245#[derive(Clone, PartialEq, Eq, Hash)]
 1246struct HoveredCursor {
 1247    replica_id: u16,
 1248    selection_id: usize,
 1249}
 1250
 1251impl Default for SelectionHistoryMode {
 1252    fn default() -> Self {
 1253        Self::Normal
 1254    }
 1255}
 1256
 1257#[derive(Debug)]
 1258pub struct SelectionEffects {
 1259    nav_history: bool,
 1260    completions: bool,
 1261    scroll: Option<Autoscroll>,
 1262}
 1263
 1264impl Default for SelectionEffects {
 1265    fn default() -> Self {
 1266        Self {
 1267            nav_history: true,
 1268            completions: true,
 1269            scroll: Some(Autoscroll::fit()),
 1270        }
 1271    }
 1272}
 1273impl SelectionEffects {
 1274    pub fn scroll(scroll: Autoscroll) -> Self {
 1275        Self {
 1276            scroll: Some(scroll),
 1277            ..Default::default()
 1278        }
 1279    }
 1280
 1281    pub fn no_scroll() -> Self {
 1282        Self {
 1283            scroll: None,
 1284            ..Default::default()
 1285        }
 1286    }
 1287
 1288    pub fn completions(self, completions: bool) -> Self {
 1289        Self {
 1290            completions,
 1291            ..self
 1292        }
 1293    }
 1294
 1295    pub fn nav_history(self, nav_history: bool) -> Self {
 1296        Self {
 1297            nav_history,
 1298            ..self
 1299        }
 1300    }
 1301}
 1302
 1303struct DeferredSelectionEffectsState {
 1304    changed: bool,
 1305    effects: SelectionEffects,
 1306    old_cursor_position: Anchor,
 1307    history_entry: SelectionHistoryEntry,
 1308}
 1309
 1310#[derive(Default)]
 1311struct SelectionHistory {
 1312    #[allow(clippy::type_complexity)]
 1313    selections_by_transaction:
 1314        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1315    mode: SelectionHistoryMode,
 1316    undo_stack: VecDeque<SelectionHistoryEntry>,
 1317    redo_stack: VecDeque<SelectionHistoryEntry>,
 1318}
 1319
 1320impl SelectionHistory {
 1321    #[track_caller]
 1322    fn insert_transaction(
 1323        &mut self,
 1324        transaction_id: TransactionId,
 1325        selections: Arc<[Selection<Anchor>]>,
 1326    ) {
 1327        if selections.is_empty() {
 1328            log::error!(
 1329                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1330                std::panic::Location::caller()
 1331            );
 1332            return;
 1333        }
 1334        self.selections_by_transaction
 1335            .insert(transaction_id, (selections, None));
 1336    }
 1337
 1338    #[allow(clippy::type_complexity)]
 1339    fn transaction(
 1340        &self,
 1341        transaction_id: TransactionId,
 1342    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1343        self.selections_by_transaction.get(&transaction_id)
 1344    }
 1345
 1346    #[allow(clippy::type_complexity)]
 1347    fn transaction_mut(
 1348        &mut self,
 1349        transaction_id: TransactionId,
 1350    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1351        self.selections_by_transaction.get_mut(&transaction_id)
 1352    }
 1353
 1354    fn push(&mut self, entry: SelectionHistoryEntry) {
 1355        if !entry.selections.is_empty() {
 1356            match self.mode {
 1357                SelectionHistoryMode::Normal => {
 1358                    self.push_undo(entry);
 1359                    self.redo_stack.clear();
 1360                }
 1361                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1362                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1363                SelectionHistoryMode::Skipping => {}
 1364            }
 1365        }
 1366    }
 1367
 1368    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1369        if self
 1370            .undo_stack
 1371            .back()
 1372            .map_or(true, |e| e.selections != entry.selections)
 1373        {
 1374            self.undo_stack.push_back(entry);
 1375            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1376                self.undo_stack.pop_front();
 1377            }
 1378        }
 1379    }
 1380
 1381    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1382        if self
 1383            .redo_stack
 1384            .back()
 1385            .map_or(true, |e| e.selections != entry.selections)
 1386        {
 1387            self.redo_stack.push_back(entry);
 1388            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1389                self.redo_stack.pop_front();
 1390            }
 1391        }
 1392    }
 1393}
 1394
 1395#[derive(Clone, Copy)]
 1396pub struct RowHighlightOptions {
 1397    pub autoscroll: bool,
 1398    pub include_gutter: bool,
 1399}
 1400
 1401impl Default for RowHighlightOptions {
 1402    fn default() -> Self {
 1403        Self {
 1404            autoscroll: Default::default(),
 1405            include_gutter: true,
 1406        }
 1407    }
 1408}
 1409
 1410struct RowHighlight {
 1411    index: usize,
 1412    range: Range<Anchor>,
 1413    color: Hsla,
 1414    options: RowHighlightOptions,
 1415    type_id: TypeId,
 1416}
 1417
 1418#[derive(Clone, Debug)]
 1419struct AddSelectionsState {
 1420    groups: Vec<AddSelectionsGroup>,
 1421}
 1422
 1423#[derive(Clone, Debug)]
 1424struct AddSelectionsGroup {
 1425    above: bool,
 1426    stack: Vec<usize>,
 1427}
 1428
 1429#[derive(Clone)]
 1430struct SelectNextState {
 1431    query: AhoCorasick,
 1432    wordwise: bool,
 1433    done: bool,
 1434}
 1435
 1436impl std::fmt::Debug for SelectNextState {
 1437    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1438        f.debug_struct(std::any::type_name::<Self>())
 1439            .field("wordwise", &self.wordwise)
 1440            .field("done", &self.done)
 1441            .finish()
 1442    }
 1443}
 1444
 1445#[derive(Debug)]
 1446struct AutocloseRegion {
 1447    selection_id: usize,
 1448    range: Range<Anchor>,
 1449    pair: BracketPair,
 1450}
 1451
 1452#[derive(Debug)]
 1453struct SnippetState {
 1454    ranges: Vec<Vec<Range<Anchor>>>,
 1455    active_index: usize,
 1456    choices: Vec<Option<Vec<String>>>,
 1457}
 1458
 1459#[doc(hidden)]
 1460pub struct RenameState {
 1461    pub range: Range<Anchor>,
 1462    pub old_name: Arc<str>,
 1463    pub editor: Entity<Editor>,
 1464    block_id: CustomBlockId,
 1465}
 1466
 1467struct InvalidationStack<T>(Vec<T>);
 1468
 1469struct RegisteredInlineCompletionProvider {
 1470    provider: Arc<dyn InlineCompletionProviderHandle>,
 1471    _subscription: Subscription,
 1472}
 1473
 1474#[derive(Debug, PartialEq, Eq)]
 1475pub struct ActiveDiagnosticGroup {
 1476    pub active_range: Range<Anchor>,
 1477    pub active_message: String,
 1478    pub group_id: usize,
 1479    pub blocks: HashSet<CustomBlockId>,
 1480}
 1481
 1482#[derive(Debug, PartialEq, Eq)]
 1483
 1484pub(crate) enum ActiveDiagnostic {
 1485    None,
 1486    All,
 1487    Group(ActiveDiagnosticGroup),
 1488}
 1489
 1490#[derive(Serialize, Deserialize, Clone, Debug)]
 1491pub struct ClipboardSelection {
 1492    /// The number of bytes in this selection.
 1493    pub len: usize,
 1494    /// Whether this was a full-line selection.
 1495    pub is_entire_line: bool,
 1496    /// The indentation of the first line when this content was originally copied.
 1497    pub first_line_indent: u32,
 1498}
 1499
 1500// selections, scroll behavior, was newest selection reversed
 1501type SelectSyntaxNodeHistoryState = (
 1502    Box<[Selection<usize>]>,
 1503    SelectSyntaxNodeScrollBehavior,
 1504    bool,
 1505);
 1506
 1507#[derive(Default)]
 1508struct SelectSyntaxNodeHistory {
 1509    stack: Vec<SelectSyntaxNodeHistoryState>,
 1510    // disable temporarily to allow changing selections without losing the stack
 1511    pub disable_clearing: bool,
 1512}
 1513
 1514impl SelectSyntaxNodeHistory {
 1515    pub fn try_clear(&mut self) {
 1516        if !self.disable_clearing {
 1517            self.stack.clear();
 1518        }
 1519    }
 1520
 1521    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1522        self.stack.push(selection);
 1523    }
 1524
 1525    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1526        self.stack.pop()
 1527    }
 1528}
 1529
 1530enum SelectSyntaxNodeScrollBehavior {
 1531    CursorTop,
 1532    FitSelection,
 1533    CursorBottom,
 1534}
 1535
 1536#[derive(Debug)]
 1537pub(crate) struct NavigationData {
 1538    cursor_anchor: Anchor,
 1539    cursor_position: Point,
 1540    scroll_anchor: ScrollAnchor,
 1541    scroll_top_row: u32,
 1542}
 1543
 1544#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1545pub enum GotoDefinitionKind {
 1546    Symbol,
 1547    Declaration,
 1548    Type,
 1549    Implementation,
 1550}
 1551
 1552#[derive(Debug, Clone)]
 1553enum InlayHintRefreshReason {
 1554    ModifiersChanged(bool),
 1555    Toggle(bool),
 1556    SettingsChange(InlayHintSettings),
 1557    NewLinesShown,
 1558    BufferEdited(HashSet<Arc<Language>>),
 1559    RefreshRequested,
 1560    ExcerptsRemoved(Vec<ExcerptId>),
 1561}
 1562
 1563impl InlayHintRefreshReason {
 1564    fn description(&self) -> &'static str {
 1565        match self {
 1566            Self::ModifiersChanged(_) => "modifiers changed",
 1567            Self::Toggle(_) => "toggle",
 1568            Self::SettingsChange(_) => "settings change",
 1569            Self::NewLinesShown => "new lines shown",
 1570            Self::BufferEdited(_) => "buffer edited",
 1571            Self::RefreshRequested => "refresh requested",
 1572            Self::ExcerptsRemoved(_) => "excerpts removed",
 1573        }
 1574    }
 1575}
 1576
 1577pub enum FormatTarget {
 1578    Buffers(HashSet<Entity<Buffer>>),
 1579    Ranges(Vec<Range<MultiBufferPoint>>),
 1580}
 1581
 1582pub(crate) struct FocusedBlock {
 1583    id: BlockId,
 1584    focus_handle: WeakFocusHandle,
 1585}
 1586
 1587#[derive(Clone)]
 1588enum JumpData {
 1589    MultiBufferRow {
 1590        row: MultiBufferRow,
 1591        line_offset_from_top: u32,
 1592    },
 1593    MultiBufferPoint {
 1594        excerpt_id: ExcerptId,
 1595        position: Point,
 1596        anchor: text::Anchor,
 1597        line_offset_from_top: u32,
 1598    },
 1599}
 1600
 1601pub enum MultibufferSelectionMode {
 1602    First,
 1603    All,
 1604}
 1605
 1606#[derive(Clone, Copy, Debug, Default)]
 1607pub struct RewrapOptions {
 1608    pub override_language_settings: bool,
 1609    pub preserve_existing_whitespace: bool,
 1610}
 1611
 1612impl Editor {
 1613    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1614        let buffer = cx.new(|cx| Buffer::local("", cx));
 1615        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1616        Self::new(
 1617            EditorMode::SingleLine { auto_width: false },
 1618            buffer,
 1619            None,
 1620            window,
 1621            cx,
 1622        )
 1623    }
 1624
 1625    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1626        let buffer = cx.new(|cx| Buffer::local("", cx));
 1627        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1628        Self::new(EditorMode::full(), buffer, None, window, cx)
 1629    }
 1630
 1631    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1632        let buffer = cx.new(|cx| Buffer::local("", cx));
 1633        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1634        Self::new(
 1635            EditorMode::SingleLine { auto_width: true },
 1636            buffer,
 1637            None,
 1638            window,
 1639            cx,
 1640        )
 1641    }
 1642
 1643    pub fn auto_height(
 1644        min_lines: usize,
 1645        max_lines: usize,
 1646        window: &mut Window,
 1647        cx: &mut Context<Self>,
 1648    ) -> Self {
 1649        let buffer = cx.new(|cx| Buffer::local("", cx));
 1650        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1651        Self::new(
 1652            EditorMode::AutoHeight {
 1653                min_lines,
 1654                max_lines: Some(max_lines),
 1655            },
 1656            buffer,
 1657            None,
 1658            window,
 1659            cx,
 1660        )
 1661    }
 1662
 1663    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1664    /// The editor grows as tall as needed to fit its content.
 1665    pub fn auto_height_unbounded(
 1666        min_lines: usize,
 1667        window: &mut Window,
 1668        cx: &mut Context<Self>,
 1669    ) -> Self {
 1670        let buffer = cx.new(|cx| Buffer::local("", cx));
 1671        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1672        Self::new(
 1673            EditorMode::AutoHeight {
 1674                min_lines,
 1675                max_lines: None,
 1676            },
 1677            buffer,
 1678            None,
 1679            window,
 1680            cx,
 1681        )
 1682    }
 1683
 1684    pub fn for_buffer(
 1685        buffer: Entity<Buffer>,
 1686        project: Option<Entity<Project>>,
 1687        window: &mut Window,
 1688        cx: &mut Context<Self>,
 1689    ) -> Self {
 1690        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1691        Self::new(EditorMode::full(), buffer, project, window, cx)
 1692    }
 1693
 1694    pub fn for_multibuffer(
 1695        buffer: Entity<MultiBuffer>,
 1696        project: Option<Entity<Project>>,
 1697        window: &mut Window,
 1698        cx: &mut Context<Self>,
 1699    ) -> Self {
 1700        Self::new(EditorMode::full(), buffer, project, window, cx)
 1701    }
 1702
 1703    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1704        let mut clone = Self::new(
 1705            self.mode.clone(),
 1706            self.buffer.clone(),
 1707            self.project.clone(),
 1708            window,
 1709            cx,
 1710        );
 1711        self.display_map.update(cx, |display_map, cx| {
 1712            let snapshot = display_map.snapshot(cx);
 1713            clone.display_map.update(cx, |display_map, cx| {
 1714                display_map.set_state(&snapshot, cx);
 1715            });
 1716        });
 1717        clone.folds_did_change(cx);
 1718        clone.selections.clone_state(&self.selections);
 1719        clone.scroll_manager.clone_state(&self.scroll_manager);
 1720        clone.searchable = self.searchable;
 1721        clone.read_only = self.read_only;
 1722        clone
 1723    }
 1724
 1725    pub fn new(
 1726        mode: EditorMode,
 1727        buffer: Entity<MultiBuffer>,
 1728        project: Option<Entity<Project>>,
 1729        window: &mut Window,
 1730        cx: &mut Context<Self>,
 1731    ) -> Self {
 1732        Editor::new_internal(mode, buffer, project, None, window, cx)
 1733    }
 1734
 1735    fn new_internal(
 1736        mode: EditorMode,
 1737        buffer: Entity<MultiBuffer>,
 1738        project: Option<Entity<Project>>,
 1739        display_map: Option<Entity<DisplayMap>>,
 1740        window: &mut Window,
 1741        cx: &mut Context<Self>,
 1742    ) -> Self {
 1743        debug_assert!(
 1744            display_map.is_none() || mode.is_minimap(),
 1745            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1746        );
 1747
 1748        let full_mode = mode.is_full();
 1749        let diagnostics_max_severity = if full_mode {
 1750            EditorSettings::get_global(cx)
 1751                .diagnostics_max_severity
 1752                .unwrap_or(DiagnosticSeverity::Hint)
 1753        } else {
 1754            DiagnosticSeverity::Off
 1755        };
 1756        let style = window.text_style();
 1757        let font_size = style.font_size.to_pixels(window.rem_size());
 1758        let editor = cx.entity().downgrade();
 1759        let fold_placeholder = FoldPlaceholder {
 1760            constrain_width: true,
 1761            render: Arc::new(move |fold_id, fold_range, cx| {
 1762                let editor = editor.clone();
 1763                div()
 1764                    .id(fold_id)
 1765                    .bg(cx.theme().colors().ghost_element_background)
 1766                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1767                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1768                    .rounded_xs()
 1769                    .size_full()
 1770                    .cursor_pointer()
 1771                    .child("")
 1772                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1773                    .on_click(move |_, _window, cx| {
 1774                        editor
 1775                            .update(cx, |editor, cx| {
 1776                                editor.unfold_ranges(
 1777                                    &[fold_range.start..fold_range.end],
 1778                                    true,
 1779                                    false,
 1780                                    cx,
 1781                                );
 1782                                cx.stop_propagation();
 1783                            })
 1784                            .ok();
 1785                    })
 1786                    .into_any()
 1787            }),
 1788            merge_adjacent: true,
 1789            ..FoldPlaceholder::default()
 1790        };
 1791        let display_map = display_map.unwrap_or_else(|| {
 1792            cx.new(|cx| {
 1793                DisplayMap::new(
 1794                    buffer.clone(),
 1795                    style.font(),
 1796                    font_size,
 1797                    None,
 1798                    FILE_HEADER_HEIGHT,
 1799                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1800                    fold_placeholder,
 1801                    diagnostics_max_severity,
 1802                    cx,
 1803                )
 1804            })
 1805        });
 1806
 1807        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1808
 1809        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1810
 1811        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1812            .then(|| language_settings::SoftWrap::None);
 1813
 1814        let mut project_subscriptions = Vec::new();
 1815        if mode.is_full() {
 1816            if let Some(project) = project.as_ref() {
 1817                project_subscriptions.push(cx.subscribe_in(
 1818                    project,
 1819                    window,
 1820                    |editor, _, event, window, cx| match event {
 1821                        project::Event::RefreshCodeLens => {
 1822                            // we always query lens with actions, without storing them, always refreshing them
 1823                        }
 1824                        project::Event::RefreshInlayHints => {
 1825                            editor
 1826                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1827                        }
 1828                        project::Event::LanguageServerAdded(server_id, ..)
 1829                        | project::Event::LanguageServerRemoved(server_id) => {
 1830                            if editor.tasks_update_task.is_none() {
 1831                                editor.tasks_update_task =
 1832                                    Some(editor.refresh_runnables(window, cx));
 1833                            }
 1834                            editor.update_lsp_data(Some(*server_id), None, window, cx);
 1835                        }
 1836                        project::Event::SnippetEdit(id, snippet_edits) => {
 1837                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1838                                let focus_handle = editor.focus_handle(cx);
 1839                                if focus_handle.is_focused(window) {
 1840                                    let snapshot = buffer.read(cx).snapshot();
 1841                                    for (range, snippet) in snippet_edits {
 1842                                        let editor_range =
 1843                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1844                                        editor
 1845                                            .insert_snippet(
 1846                                                &[editor_range],
 1847                                                snippet.clone(),
 1848                                                window,
 1849                                                cx,
 1850                                            )
 1851                                            .ok();
 1852                                    }
 1853                                }
 1854                            }
 1855                        }
 1856                        _ => {}
 1857                    },
 1858                ));
 1859                if let Some(task_inventory) = project
 1860                    .read(cx)
 1861                    .task_store()
 1862                    .read(cx)
 1863                    .task_inventory()
 1864                    .cloned()
 1865                {
 1866                    project_subscriptions.push(cx.observe_in(
 1867                        &task_inventory,
 1868                        window,
 1869                        |editor, _, window, cx| {
 1870                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1871                        },
 1872                    ));
 1873                };
 1874
 1875                project_subscriptions.push(cx.subscribe_in(
 1876                    &project.read(cx).breakpoint_store(),
 1877                    window,
 1878                    |editor, _, event, window, cx| match event {
 1879                        BreakpointStoreEvent::ClearDebugLines => {
 1880                            editor.clear_row_highlights::<ActiveDebugLine>();
 1881                            editor.refresh_inline_values(cx);
 1882                        }
 1883                        BreakpointStoreEvent::SetDebugLine => {
 1884                            if editor.go_to_active_debug_line(window, cx) {
 1885                                cx.stop_propagation();
 1886                            }
 1887
 1888                            editor.refresh_inline_values(cx);
 1889                        }
 1890                        _ => {}
 1891                    },
 1892                ));
 1893                let git_store = project.read(cx).git_store().clone();
 1894                let project = project.clone();
 1895                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1896                    match event {
 1897                        GitStoreEvent::RepositoryUpdated(
 1898                            _,
 1899                            RepositoryEvent::Updated {
 1900                                new_instance: true, ..
 1901                            },
 1902                            _,
 1903                        ) => {
 1904                            this.load_diff_task = Some(
 1905                                update_uncommitted_diff_for_buffer(
 1906                                    cx.entity(),
 1907                                    &project,
 1908                                    this.buffer.read(cx).all_buffers(),
 1909                                    this.buffer.clone(),
 1910                                    cx,
 1911                                )
 1912                                .shared(),
 1913                            );
 1914                        }
 1915                        _ => {}
 1916                    }
 1917                }));
 1918            }
 1919        }
 1920
 1921        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1922
 1923        let inlay_hint_settings =
 1924            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1925        let focus_handle = cx.focus_handle();
 1926        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1927            .detach();
 1928        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1929            .detach();
 1930        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1931            .detach();
 1932        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1933            .detach();
 1934        cx.observe_pending_input(window, Self::observe_pending_input)
 1935            .detach();
 1936
 1937        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1938            Some(false)
 1939        } else {
 1940            None
 1941        };
 1942
 1943        let breakpoint_store = match (&mode, project.as_ref()) {
 1944            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1945            _ => None,
 1946        };
 1947
 1948        let mut code_action_providers = Vec::new();
 1949        let mut load_uncommitted_diff = None;
 1950        if let Some(project) = project.clone() {
 1951            load_uncommitted_diff = Some(
 1952                update_uncommitted_diff_for_buffer(
 1953                    cx.entity(),
 1954                    &project,
 1955                    buffer.read(cx).all_buffers(),
 1956                    buffer.clone(),
 1957                    cx,
 1958                )
 1959                .shared(),
 1960            );
 1961            code_action_providers.push(Rc::new(project) as Rc<_>);
 1962        }
 1963
 1964        let mut editor = Self {
 1965            focus_handle,
 1966            show_cursor_when_unfocused: false,
 1967            last_focused_descendant: None,
 1968            buffer: buffer.clone(),
 1969            display_map: display_map.clone(),
 1970            selections,
 1971            scroll_manager: ScrollManager::new(cx),
 1972            columnar_selection_state: None,
 1973            add_selections_state: None,
 1974            select_next_state: None,
 1975            select_prev_state: None,
 1976            selection_history: SelectionHistory::default(),
 1977            defer_selection_effects: false,
 1978            deferred_selection_effects_state: None,
 1979            autoclose_regions: Vec::new(),
 1980            snippet_stack: InvalidationStack::default(),
 1981            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1982            ime_transaction: None,
 1983            active_diagnostics: ActiveDiagnostic::None,
 1984            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1985            inline_diagnostics_update: Task::ready(()),
 1986            inline_diagnostics: Vec::new(),
 1987            soft_wrap_mode_override,
 1988            diagnostics_max_severity,
 1989            hard_wrap: None,
 1990            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1991            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1992            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1993            project,
 1994            blink_manager: blink_manager.clone(),
 1995            show_local_selections: true,
 1996            show_scrollbars: ScrollbarAxes {
 1997                horizontal: full_mode,
 1998                vertical: full_mode,
 1999            },
 2000            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2001            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2002            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2003            show_gutter: mode.is_full(),
 2004            show_line_numbers: None,
 2005            use_relative_line_numbers: None,
 2006            disable_expand_excerpt_buttons: false,
 2007            show_git_diff_gutter: None,
 2008            show_code_actions: None,
 2009            show_runnables: None,
 2010            show_breakpoints: None,
 2011            show_wrap_guides: None,
 2012            show_indent_guides,
 2013            placeholder_text: None,
 2014            highlight_order: 0,
 2015            highlighted_rows: HashMap::default(),
 2016            background_highlights: TreeMap::default(),
 2017            gutter_highlights: TreeMap::default(),
 2018            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2019            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2020            nav_history: None,
 2021            context_menu: RefCell::new(None),
 2022            context_menu_options: None,
 2023            mouse_context_menu: None,
 2024            completion_tasks: Vec::new(),
 2025            inline_blame_popover: None,
 2026            inline_blame_popover_show_task: None,
 2027            signature_help_state: SignatureHelpState::default(),
 2028            auto_signature_help: None,
 2029            find_all_references_task_sources: Vec::new(),
 2030            next_completion_id: 0,
 2031            next_inlay_id: 0,
 2032            code_action_providers,
 2033            available_code_actions: None,
 2034            code_actions_task: None,
 2035            quick_selection_highlight_task: None,
 2036            debounced_selection_highlight_task: None,
 2037            document_highlights_task: None,
 2038            linked_editing_range_task: None,
 2039            pending_rename: None,
 2040            searchable: true,
 2041            cursor_shape: EditorSettings::get_global(cx)
 2042                .cursor_shape
 2043                .unwrap_or_default(),
 2044            current_line_highlight: None,
 2045            autoindent_mode: Some(AutoindentMode::EachLine),
 2046            collapse_matches: false,
 2047            workspace: None,
 2048            input_enabled: true,
 2049            use_modal_editing: mode.is_full(),
 2050            read_only: mode.is_minimap(),
 2051            use_autoclose: true,
 2052            use_auto_surround: true,
 2053            auto_replace_emoji_shortcode: false,
 2054            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2055            leader_id: None,
 2056            remote_id: None,
 2057            hover_state: HoverState::default(),
 2058            pending_mouse_down: None,
 2059            hovered_link_state: None,
 2060            edit_prediction_provider: None,
 2061            active_inline_completion: None,
 2062            stale_inline_completion_in_menu: None,
 2063            edit_prediction_preview: EditPredictionPreview::Inactive {
 2064                released_too_fast: false,
 2065            },
 2066            inline_diagnostics_enabled: mode.is_full(),
 2067            diagnostics_enabled: mode.is_full(),
 2068            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2069            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2070
 2071            gutter_hovered: false,
 2072            pixel_position_of_newest_cursor: None,
 2073            last_bounds: None,
 2074            last_position_map: None,
 2075            expect_bounds_change: None,
 2076            gutter_dimensions: GutterDimensions::default(),
 2077            style: None,
 2078            show_cursor_names: false,
 2079            hovered_cursors: HashMap::default(),
 2080            next_editor_action_id: EditorActionId::default(),
 2081            editor_actions: Rc::default(),
 2082            inline_completions_hidden_for_vim_mode: false,
 2083            show_inline_completions_override: None,
 2084            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 2085            edit_prediction_settings: EditPredictionSettings::Disabled,
 2086            edit_prediction_indent_conflict: false,
 2087            edit_prediction_requires_modifier_in_indent_conflict: true,
 2088            custom_context_menu: None,
 2089            show_git_blame_gutter: false,
 2090            show_git_blame_inline: false,
 2091            show_selection_menu: None,
 2092            show_git_blame_inline_delay_task: None,
 2093            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2094            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2095            serialize_dirty_buffers: !mode.is_minimap()
 2096                && ProjectSettings::get_global(cx)
 2097                    .session
 2098                    .restore_unsaved_buffers,
 2099            blame: None,
 2100            blame_subscription: None,
 2101            tasks: BTreeMap::default(),
 2102
 2103            breakpoint_store,
 2104            gutter_breakpoint_indicator: (None, None),
 2105            hovered_diff_hunk_row: None,
 2106            _subscriptions: vec![
 2107                cx.observe(&buffer, Self::on_buffer_changed),
 2108                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2109                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2110                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2111                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2112                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2113                cx.observe_window_activation(window, |editor, window, cx| {
 2114                    let active = window.is_window_active();
 2115                    editor.blink_manager.update(cx, |blink_manager, cx| {
 2116                        if active {
 2117                            blink_manager.enable(cx);
 2118                        } else {
 2119                            blink_manager.disable(cx);
 2120                        }
 2121                    });
 2122                    if active {
 2123                        editor.show_mouse_cursor(cx);
 2124                    }
 2125                }),
 2126            ],
 2127            tasks_update_task: None,
 2128            pull_diagnostics_task: Task::ready(()),
 2129            colors: None,
 2130            next_color_inlay_id: 0,
 2131            linked_edit_ranges: Default::default(),
 2132            in_project_search: false,
 2133            previous_search_ranges: None,
 2134            breadcrumb_header: None,
 2135            focused_block: None,
 2136            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2137            addons: HashMap::default(),
 2138            registered_buffers: HashMap::default(),
 2139            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2140            selection_mark_mode: false,
 2141            toggle_fold_multiple_buffers: Task::ready(()),
 2142            serialize_selections: Task::ready(()),
 2143            serialize_folds: Task::ready(()),
 2144            text_style_refinement: None,
 2145            load_diff_task: load_uncommitted_diff,
 2146            temporary_diff_override: false,
 2147            mouse_cursor_hidden: false,
 2148            minimap: None,
 2149            hide_mouse_mode: EditorSettings::get_global(cx)
 2150                .hide_mouse
 2151                .unwrap_or_default(),
 2152            change_list: ChangeList::new(),
 2153            mode,
 2154            selection_drag_state: SelectionDragState::None,
 2155            drag_and_drop_selection_enabled: EditorSettings::get_global(cx).drag_and_drop_selection,
 2156        };
 2157        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2158            editor
 2159                ._subscriptions
 2160                .push(cx.observe(breakpoints, |_, _, cx| {
 2161                    cx.notify();
 2162                }));
 2163        }
 2164        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2165        editor._subscriptions.extend(project_subscriptions);
 2166
 2167        editor._subscriptions.push(cx.subscribe_in(
 2168            &cx.entity(),
 2169            window,
 2170            |editor, _, e: &EditorEvent, window, cx| match e {
 2171                EditorEvent::ScrollPositionChanged { local, .. } => {
 2172                    if *local {
 2173                        let new_anchor = editor.scroll_manager.anchor();
 2174                        let snapshot = editor.snapshot(window, cx);
 2175                        editor.update_restoration_data(cx, move |data| {
 2176                            data.scroll_position = (
 2177                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2178                                new_anchor.offset,
 2179                            );
 2180                        });
 2181                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2182                        editor.inline_blame_popover.take();
 2183                    }
 2184                }
 2185                EditorEvent::Edited { .. } => {
 2186                    if !vim_enabled(cx) {
 2187                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2188                        let pop_state = editor
 2189                            .change_list
 2190                            .last()
 2191                            .map(|previous| {
 2192                                previous.len() == selections.len()
 2193                                    && previous.iter().enumerate().all(|(ix, p)| {
 2194                                        p.to_display_point(&map).row()
 2195                                            == selections[ix].head().row()
 2196                                    })
 2197                            })
 2198                            .unwrap_or(false);
 2199                        let new_positions = selections
 2200                            .into_iter()
 2201                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2202                            .collect();
 2203                        editor
 2204                            .change_list
 2205                            .push_to_change_list(pop_state, new_positions);
 2206                    }
 2207                }
 2208                _ => (),
 2209            },
 2210        ));
 2211
 2212        if let Some(dap_store) = editor
 2213            .project
 2214            .as_ref()
 2215            .map(|project| project.read(cx).dap_store())
 2216        {
 2217            let weak_editor = cx.weak_entity();
 2218
 2219            editor
 2220                ._subscriptions
 2221                .push(
 2222                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2223                        let session_entity = cx.entity();
 2224                        weak_editor
 2225                            .update(cx, |editor, cx| {
 2226                                editor._subscriptions.push(
 2227                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2228                                );
 2229                            })
 2230                            .ok();
 2231                    }),
 2232                );
 2233
 2234            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2235                editor
 2236                    ._subscriptions
 2237                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2238            }
 2239        }
 2240
 2241        // skip adding the initial selection to selection history
 2242        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2243        editor.end_selection(window, cx);
 2244        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2245
 2246        editor.scroll_manager.show_scrollbars(window, cx);
 2247        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2248
 2249        if full_mode {
 2250            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2251            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2252
 2253            if editor.git_blame_inline_enabled {
 2254                editor.start_git_blame_inline(false, window, cx);
 2255            }
 2256
 2257            editor.go_to_active_debug_line(window, cx);
 2258
 2259            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2260                if let Some(project) = editor.project.as_ref() {
 2261                    let handle = project.update(cx, |project, cx| {
 2262                        project.register_buffer_with_language_servers(&buffer, cx)
 2263                    });
 2264                    editor
 2265                        .registered_buffers
 2266                        .insert(buffer.read(cx).remote_id(), handle);
 2267                }
 2268            }
 2269
 2270            editor.minimap =
 2271                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2272            editor.colors = Some(LspColorData::new(cx));
 2273            editor.update_lsp_data(None, None, window, cx);
 2274        }
 2275
 2276        editor.report_editor_event("Editor Opened", None, cx);
 2277        editor
 2278    }
 2279
 2280    pub fn deploy_mouse_context_menu(
 2281        &mut self,
 2282        position: gpui::Point<Pixels>,
 2283        context_menu: Entity<ContextMenu>,
 2284        window: &mut Window,
 2285        cx: &mut Context<Self>,
 2286    ) {
 2287        self.mouse_context_menu = Some(MouseContextMenu::new(
 2288            self,
 2289            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2290            context_menu,
 2291            window,
 2292            cx,
 2293        ));
 2294    }
 2295
 2296    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2297        self.mouse_context_menu
 2298            .as_ref()
 2299            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2300    }
 2301
 2302    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2303        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2304    }
 2305
 2306    fn key_context_internal(
 2307        &self,
 2308        has_active_edit_prediction: bool,
 2309        window: &Window,
 2310        cx: &App,
 2311    ) -> KeyContext {
 2312        let mut key_context = KeyContext::new_with_defaults();
 2313        key_context.add("Editor");
 2314        let mode = match self.mode {
 2315            EditorMode::SingleLine { .. } => "single_line",
 2316            EditorMode::AutoHeight { .. } => "auto_height",
 2317            EditorMode::Minimap { .. } => "minimap",
 2318            EditorMode::Full { .. } => "full",
 2319        };
 2320
 2321        if EditorSettings::jupyter_enabled(cx) {
 2322            key_context.add("jupyter");
 2323        }
 2324
 2325        key_context.set("mode", mode);
 2326        if self.pending_rename.is_some() {
 2327            key_context.add("renaming");
 2328        }
 2329
 2330        match self.context_menu.borrow().as_ref() {
 2331            Some(CodeContextMenu::Completions(_)) => {
 2332                key_context.add("menu");
 2333                key_context.add("showing_completions");
 2334            }
 2335            Some(CodeContextMenu::CodeActions(_)) => {
 2336                key_context.add("menu");
 2337                key_context.add("showing_code_actions")
 2338            }
 2339            None => {}
 2340        }
 2341
 2342        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2343        if !self.focus_handle(cx).contains_focused(window, cx)
 2344            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2345        {
 2346            for addon in self.addons.values() {
 2347                addon.extend_key_context(&mut key_context, cx)
 2348            }
 2349        }
 2350
 2351        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2352            if let Some(extension) = singleton_buffer
 2353                .read(cx)
 2354                .file()
 2355                .and_then(|file| file.path().extension()?.to_str())
 2356            {
 2357                key_context.set("extension", extension.to_string());
 2358            }
 2359        } else {
 2360            key_context.add("multibuffer");
 2361        }
 2362
 2363        if has_active_edit_prediction {
 2364            if self.edit_prediction_in_conflict() {
 2365                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2366            } else {
 2367                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2368                key_context.add("copilot_suggestion");
 2369            }
 2370        }
 2371
 2372        if self.selection_mark_mode {
 2373            key_context.add("selection_mode");
 2374        }
 2375
 2376        key_context
 2377    }
 2378
 2379    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2380        if self.mouse_cursor_hidden {
 2381            self.mouse_cursor_hidden = false;
 2382            cx.notify();
 2383        }
 2384    }
 2385
 2386    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2387        let hide_mouse_cursor = match origin {
 2388            HideMouseCursorOrigin::TypingAction => {
 2389                matches!(
 2390                    self.hide_mouse_mode,
 2391                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2392                )
 2393            }
 2394            HideMouseCursorOrigin::MovementAction => {
 2395                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2396            }
 2397        };
 2398        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2399            self.mouse_cursor_hidden = hide_mouse_cursor;
 2400            cx.notify();
 2401        }
 2402    }
 2403
 2404    pub fn edit_prediction_in_conflict(&self) -> bool {
 2405        if !self.show_edit_predictions_in_menu() {
 2406            return false;
 2407        }
 2408
 2409        let showing_completions = self
 2410            .context_menu
 2411            .borrow()
 2412            .as_ref()
 2413            .map_or(false, |context| {
 2414                matches!(context, CodeContextMenu::Completions(_))
 2415            });
 2416
 2417        showing_completions
 2418            || self.edit_prediction_requires_modifier()
 2419            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2420            // bindings to insert tab characters.
 2421            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2422    }
 2423
 2424    pub fn accept_edit_prediction_keybind(
 2425        &self,
 2426        accept_partial: bool,
 2427        window: &Window,
 2428        cx: &App,
 2429    ) -> AcceptEditPredictionBinding {
 2430        let key_context = self.key_context_internal(true, window, cx);
 2431        let in_conflict = self.edit_prediction_in_conflict();
 2432
 2433        let bindings = if accept_partial {
 2434            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2435        } else {
 2436            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2437        };
 2438
 2439        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2440        // just the first one.
 2441        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2442            !in_conflict
 2443                || binding
 2444                    .keystrokes()
 2445                    .first()
 2446                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2447        }))
 2448    }
 2449
 2450    pub fn new_file(
 2451        workspace: &mut Workspace,
 2452        _: &workspace::NewFile,
 2453        window: &mut Window,
 2454        cx: &mut Context<Workspace>,
 2455    ) {
 2456        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2457            "Failed to create buffer",
 2458            window,
 2459            cx,
 2460            |e, _, _| match e.error_code() {
 2461                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2462                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2463                e.error_tag("required").unwrap_or("the latest version")
 2464            )),
 2465                _ => None,
 2466            },
 2467        );
 2468    }
 2469
 2470    pub fn new_in_workspace(
 2471        workspace: &mut Workspace,
 2472        window: &mut Window,
 2473        cx: &mut Context<Workspace>,
 2474    ) -> Task<Result<Entity<Editor>>> {
 2475        let project = workspace.project().clone();
 2476        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2477
 2478        cx.spawn_in(window, async move |workspace, cx| {
 2479            let buffer = create.await?;
 2480            workspace.update_in(cx, |workspace, window, cx| {
 2481                let editor =
 2482                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2483                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2484                editor
 2485            })
 2486        })
 2487    }
 2488
 2489    fn new_file_vertical(
 2490        workspace: &mut Workspace,
 2491        _: &workspace::NewFileSplitVertical,
 2492        window: &mut Window,
 2493        cx: &mut Context<Workspace>,
 2494    ) {
 2495        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2496    }
 2497
 2498    fn new_file_horizontal(
 2499        workspace: &mut Workspace,
 2500        _: &workspace::NewFileSplitHorizontal,
 2501        window: &mut Window,
 2502        cx: &mut Context<Workspace>,
 2503    ) {
 2504        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2505    }
 2506
 2507    fn new_file_in_direction(
 2508        workspace: &mut Workspace,
 2509        direction: SplitDirection,
 2510        window: &mut Window,
 2511        cx: &mut Context<Workspace>,
 2512    ) {
 2513        let project = workspace.project().clone();
 2514        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2515
 2516        cx.spawn_in(window, async move |workspace, cx| {
 2517            let buffer = create.await?;
 2518            workspace.update_in(cx, move |workspace, window, cx| {
 2519                workspace.split_item(
 2520                    direction,
 2521                    Box::new(
 2522                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2523                    ),
 2524                    window,
 2525                    cx,
 2526                )
 2527            })?;
 2528            anyhow::Ok(())
 2529        })
 2530        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2531            match e.error_code() {
 2532                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2533                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2534                e.error_tag("required").unwrap_or("the latest version")
 2535            )),
 2536                _ => None,
 2537            }
 2538        });
 2539    }
 2540
 2541    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2542        self.leader_id
 2543    }
 2544
 2545    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2546        &self.buffer
 2547    }
 2548
 2549    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2550        self.workspace.as_ref()?.0.upgrade()
 2551    }
 2552
 2553    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2554        self.buffer().read(cx).title(cx)
 2555    }
 2556
 2557    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2558        let git_blame_gutter_max_author_length = self
 2559            .render_git_blame_gutter(cx)
 2560            .then(|| {
 2561                if let Some(blame) = self.blame.as_ref() {
 2562                    let max_author_length =
 2563                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2564                    Some(max_author_length)
 2565                } else {
 2566                    None
 2567                }
 2568            })
 2569            .flatten();
 2570
 2571        EditorSnapshot {
 2572            mode: self.mode.clone(),
 2573            show_gutter: self.show_gutter,
 2574            show_line_numbers: self.show_line_numbers,
 2575            show_git_diff_gutter: self.show_git_diff_gutter,
 2576            show_code_actions: self.show_code_actions,
 2577            show_runnables: self.show_runnables,
 2578            show_breakpoints: self.show_breakpoints,
 2579            git_blame_gutter_max_author_length,
 2580            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2581            scroll_anchor: self.scroll_manager.anchor(),
 2582            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2583            placeholder_text: self.placeholder_text.clone(),
 2584            is_focused: self.focus_handle.is_focused(window),
 2585            current_line_highlight: self
 2586                .current_line_highlight
 2587                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2588            gutter_hovered: self.gutter_hovered,
 2589        }
 2590    }
 2591
 2592    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2593        self.buffer.read(cx).language_at(point, cx)
 2594    }
 2595
 2596    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2597        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2598    }
 2599
 2600    pub fn active_excerpt(
 2601        &self,
 2602        cx: &App,
 2603    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2604        self.buffer
 2605            .read(cx)
 2606            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2607    }
 2608
 2609    pub fn mode(&self) -> &EditorMode {
 2610        &self.mode
 2611    }
 2612
 2613    pub fn set_mode(&mut self, mode: EditorMode) {
 2614        self.mode = mode;
 2615    }
 2616
 2617    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2618        self.collaboration_hub.as_deref()
 2619    }
 2620
 2621    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2622        self.collaboration_hub = Some(hub);
 2623    }
 2624
 2625    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2626        self.in_project_search = in_project_search;
 2627    }
 2628
 2629    pub fn set_custom_context_menu(
 2630        &mut self,
 2631        f: impl 'static
 2632        + Fn(
 2633            &mut Self,
 2634            DisplayPoint,
 2635            &mut Window,
 2636            &mut Context<Self>,
 2637        ) -> Option<Entity<ui::ContextMenu>>,
 2638    ) {
 2639        self.custom_context_menu = Some(Box::new(f))
 2640    }
 2641
 2642    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2643        self.completion_provider = provider;
 2644    }
 2645
 2646    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2647        self.semantics_provider.clone()
 2648    }
 2649
 2650    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2651        self.semantics_provider = provider;
 2652    }
 2653
 2654    pub fn set_edit_prediction_provider<T>(
 2655        &mut self,
 2656        provider: Option<Entity<T>>,
 2657        window: &mut Window,
 2658        cx: &mut Context<Self>,
 2659    ) where
 2660        T: EditPredictionProvider,
 2661    {
 2662        self.edit_prediction_provider =
 2663            provider.map(|provider| RegisteredInlineCompletionProvider {
 2664                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2665                    if this.focus_handle.is_focused(window) {
 2666                        this.update_visible_inline_completion(window, cx);
 2667                    }
 2668                }),
 2669                provider: Arc::new(provider),
 2670            });
 2671        self.update_edit_prediction_settings(cx);
 2672        self.refresh_inline_completion(false, false, window, cx);
 2673    }
 2674
 2675    pub fn placeholder_text(&self) -> Option<&str> {
 2676        self.placeholder_text.as_deref()
 2677    }
 2678
 2679    pub fn set_placeholder_text(
 2680        &mut self,
 2681        placeholder_text: impl Into<Arc<str>>,
 2682        cx: &mut Context<Self>,
 2683    ) {
 2684        let placeholder_text = Some(placeholder_text.into());
 2685        if self.placeholder_text != placeholder_text {
 2686            self.placeholder_text = placeholder_text;
 2687            cx.notify();
 2688        }
 2689    }
 2690
 2691    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2692        self.cursor_shape = cursor_shape;
 2693
 2694        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2695        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2696
 2697        cx.notify();
 2698    }
 2699
 2700    pub fn set_current_line_highlight(
 2701        &mut self,
 2702        current_line_highlight: Option<CurrentLineHighlight>,
 2703    ) {
 2704        self.current_line_highlight = current_line_highlight;
 2705    }
 2706
 2707    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2708        self.collapse_matches = collapse_matches;
 2709    }
 2710
 2711    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2712        let buffers = self.buffer.read(cx).all_buffers();
 2713        let Some(project) = self.project.as_ref() else {
 2714            return;
 2715        };
 2716        project.update(cx, |project, cx| {
 2717            for buffer in buffers {
 2718                self.registered_buffers
 2719                    .entry(buffer.read(cx).remote_id())
 2720                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2721            }
 2722        })
 2723    }
 2724
 2725    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2726        if self.collapse_matches {
 2727            return range.start..range.start;
 2728        }
 2729        range.clone()
 2730    }
 2731
 2732    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2733        if self.display_map.read(cx).clip_at_line_ends != clip {
 2734            self.display_map
 2735                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2736        }
 2737    }
 2738
 2739    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2740        self.input_enabled = input_enabled;
 2741    }
 2742
 2743    pub fn set_inline_completions_hidden_for_vim_mode(
 2744        &mut self,
 2745        hidden: bool,
 2746        window: &mut Window,
 2747        cx: &mut Context<Self>,
 2748    ) {
 2749        if hidden != self.inline_completions_hidden_for_vim_mode {
 2750            self.inline_completions_hidden_for_vim_mode = hidden;
 2751            if hidden {
 2752                self.update_visible_inline_completion(window, cx);
 2753            } else {
 2754                self.refresh_inline_completion(true, false, window, cx);
 2755            }
 2756        }
 2757    }
 2758
 2759    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2760        self.menu_inline_completions_policy = value;
 2761    }
 2762
 2763    pub fn set_autoindent(&mut self, autoindent: bool) {
 2764        if autoindent {
 2765            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2766        } else {
 2767            self.autoindent_mode = None;
 2768        }
 2769    }
 2770
 2771    pub fn read_only(&self, cx: &App) -> bool {
 2772        self.read_only || self.buffer.read(cx).read_only()
 2773    }
 2774
 2775    pub fn set_read_only(&mut self, read_only: bool) {
 2776        self.read_only = read_only;
 2777    }
 2778
 2779    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2780        self.use_autoclose = autoclose;
 2781    }
 2782
 2783    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2784        self.use_auto_surround = auto_surround;
 2785    }
 2786
 2787    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2788        self.auto_replace_emoji_shortcode = auto_replace;
 2789    }
 2790
 2791    pub fn toggle_edit_predictions(
 2792        &mut self,
 2793        _: &ToggleEditPrediction,
 2794        window: &mut Window,
 2795        cx: &mut Context<Self>,
 2796    ) {
 2797        if self.show_inline_completions_override.is_some() {
 2798            self.set_show_edit_predictions(None, window, cx);
 2799        } else {
 2800            let show_edit_predictions = !self.edit_predictions_enabled();
 2801            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2802        }
 2803    }
 2804
 2805    pub fn set_show_edit_predictions(
 2806        &mut self,
 2807        show_edit_predictions: Option<bool>,
 2808        window: &mut Window,
 2809        cx: &mut Context<Self>,
 2810    ) {
 2811        self.show_inline_completions_override = show_edit_predictions;
 2812        self.update_edit_prediction_settings(cx);
 2813
 2814        if let Some(false) = show_edit_predictions {
 2815            self.discard_inline_completion(false, cx);
 2816        } else {
 2817            self.refresh_inline_completion(false, true, window, cx);
 2818        }
 2819    }
 2820
 2821    fn inline_completions_disabled_in_scope(
 2822        &self,
 2823        buffer: &Entity<Buffer>,
 2824        buffer_position: language::Anchor,
 2825        cx: &App,
 2826    ) -> bool {
 2827        let snapshot = buffer.read(cx).snapshot();
 2828        let settings = snapshot.settings_at(buffer_position, cx);
 2829
 2830        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2831            return false;
 2832        };
 2833
 2834        scope.override_name().map_or(false, |scope_name| {
 2835            settings
 2836                .edit_predictions_disabled_in
 2837                .iter()
 2838                .any(|s| s == scope_name)
 2839        })
 2840    }
 2841
 2842    pub fn set_use_modal_editing(&mut self, to: bool) {
 2843        self.use_modal_editing = to;
 2844    }
 2845
 2846    pub fn use_modal_editing(&self) -> bool {
 2847        self.use_modal_editing
 2848    }
 2849
 2850    fn selections_did_change(
 2851        &mut self,
 2852        local: bool,
 2853        old_cursor_position: &Anchor,
 2854        effects: SelectionEffects,
 2855        window: &mut Window,
 2856        cx: &mut Context<Self>,
 2857    ) {
 2858        window.invalidate_character_coordinates();
 2859
 2860        // Copy selections to primary selection buffer
 2861        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2862        if local {
 2863            let selections = self.selections.all::<usize>(cx);
 2864            let buffer_handle = self.buffer.read(cx).read(cx);
 2865
 2866            let mut text = String::new();
 2867            for (index, selection) in selections.iter().enumerate() {
 2868                let text_for_selection = buffer_handle
 2869                    .text_for_range(selection.start..selection.end)
 2870                    .collect::<String>();
 2871
 2872                text.push_str(&text_for_selection);
 2873                if index != selections.len() - 1 {
 2874                    text.push('\n');
 2875                }
 2876            }
 2877
 2878            if !text.is_empty() {
 2879                cx.write_to_primary(ClipboardItem::new_string(text));
 2880            }
 2881        }
 2882
 2883        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2884            self.buffer.update(cx, |buffer, cx| {
 2885                buffer.set_active_selections(
 2886                    &self.selections.disjoint_anchors(),
 2887                    self.selections.line_mode,
 2888                    self.cursor_shape,
 2889                    cx,
 2890                )
 2891            });
 2892        }
 2893        let display_map = self
 2894            .display_map
 2895            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2896        let buffer = &display_map.buffer_snapshot;
 2897        if self.selections.count() == 1 {
 2898            self.add_selections_state = None;
 2899        }
 2900        self.select_next_state = None;
 2901        self.select_prev_state = None;
 2902        self.select_syntax_node_history.try_clear();
 2903        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2904        self.snippet_stack
 2905            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2906        self.take_rename(false, window, cx);
 2907
 2908        let newest_selection = self.selections.newest_anchor();
 2909        let new_cursor_position = newest_selection.head();
 2910        let selection_start = newest_selection.start;
 2911
 2912        if effects.nav_history {
 2913            self.push_to_nav_history(
 2914                *old_cursor_position,
 2915                Some(new_cursor_position.to_point(buffer)),
 2916                false,
 2917                cx,
 2918            );
 2919        }
 2920
 2921        if local {
 2922            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2923                if !self.registered_buffers.contains_key(&buffer_id) {
 2924                    if let Some(project) = self.project.as_ref() {
 2925                        project.update(cx, |project, cx| {
 2926                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2927                                return;
 2928                            };
 2929                            self.registered_buffers.insert(
 2930                                buffer_id,
 2931                                project.register_buffer_with_language_servers(&buffer, cx),
 2932                            );
 2933                        })
 2934                    }
 2935                }
 2936            }
 2937
 2938            let mut context_menu = self.context_menu.borrow_mut();
 2939            let completion_menu = match context_menu.as_ref() {
 2940                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2941                Some(CodeContextMenu::CodeActions(_)) => {
 2942                    *context_menu = None;
 2943                    None
 2944                }
 2945                None => None,
 2946            };
 2947            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2948            drop(context_menu);
 2949
 2950            if effects.completions {
 2951                if let Some(completion_position) = completion_position {
 2952                    let start_offset = selection_start.to_offset(buffer);
 2953                    let position_matches = start_offset == completion_position.to_offset(buffer);
 2954                    let continue_showing = if position_matches {
 2955                        if self.snippet_stack.is_empty() {
 2956                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 2957                        } else {
 2958                            // Snippet choices can be shown even when the cursor is in whitespace.
 2959                            // Dismissing the menu with actions like backspace is handled by
 2960                            // invalidation regions.
 2961                            true
 2962                        }
 2963                    } else {
 2964                        false
 2965                    };
 2966
 2967                    if continue_showing {
 2968                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2969                    } else {
 2970                        self.hide_context_menu(window, cx);
 2971                    }
 2972                }
 2973            }
 2974
 2975            hide_hover(self, cx);
 2976
 2977            if old_cursor_position.to_display_point(&display_map).row()
 2978                != new_cursor_position.to_display_point(&display_map).row()
 2979            {
 2980                self.available_code_actions.take();
 2981            }
 2982            self.refresh_code_actions(window, cx);
 2983            self.refresh_document_highlights(cx);
 2984            self.refresh_selected_text_highlights(false, window, cx);
 2985            refresh_matching_bracket_highlights(self, window, cx);
 2986            self.update_visible_inline_completion(window, cx);
 2987            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2988            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2989            self.inline_blame_popover.take();
 2990            if self.git_blame_inline_enabled {
 2991                self.start_inline_blame_timer(window, cx);
 2992            }
 2993        }
 2994
 2995        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2996        cx.emit(EditorEvent::SelectionsChanged { local });
 2997
 2998        let selections = &self.selections.disjoint;
 2999        if selections.len() == 1 {
 3000            cx.emit(SearchEvent::ActiveMatchChanged)
 3001        }
 3002        if local {
 3003            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3004                let inmemory_selections = selections
 3005                    .iter()
 3006                    .map(|s| {
 3007                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3008                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3009                    })
 3010                    .collect();
 3011                self.update_restoration_data(cx, |data| {
 3012                    data.selections = inmemory_selections;
 3013                });
 3014
 3015                if WorkspaceSettings::get(None, cx).restore_on_startup
 3016                    != RestoreOnStartupBehavior::None
 3017                {
 3018                    if let Some(workspace_id) =
 3019                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3020                    {
 3021                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3022                        let selections = selections.clone();
 3023                        let background_executor = cx.background_executor().clone();
 3024                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3025                        self.serialize_selections = cx.background_spawn(async move {
 3026                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3027                            let db_selections = selections
 3028                                .iter()
 3029                                .map(|selection| {
 3030                                    (
 3031                                        selection.start.to_offset(&snapshot),
 3032                                        selection.end.to_offset(&snapshot),
 3033                                    )
 3034                                })
 3035                                .collect();
 3036
 3037                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3038                                .await
 3039                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3040                                .log_err();
 3041                        });
 3042                    }
 3043                }
 3044            }
 3045        }
 3046
 3047        cx.notify();
 3048    }
 3049
 3050    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3051        use text::ToOffset as _;
 3052        use text::ToPoint as _;
 3053
 3054        if self.mode.is_minimap()
 3055            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3056        {
 3057            return;
 3058        }
 3059
 3060        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3061            return;
 3062        };
 3063
 3064        let snapshot = singleton.read(cx).snapshot();
 3065        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3066            let display_snapshot = display_map.snapshot(cx);
 3067
 3068            display_snapshot
 3069                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3070                .map(|fold| {
 3071                    fold.range.start.text_anchor.to_point(&snapshot)
 3072                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3073                })
 3074                .collect()
 3075        });
 3076        self.update_restoration_data(cx, |data| {
 3077            data.folds = inmemory_folds;
 3078        });
 3079
 3080        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3081            return;
 3082        };
 3083        let background_executor = cx.background_executor().clone();
 3084        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3085        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3086            display_map
 3087                .snapshot(cx)
 3088                .folds_in_range(0..snapshot.len())
 3089                .map(|fold| {
 3090                    (
 3091                        fold.range.start.text_anchor.to_offset(&snapshot),
 3092                        fold.range.end.text_anchor.to_offset(&snapshot),
 3093                    )
 3094                })
 3095                .collect()
 3096        });
 3097        self.serialize_folds = cx.background_spawn(async move {
 3098            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3099            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3100                .await
 3101                .with_context(|| {
 3102                    format!(
 3103                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3104                    )
 3105                })
 3106                .log_err();
 3107        });
 3108    }
 3109
 3110    pub fn sync_selections(
 3111        &mut self,
 3112        other: Entity<Editor>,
 3113        cx: &mut Context<Self>,
 3114    ) -> gpui::Subscription {
 3115        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3116        self.selections.change_with(cx, |selections| {
 3117            selections.select_anchors(other_selections);
 3118        });
 3119
 3120        let other_subscription =
 3121            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3122                EditorEvent::SelectionsChanged { local: true } => {
 3123                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3124                    if other_selections.is_empty() {
 3125                        return;
 3126                    }
 3127                    this.selections.change_with(cx, |selections| {
 3128                        selections.select_anchors(other_selections);
 3129                    });
 3130                }
 3131                _ => {}
 3132            });
 3133
 3134        let this_subscription =
 3135            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3136                EditorEvent::SelectionsChanged { local: true } => {
 3137                    let these_selections = this.selections.disjoint.to_vec();
 3138                    if these_selections.is_empty() {
 3139                        return;
 3140                    }
 3141                    other.update(cx, |other_editor, cx| {
 3142                        other_editor.selections.change_with(cx, |selections| {
 3143                            selections.select_anchors(these_selections);
 3144                        })
 3145                    });
 3146                }
 3147                _ => {}
 3148            });
 3149
 3150        Subscription::join(other_subscription, this_subscription)
 3151    }
 3152
 3153    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3154    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3155    /// effects of selection change occur at the end of the transaction.
 3156    pub fn change_selections<R>(
 3157        &mut self,
 3158        effects: impl Into<SelectionEffects>,
 3159        window: &mut Window,
 3160        cx: &mut Context<Self>,
 3161        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3162    ) -> R {
 3163        let effects = effects.into();
 3164        if let Some(state) = &mut self.deferred_selection_effects_state {
 3165            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3166            state.effects.completions = effects.completions;
 3167            state.effects.nav_history |= effects.nav_history;
 3168            let (changed, result) = self.selections.change_with(cx, change);
 3169            state.changed |= changed;
 3170            return result;
 3171        }
 3172        let mut state = DeferredSelectionEffectsState {
 3173            changed: false,
 3174            effects,
 3175            old_cursor_position: self.selections.newest_anchor().head(),
 3176            history_entry: SelectionHistoryEntry {
 3177                selections: self.selections.disjoint_anchors(),
 3178                select_next_state: self.select_next_state.clone(),
 3179                select_prev_state: self.select_prev_state.clone(),
 3180                add_selections_state: self.add_selections_state.clone(),
 3181            },
 3182        };
 3183        let (changed, result) = self.selections.change_with(cx, change);
 3184        state.changed = state.changed || changed;
 3185        if self.defer_selection_effects {
 3186            self.deferred_selection_effects_state = Some(state);
 3187        } else {
 3188            self.apply_selection_effects(state, window, cx);
 3189        }
 3190        result
 3191    }
 3192
 3193    /// Defers the effects of selection change, so that the effects of multiple calls to
 3194    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3195    /// to selection history and the state of popovers based on selection position aren't
 3196    /// erroneously updated.
 3197    pub fn with_selection_effects_deferred<R>(
 3198        &mut self,
 3199        window: &mut Window,
 3200        cx: &mut Context<Self>,
 3201        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3202    ) -> R {
 3203        let already_deferred = self.defer_selection_effects;
 3204        self.defer_selection_effects = true;
 3205        let result = update(self, window, cx);
 3206        if !already_deferred {
 3207            self.defer_selection_effects = false;
 3208            if let Some(state) = self.deferred_selection_effects_state.take() {
 3209                self.apply_selection_effects(state, window, cx);
 3210            }
 3211        }
 3212        result
 3213    }
 3214
 3215    fn apply_selection_effects(
 3216        &mut self,
 3217        state: DeferredSelectionEffectsState,
 3218        window: &mut Window,
 3219        cx: &mut Context<Self>,
 3220    ) {
 3221        if state.changed {
 3222            self.selection_history.push(state.history_entry);
 3223
 3224            if let Some(autoscroll) = state.effects.scroll {
 3225                self.request_autoscroll(autoscroll, cx);
 3226            }
 3227
 3228            let old_cursor_position = &state.old_cursor_position;
 3229
 3230            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3231
 3232            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3233                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3234            }
 3235        }
 3236    }
 3237
 3238    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3239    where
 3240        I: IntoIterator<Item = (Range<S>, T)>,
 3241        S: ToOffset,
 3242        T: Into<Arc<str>>,
 3243    {
 3244        if self.read_only(cx) {
 3245            return;
 3246        }
 3247
 3248        self.buffer
 3249            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3250    }
 3251
 3252    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3253    where
 3254        I: IntoIterator<Item = (Range<S>, T)>,
 3255        S: ToOffset,
 3256        T: Into<Arc<str>>,
 3257    {
 3258        if self.read_only(cx) {
 3259            return;
 3260        }
 3261
 3262        self.buffer.update(cx, |buffer, cx| {
 3263            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3264        });
 3265    }
 3266
 3267    pub fn edit_with_block_indent<I, S, T>(
 3268        &mut self,
 3269        edits: I,
 3270        original_indent_columns: Vec<Option<u32>>,
 3271        cx: &mut Context<Self>,
 3272    ) where
 3273        I: IntoIterator<Item = (Range<S>, T)>,
 3274        S: ToOffset,
 3275        T: Into<Arc<str>>,
 3276    {
 3277        if self.read_only(cx) {
 3278            return;
 3279        }
 3280
 3281        self.buffer.update(cx, |buffer, cx| {
 3282            buffer.edit(
 3283                edits,
 3284                Some(AutoindentMode::Block {
 3285                    original_indent_columns,
 3286                }),
 3287                cx,
 3288            )
 3289        });
 3290    }
 3291
 3292    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3293        self.hide_context_menu(window, cx);
 3294
 3295        match phase {
 3296            SelectPhase::Begin {
 3297                position,
 3298                add,
 3299                click_count,
 3300            } => self.begin_selection(position, add, click_count, window, cx),
 3301            SelectPhase::BeginColumnar {
 3302                position,
 3303                goal_column,
 3304                reset,
 3305                mode,
 3306            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3307            SelectPhase::Extend {
 3308                position,
 3309                click_count,
 3310            } => self.extend_selection(position, click_count, window, cx),
 3311            SelectPhase::Update {
 3312                position,
 3313                goal_column,
 3314                scroll_delta,
 3315            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3316            SelectPhase::End => self.end_selection(window, cx),
 3317        }
 3318    }
 3319
 3320    fn extend_selection(
 3321        &mut self,
 3322        position: DisplayPoint,
 3323        click_count: usize,
 3324        window: &mut Window,
 3325        cx: &mut Context<Self>,
 3326    ) {
 3327        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3328        let tail = self.selections.newest::<usize>(cx).tail();
 3329        self.begin_selection(position, false, click_count, window, cx);
 3330
 3331        let position = position.to_offset(&display_map, Bias::Left);
 3332        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3333
 3334        let mut pending_selection = self
 3335            .selections
 3336            .pending_anchor()
 3337            .expect("extend_selection not called with pending selection");
 3338        if position >= tail {
 3339            pending_selection.start = tail_anchor;
 3340        } else {
 3341            pending_selection.end = tail_anchor;
 3342            pending_selection.reversed = true;
 3343        }
 3344
 3345        let mut pending_mode = self.selections.pending_mode().unwrap();
 3346        match &mut pending_mode {
 3347            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3348            _ => {}
 3349        }
 3350
 3351        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3352            SelectionEffects::scroll(Autoscroll::fit())
 3353        } else {
 3354            SelectionEffects::no_scroll()
 3355        };
 3356
 3357        self.change_selections(effects, window, cx, |s| {
 3358            s.set_pending(pending_selection, pending_mode)
 3359        });
 3360    }
 3361
 3362    fn begin_selection(
 3363        &mut self,
 3364        position: DisplayPoint,
 3365        add: bool,
 3366        click_count: usize,
 3367        window: &mut Window,
 3368        cx: &mut Context<Self>,
 3369    ) {
 3370        if !self.focus_handle.is_focused(window) {
 3371            self.last_focused_descendant = None;
 3372            window.focus(&self.focus_handle);
 3373        }
 3374
 3375        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3376        let buffer = &display_map.buffer_snapshot;
 3377        let position = display_map.clip_point(position, Bias::Left);
 3378
 3379        let start;
 3380        let end;
 3381        let mode;
 3382        let mut auto_scroll;
 3383        match click_count {
 3384            1 => {
 3385                start = buffer.anchor_before(position.to_point(&display_map));
 3386                end = start;
 3387                mode = SelectMode::Character;
 3388                auto_scroll = true;
 3389            }
 3390            2 => {
 3391                let position = display_map
 3392                    .clip_point(position, Bias::Left)
 3393                    .to_offset(&display_map, Bias::Left);
 3394                let (range, _) = buffer.surrounding_word(position, false);
 3395                start = buffer.anchor_before(range.start);
 3396                end = buffer.anchor_before(range.end);
 3397                mode = SelectMode::Word(start..end);
 3398                auto_scroll = true;
 3399            }
 3400            3 => {
 3401                let position = display_map
 3402                    .clip_point(position, Bias::Left)
 3403                    .to_point(&display_map);
 3404                let line_start = display_map.prev_line_boundary(position).0;
 3405                let next_line_start = buffer.clip_point(
 3406                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3407                    Bias::Left,
 3408                );
 3409                start = buffer.anchor_before(line_start);
 3410                end = buffer.anchor_before(next_line_start);
 3411                mode = SelectMode::Line(start..end);
 3412                auto_scroll = true;
 3413            }
 3414            _ => {
 3415                start = buffer.anchor_before(0);
 3416                end = buffer.anchor_before(buffer.len());
 3417                mode = SelectMode::All;
 3418                auto_scroll = false;
 3419            }
 3420        }
 3421        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3422
 3423        let point_to_delete: Option<usize> = {
 3424            let selected_points: Vec<Selection<Point>> =
 3425                self.selections.disjoint_in_range(start..end, cx);
 3426
 3427            if !add || click_count > 1 {
 3428                None
 3429            } else if !selected_points.is_empty() {
 3430                Some(selected_points[0].id)
 3431            } else {
 3432                let clicked_point_already_selected =
 3433                    self.selections.disjoint.iter().find(|selection| {
 3434                        selection.start.to_point(buffer) == start.to_point(buffer)
 3435                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3436                    });
 3437
 3438                clicked_point_already_selected.map(|selection| selection.id)
 3439            }
 3440        };
 3441
 3442        let selections_count = self.selections.count();
 3443
 3444        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3445            if let Some(point_to_delete) = point_to_delete {
 3446                s.delete(point_to_delete);
 3447
 3448                if selections_count == 1 {
 3449                    s.set_pending_anchor_range(start..end, mode);
 3450                }
 3451            } else {
 3452                if !add {
 3453                    s.clear_disjoint();
 3454                }
 3455
 3456                s.set_pending_anchor_range(start..end, mode);
 3457            }
 3458        });
 3459    }
 3460
 3461    fn begin_columnar_selection(
 3462        &mut self,
 3463        position: DisplayPoint,
 3464        goal_column: u32,
 3465        reset: bool,
 3466        mode: ColumnarMode,
 3467        window: &mut Window,
 3468        cx: &mut Context<Self>,
 3469    ) {
 3470        if !self.focus_handle.is_focused(window) {
 3471            self.last_focused_descendant = None;
 3472            window.focus(&self.focus_handle);
 3473        }
 3474
 3475        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3476
 3477        if reset {
 3478            let pointer_position = display_map
 3479                .buffer_snapshot
 3480                .anchor_before(position.to_point(&display_map));
 3481
 3482            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3483                s.clear_disjoint();
 3484                s.set_pending_anchor_range(
 3485                    pointer_position..pointer_position,
 3486                    SelectMode::Character,
 3487                );
 3488            });
 3489        };
 3490
 3491        let tail = self.selections.newest::<Point>(cx).tail();
 3492        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3493        self.columnar_selection_state = match mode {
 3494            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3495                selection_tail: selection_anchor,
 3496                display_point: if reset {
 3497                    if position.column() != goal_column {
 3498                        Some(DisplayPoint::new(position.row(), goal_column))
 3499                    } else {
 3500                        None
 3501                    }
 3502                } else {
 3503                    None
 3504                },
 3505            }),
 3506            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3507                selection_tail: selection_anchor,
 3508            }),
 3509        };
 3510
 3511        if !reset {
 3512            self.select_columns(position, goal_column, &display_map, window, cx);
 3513        }
 3514    }
 3515
 3516    fn update_selection(
 3517        &mut self,
 3518        position: DisplayPoint,
 3519        goal_column: u32,
 3520        scroll_delta: gpui::Point<f32>,
 3521        window: &mut Window,
 3522        cx: &mut Context<Self>,
 3523    ) {
 3524        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3525
 3526        if self.columnar_selection_state.is_some() {
 3527            self.select_columns(position, goal_column, &display_map, window, cx);
 3528        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3529            let buffer = &display_map.buffer_snapshot;
 3530            let head;
 3531            let tail;
 3532            let mode = self.selections.pending_mode().unwrap();
 3533            match &mode {
 3534                SelectMode::Character => {
 3535                    head = position.to_point(&display_map);
 3536                    tail = pending.tail().to_point(buffer);
 3537                }
 3538                SelectMode::Word(original_range) => {
 3539                    let offset = display_map
 3540                        .clip_point(position, Bias::Left)
 3541                        .to_offset(&display_map, Bias::Left);
 3542                    let original_range = original_range.to_offset(buffer);
 3543
 3544                    let head_offset = if buffer.is_inside_word(offset, false)
 3545                        || original_range.contains(&offset)
 3546                    {
 3547                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3548                        if word_range.start < original_range.start {
 3549                            word_range.start
 3550                        } else {
 3551                            word_range.end
 3552                        }
 3553                    } else {
 3554                        offset
 3555                    };
 3556
 3557                    head = head_offset.to_point(buffer);
 3558                    if head_offset <= original_range.start {
 3559                        tail = original_range.end.to_point(buffer);
 3560                    } else {
 3561                        tail = original_range.start.to_point(buffer);
 3562                    }
 3563                }
 3564                SelectMode::Line(original_range) => {
 3565                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3566
 3567                    let position = display_map
 3568                        .clip_point(position, Bias::Left)
 3569                        .to_point(&display_map);
 3570                    let line_start = display_map.prev_line_boundary(position).0;
 3571                    let next_line_start = buffer.clip_point(
 3572                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3573                        Bias::Left,
 3574                    );
 3575
 3576                    if line_start < original_range.start {
 3577                        head = line_start
 3578                    } else {
 3579                        head = next_line_start
 3580                    }
 3581
 3582                    if head <= original_range.start {
 3583                        tail = original_range.end;
 3584                    } else {
 3585                        tail = original_range.start;
 3586                    }
 3587                }
 3588                SelectMode::All => {
 3589                    return;
 3590                }
 3591            };
 3592
 3593            if head < tail {
 3594                pending.start = buffer.anchor_before(head);
 3595                pending.end = buffer.anchor_before(tail);
 3596                pending.reversed = true;
 3597            } else {
 3598                pending.start = buffer.anchor_before(tail);
 3599                pending.end = buffer.anchor_before(head);
 3600                pending.reversed = false;
 3601            }
 3602
 3603            self.change_selections(None, window, cx, |s| {
 3604                s.set_pending(pending, mode);
 3605            });
 3606        } else {
 3607            log::error!("update_selection dispatched with no pending selection");
 3608            return;
 3609        }
 3610
 3611        self.apply_scroll_delta(scroll_delta, window, cx);
 3612        cx.notify();
 3613    }
 3614
 3615    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3616        self.columnar_selection_state.take();
 3617        if self.selections.pending_anchor().is_some() {
 3618            let selections = self.selections.all::<usize>(cx);
 3619            self.change_selections(None, window, cx, |s| {
 3620                s.select(selections);
 3621                s.clear_pending();
 3622            });
 3623        }
 3624    }
 3625
 3626    fn select_columns(
 3627        &mut self,
 3628        head: DisplayPoint,
 3629        goal_column: u32,
 3630        display_map: &DisplaySnapshot,
 3631        window: &mut Window,
 3632        cx: &mut Context<Self>,
 3633    ) {
 3634        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3635            return;
 3636        };
 3637
 3638        let tail = match columnar_state {
 3639            ColumnarSelectionState::FromMouse {
 3640                selection_tail,
 3641                display_point,
 3642            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3643            ColumnarSelectionState::FromSelection { selection_tail } => {
 3644                selection_tail.to_display_point(&display_map)
 3645            }
 3646        };
 3647
 3648        let start_row = cmp::min(tail.row(), head.row());
 3649        let end_row = cmp::max(tail.row(), head.row());
 3650        let start_column = cmp::min(tail.column(), goal_column);
 3651        let end_column = cmp::max(tail.column(), goal_column);
 3652        let reversed = start_column < tail.column();
 3653
 3654        let selection_ranges = (start_row.0..=end_row.0)
 3655            .map(DisplayRow)
 3656            .filter_map(|row| {
 3657                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3658                    || start_column <= display_map.line_len(row))
 3659                    && !display_map.is_block_line(row)
 3660                {
 3661                    let start = display_map
 3662                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3663                        .to_point(display_map);
 3664                    let end = display_map
 3665                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3666                        .to_point(display_map);
 3667                    if reversed {
 3668                        Some(end..start)
 3669                    } else {
 3670                        Some(start..end)
 3671                    }
 3672                } else {
 3673                    None
 3674                }
 3675            })
 3676            .collect::<Vec<_>>();
 3677
 3678        let ranges = match columnar_state {
 3679            ColumnarSelectionState::FromMouse { .. } => {
 3680                let mut non_empty_ranges = selection_ranges
 3681                    .iter()
 3682                    .filter(|selection_range| selection_range.start != selection_range.end)
 3683                    .peekable();
 3684                if non_empty_ranges.peek().is_some() {
 3685                    non_empty_ranges.cloned().collect()
 3686                } else {
 3687                    selection_ranges
 3688                }
 3689            }
 3690            _ => selection_ranges,
 3691        };
 3692
 3693        self.change_selections(None, window, cx, |s| {
 3694            s.select_ranges(ranges);
 3695        });
 3696        cx.notify();
 3697    }
 3698
 3699    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3700        self.selections
 3701            .all_adjusted(cx)
 3702            .iter()
 3703            .any(|selection| !selection.is_empty())
 3704    }
 3705
 3706    pub fn has_pending_nonempty_selection(&self) -> bool {
 3707        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3708            Some(Selection { start, end, .. }) => start != end,
 3709            None => false,
 3710        };
 3711
 3712        pending_nonempty_selection
 3713            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3714    }
 3715
 3716    pub fn has_pending_selection(&self) -> bool {
 3717        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3718    }
 3719
 3720    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3721        self.selection_mark_mode = false;
 3722        self.selection_drag_state = SelectionDragState::None;
 3723
 3724        if self.clear_expanded_diff_hunks(cx) {
 3725            cx.notify();
 3726            return;
 3727        }
 3728        if self.dismiss_menus_and_popups(true, window, cx) {
 3729            return;
 3730        }
 3731
 3732        if self.mode.is_full()
 3733            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3734        {
 3735            return;
 3736        }
 3737
 3738        cx.propagate();
 3739    }
 3740
 3741    pub fn dismiss_menus_and_popups(
 3742        &mut self,
 3743        is_user_requested: bool,
 3744        window: &mut Window,
 3745        cx: &mut Context<Self>,
 3746    ) -> bool {
 3747        if self.take_rename(false, window, cx).is_some() {
 3748            return true;
 3749        }
 3750
 3751        if hide_hover(self, cx) {
 3752            return true;
 3753        }
 3754
 3755        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3756            return true;
 3757        }
 3758
 3759        if self.hide_context_menu(window, cx).is_some() {
 3760            return true;
 3761        }
 3762
 3763        if self.mouse_context_menu.take().is_some() {
 3764            return true;
 3765        }
 3766
 3767        if is_user_requested && self.discard_inline_completion(true, cx) {
 3768            return true;
 3769        }
 3770
 3771        if self.snippet_stack.pop().is_some() {
 3772            return true;
 3773        }
 3774
 3775        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3776            self.dismiss_diagnostics(cx);
 3777            return true;
 3778        }
 3779
 3780        false
 3781    }
 3782
 3783    fn linked_editing_ranges_for(
 3784        &self,
 3785        selection: Range<text::Anchor>,
 3786        cx: &App,
 3787    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3788        if self.linked_edit_ranges.is_empty() {
 3789            return None;
 3790        }
 3791        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3792            selection.end.buffer_id.and_then(|end_buffer_id| {
 3793                if selection.start.buffer_id != Some(end_buffer_id) {
 3794                    return None;
 3795                }
 3796                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3797                let snapshot = buffer.read(cx).snapshot();
 3798                self.linked_edit_ranges
 3799                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3800                    .map(|ranges| (ranges, snapshot, buffer))
 3801            })?;
 3802        use text::ToOffset as TO;
 3803        // find offset from the start of current range to current cursor position
 3804        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3805
 3806        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3807        let start_difference = start_offset - start_byte_offset;
 3808        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3809        let end_difference = end_offset - start_byte_offset;
 3810        // Current range has associated linked ranges.
 3811        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3812        for range in linked_ranges.iter() {
 3813            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3814            let end_offset = start_offset + end_difference;
 3815            let start_offset = start_offset + start_difference;
 3816            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3817                continue;
 3818            }
 3819            if self.selections.disjoint_anchor_ranges().any(|s| {
 3820                if s.start.buffer_id != selection.start.buffer_id
 3821                    || s.end.buffer_id != selection.end.buffer_id
 3822                {
 3823                    return false;
 3824                }
 3825                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3826                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3827            }) {
 3828                continue;
 3829            }
 3830            let start = buffer_snapshot.anchor_after(start_offset);
 3831            let end = buffer_snapshot.anchor_after(end_offset);
 3832            linked_edits
 3833                .entry(buffer.clone())
 3834                .or_default()
 3835                .push(start..end);
 3836        }
 3837        Some(linked_edits)
 3838    }
 3839
 3840    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3841        let text: Arc<str> = text.into();
 3842
 3843        if self.read_only(cx) {
 3844            return;
 3845        }
 3846
 3847        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3848
 3849        let selections = self.selections.all_adjusted(cx);
 3850        let mut bracket_inserted = false;
 3851        let mut edits = Vec::new();
 3852        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3853        let mut new_selections = Vec::with_capacity(selections.len());
 3854        let mut new_autoclose_regions = Vec::new();
 3855        let snapshot = self.buffer.read(cx).read(cx);
 3856        let mut clear_linked_edit_ranges = false;
 3857
 3858        for (selection, autoclose_region) in
 3859            self.selections_with_autoclose_regions(selections, &snapshot)
 3860        {
 3861            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3862                // Determine if the inserted text matches the opening or closing
 3863                // bracket of any of this language's bracket pairs.
 3864                let mut bracket_pair = None;
 3865                let mut is_bracket_pair_start = false;
 3866                let mut is_bracket_pair_end = false;
 3867                if !text.is_empty() {
 3868                    let mut bracket_pair_matching_end = None;
 3869                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3870                    //  and they are removing the character that triggered IME popup.
 3871                    for (pair, enabled) in scope.brackets() {
 3872                        if !pair.close && !pair.surround {
 3873                            continue;
 3874                        }
 3875
 3876                        if enabled && pair.start.ends_with(text.as_ref()) {
 3877                            let prefix_len = pair.start.len() - text.len();
 3878                            let preceding_text_matches_prefix = prefix_len == 0
 3879                                || (selection.start.column >= (prefix_len as u32)
 3880                                    && snapshot.contains_str_at(
 3881                                        Point::new(
 3882                                            selection.start.row,
 3883                                            selection.start.column - (prefix_len as u32),
 3884                                        ),
 3885                                        &pair.start[..prefix_len],
 3886                                    ));
 3887                            if preceding_text_matches_prefix {
 3888                                bracket_pair = Some(pair.clone());
 3889                                is_bracket_pair_start = true;
 3890                                break;
 3891                            }
 3892                        }
 3893                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3894                        {
 3895                            // take first bracket pair matching end, but don't break in case a later bracket
 3896                            // pair matches start
 3897                            bracket_pair_matching_end = Some(pair.clone());
 3898                        }
 3899                    }
 3900                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3901                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3902                        is_bracket_pair_end = true;
 3903                    }
 3904                }
 3905
 3906                if let Some(bracket_pair) = bracket_pair {
 3907                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3908                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3909                    let auto_surround =
 3910                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3911                    if selection.is_empty() {
 3912                        if is_bracket_pair_start {
 3913                            // If the inserted text is a suffix of an opening bracket and the
 3914                            // selection is preceded by the rest of the opening bracket, then
 3915                            // insert the closing bracket.
 3916                            let following_text_allows_autoclose = snapshot
 3917                                .chars_at(selection.start)
 3918                                .next()
 3919                                .map_or(true, |c| scope.should_autoclose_before(c));
 3920
 3921                            let preceding_text_allows_autoclose = selection.start.column == 0
 3922                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3923                                    true,
 3924                                    |c| {
 3925                                        bracket_pair.start != bracket_pair.end
 3926                                            || !snapshot
 3927                                                .char_classifier_at(selection.start)
 3928                                                .is_word(c)
 3929                                    },
 3930                                );
 3931
 3932                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3933                                && bracket_pair.start.len() == 1
 3934                            {
 3935                                let target = bracket_pair.start.chars().next().unwrap();
 3936                                let current_line_count = snapshot
 3937                                    .reversed_chars_at(selection.start)
 3938                                    .take_while(|&c| c != '\n')
 3939                                    .filter(|&c| c == target)
 3940                                    .count();
 3941                                current_line_count % 2 == 1
 3942                            } else {
 3943                                false
 3944                            };
 3945
 3946                            if autoclose
 3947                                && bracket_pair.close
 3948                                && following_text_allows_autoclose
 3949                                && preceding_text_allows_autoclose
 3950                                && !is_closing_quote
 3951                            {
 3952                                let anchor = snapshot.anchor_before(selection.end);
 3953                                new_selections.push((selection.map(|_| anchor), text.len()));
 3954                                new_autoclose_regions.push((
 3955                                    anchor,
 3956                                    text.len(),
 3957                                    selection.id,
 3958                                    bracket_pair.clone(),
 3959                                ));
 3960                                edits.push((
 3961                                    selection.range(),
 3962                                    format!("{}{}", text, bracket_pair.end).into(),
 3963                                ));
 3964                                bracket_inserted = true;
 3965                                continue;
 3966                            }
 3967                        }
 3968
 3969                        if let Some(region) = autoclose_region {
 3970                            // If the selection is followed by an auto-inserted closing bracket,
 3971                            // then don't insert that closing bracket again; just move the selection
 3972                            // past the closing bracket.
 3973                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3974                                && text.as_ref() == region.pair.end.as_str();
 3975                            if should_skip {
 3976                                let anchor = snapshot.anchor_after(selection.end);
 3977                                new_selections
 3978                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3979                                continue;
 3980                            }
 3981                        }
 3982
 3983                        let always_treat_brackets_as_autoclosed = snapshot
 3984                            .language_settings_at(selection.start, cx)
 3985                            .always_treat_brackets_as_autoclosed;
 3986                        if always_treat_brackets_as_autoclosed
 3987                            && is_bracket_pair_end
 3988                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3989                        {
 3990                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3991                            // and the inserted text is a closing bracket and the selection is followed
 3992                            // by the closing bracket then move the selection past the closing bracket.
 3993                            let anchor = snapshot.anchor_after(selection.end);
 3994                            new_selections.push((selection.map(|_| anchor), text.len()));
 3995                            continue;
 3996                        }
 3997                    }
 3998                    // If an opening bracket is 1 character long and is typed while
 3999                    // text is selected, then surround that text with the bracket pair.
 4000                    else if auto_surround
 4001                        && bracket_pair.surround
 4002                        && is_bracket_pair_start
 4003                        && bracket_pair.start.chars().count() == 1
 4004                    {
 4005                        edits.push((selection.start..selection.start, text.clone()));
 4006                        edits.push((
 4007                            selection.end..selection.end,
 4008                            bracket_pair.end.as_str().into(),
 4009                        ));
 4010                        bracket_inserted = true;
 4011                        new_selections.push((
 4012                            Selection {
 4013                                id: selection.id,
 4014                                start: snapshot.anchor_after(selection.start),
 4015                                end: snapshot.anchor_before(selection.end),
 4016                                reversed: selection.reversed,
 4017                                goal: selection.goal,
 4018                            },
 4019                            0,
 4020                        ));
 4021                        continue;
 4022                    }
 4023                }
 4024            }
 4025
 4026            if self.auto_replace_emoji_shortcode
 4027                && selection.is_empty()
 4028                && text.as_ref().ends_with(':')
 4029            {
 4030                if let Some(possible_emoji_short_code) =
 4031                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4032                {
 4033                    if !possible_emoji_short_code.is_empty() {
 4034                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4035                            let emoji_shortcode_start = Point::new(
 4036                                selection.start.row,
 4037                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4038                            );
 4039
 4040                            // Remove shortcode from buffer
 4041                            edits.push((
 4042                                emoji_shortcode_start..selection.start,
 4043                                "".to_string().into(),
 4044                            ));
 4045                            new_selections.push((
 4046                                Selection {
 4047                                    id: selection.id,
 4048                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4049                                    end: snapshot.anchor_before(selection.start),
 4050                                    reversed: selection.reversed,
 4051                                    goal: selection.goal,
 4052                                },
 4053                                0,
 4054                            ));
 4055
 4056                            // Insert emoji
 4057                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4058                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4059                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4060
 4061                            continue;
 4062                        }
 4063                    }
 4064                }
 4065            }
 4066
 4067            // If not handling any auto-close operation, then just replace the selected
 4068            // text with the given input and move the selection to the end of the
 4069            // newly inserted text.
 4070            let anchor = snapshot.anchor_after(selection.end);
 4071            if !self.linked_edit_ranges.is_empty() {
 4072                let start_anchor = snapshot.anchor_before(selection.start);
 4073
 4074                let is_word_char = text.chars().next().map_or(true, |char| {
 4075                    let classifier = snapshot
 4076                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4077                        .ignore_punctuation(true);
 4078                    classifier.is_word(char)
 4079                });
 4080
 4081                if is_word_char {
 4082                    if let Some(ranges) = self
 4083                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4084                    {
 4085                        for (buffer, edits) in ranges {
 4086                            linked_edits
 4087                                .entry(buffer.clone())
 4088                                .or_default()
 4089                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4090                        }
 4091                    }
 4092                } else {
 4093                    clear_linked_edit_ranges = true;
 4094                }
 4095            }
 4096
 4097            new_selections.push((selection.map(|_| anchor), 0));
 4098            edits.push((selection.start..selection.end, text.clone()));
 4099        }
 4100
 4101        drop(snapshot);
 4102
 4103        self.transact(window, cx, |this, window, cx| {
 4104            if clear_linked_edit_ranges {
 4105                this.linked_edit_ranges.clear();
 4106            }
 4107            let initial_buffer_versions =
 4108                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4109
 4110            this.buffer.update(cx, |buffer, cx| {
 4111                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4112            });
 4113            for (buffer, edits) in linked_edits {
 4114                buffer.update(cx, |buffer, cx| {
 4115                    let snapshot = buffer.snapshot();
 4116                    let edits = edits
 4117                        .into_iter()
 4118                        .map(|(range, text)| {
 4119                            use text::ToPoint as TP;
 4120                            let end_point = TP::to_point(&range.end, &snapshot);
 4121                            let start_point = TP::to_point(&range.start, &snapshot);
 4122                            (start_point..end_point, text)
 4123                        })
 4124                        .sorted_by_key(|(range, _)| range.start);
 4125                    buffer.edit(edits, None, cx);
 4126                })
 4127            }
 4128            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4129            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4130            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4131            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4132                .zip(new_selection_deltas)
 4133                .map(|(selection, delta)| Selection {
 4134                    id: selection.id,
 4135                    start: selection.start + delta,
 4136                    end: selection.end + delta,
 4137                    reversed: selection.reversed,
 4138                    goal: SelectionGoal::None,
 4139                })
 4140                .collect::<Vec<_>>();
 4141
 4142            let mut i = 0;
 4143            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4144                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4145                let start = map.buffer_snapshot.anchor_before(position);
 4146                let end = map.buffer_snapshot.anchor_after(position);
 4147                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4148                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4149                        Ordering::Less => i += 1,
 4150                        Ordering::Greater => break,
 4151                        Ordering::Equal => {
 4152                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4153                                Ordering::Less => i += 1,
 4154                                Ordering::Equal => break,
 4155                                Ordering::Greater => break,
 4156                            }
 4157                        }
 4158                    }
 4159                }
 4160                this.autoclose_regions.insert(
 4161                    i,
 4162                    AutocloseRegion {
 4163                        selection_id,
 4164                        range: start..end,
 4165                        pair,
 4166                    },
 4167                );
 4168            }
 4169
 4170            let had_active_inline_completion = this.has_active_inline_completion();
 4171            this.change_selections(
 4172                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4173                window,
 4174                cx,
 4175                |s| s.select(new_selections),
 4176            );
 4177
 4178            if !bracket_inserted {
 4179                if let Some(on_type_format_task) =
 4180                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4181                {
 4182                    on_type_format_task.detach_and_log_err(cx);
 4183                }
 4184            }
 4185
 4186            let editor_settings = EditorSettings::get_global(cx);
 4187            if bracket_inserted
 4188                && (editor_settings.auto_signature_help
 4189                    || editor_settings.show_signature_help_after_edits)
 4190            {
 4191                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4192            }
 4193
 4194            let trigger_in_words =
 4195                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4196            if this.hard_wrap.is_some() {
 4197                let latest: Range<Point> = this.selections.newest(cx).range();
 4198                if latest.is_empty()
 4199                    && this
 4200                        .buffer()
 4201                        .read(cx)
 4202                        .snapshot(cx)
 4203                        .line_len(MultiBufferRow(latest.start.row))
 4204                        == latest.start.column
 4205                {
 4206                    this.rewrap_impl(
 4207                        RewrapOptions {
 4208                            override_language_settings: true,
 4209                            preserve_existing_whitespace: true,
 4210                        },
 4211                        cx,
 4212                    )
 4213                }
 4214            }
 4215            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4216            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4217            this.refresh_inline_completion(true, false, window, cx);
 4218            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4219        });
 4220    }
 4221
 4222    fn find_possible_emoji_shortcode_at_position(
 4223        snapshot: &MultiBufferSnapshot,
 4224        position: Point,
 4225    ) -> Option<String> {
 4226        let mut chars = Vec::new();
 4227        let mut found_colon = false;
 4228        for char in snapshot.reversed_chars_at(position).take(100) {
 4229            // Found a possible emoji shortcode in the middle of the buffer
 4230            if found_colon {
 4231                if char.is_whitespace() {
 4232                    chars.reverse();
 4233                    return Some(chars.iter().collect());
 4234                }
 4235                // If the previous character is not a whitespace, we are in the middle of a word
 4236                // and we only want to complete the shortcode if the word is made up of other emojis
 4237                let mut containing_word = String::new();
 4238                for ch in snapshot
 4239                    .reversed_chars_at(position)
 4240                    .skip(chars.len() + 1)
 4241                    .take(100)
 4242                {
 4243                    if ch.is_whitespace() {
 4244                        break;
 4245                    }
 4246                    containing_word.push(ch);
 4247                }
 4248                let containing_word = containing_word.chars().rev().collect::<String>();
 4249                if util::word_consists_of_emojis(containing_word.as_str()) {
 4250                    chars.reverse();
 4251                    return Some(chars.iter().collect());
 4252                }
 4253            }
 4254
 4255            if char.is_whitespace() || !char.is_ascii() {
 4256                return None;
 4257            }
 4258            if char == ':' {
 4259                found_colon = true;
 4260            } else {
 4261                chars.push(char);
 4262            }
 4263        }
 4264        // Found a possible emoji shortcode at the beginning of the buffer
 4265        chars.reverse();
 4266        Some(chars.iter().collect())
 4267    }
 4268
 4269    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4270        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4271        self.transact(window, cx, |this, window, cx| {
 4272            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4273                let selections = this.selections.all::<usize>(cx);
 4274                let multi_buffer = this.buffer.read(cx);
 4275                let buffer = multi_buffer.snapshot(cx);
 4276                selections
 4277                    .iter()
 4278                    .map(|selection| {
 4279                        let start_point = selection.start.to_point(&buffer);
 4280                        let mut existing_indent =
 4281                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4282                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4283                        let start = selection.start;
 4284                        let end = selection.end;
 4285                        let selection_is_empty = start == end;
 4286                        let language_scope = buffer.language_scope_at(start);
 4287                        let (
 4288                            comment_delimiter,
 4289                            doc_delimiter,
 4290                            insert_extra_newline,
 4291                            indent_on_newline,
 4292                            indent_on_extra_newline,
 4293                        ) = if let Some(language) = &language_scope {
 4294                            let mut insert_extra_newline =
 4295                                insert_extra_newline_brackets(&buffer, start..end, language)
 4296                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4297
 4298                            // Comment extension on newline is allowed only for cursor selections
 4299                            let comment_delimiter = maybe!({
 4300                                if !selection_is_empty {
 4301                                    return None;
 4302                                }
 4303
 4304                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4305                                    return None;
 4306                                }
 4307
 4308                                let delimiters = language.line_comment_prefixes();
 4309                                let max_len_of_delimiter =
 4310                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4311                                let (snapshot, range) =
 4312                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4313
 4314                                let num_of_whitespaces = snapshot
 4315                                    .chars_for_range(range.clone())
 4316                                    .take_while(|c| c.is_whitespace())
 4317                                    .count();
 4318                                let comment_candidate = snapshot
 4319                                    .chars_for_range(range)
 4320                                    .skip(num_of_whitespaces)
 4321                                    .take(max_len_of_delimiter)
 4322                                    .collect::<String>();
 4323                                let (delimiter, trimmed_len) = delimiters
 4324                                    .iter()
 4325                                    .filter_map(|delimiter| {
 4326                                        let prefix = delimiter.trim_end();
 4327                                        if comment_candidate.starts_with(prefix) {
 4328                                            Some((delimiter, prefix.len()))
 4329                                        } else {
 4330                                            None
 4331                                        }
 4332                                    })
 4333                                    .max_by_key(|(_, len)| *len)?;
 4334
 4335                                let cursor_is_placed_after_comment_marker =
 4336                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4337                                if cursor_is_placed_after_comment_marker {
 4338                                    Some(delimiter.clone())
 4339                                } else {
 4340                                    None
 4341                                }
 4342                            });
 4343
 4344                            let mut indent_on_newline = IndentSize::spaces(0);
 4345                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4346
 4347                            let doc_delimiter = maybe!({
 4348                                if !selection_is_empty {
 4349                                    return None;
 4350                                }
 4351
 4352                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4353                                    return None;
 4354                                }
 4355
 4356                                let DocumentationConfig {
 4357                                    start: start_tag,
 4358                                    end: end_tag,
 4359                                    prefix: delimiter,
 4360                                    tab_size: len,
 4361                                } = language.documentation()?;
 4362
 4363                                let is_within_block_comment = buffer
 4364                                    .language_scope_at(start_point)
 4365                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4366                                if !is_within_block_comment {
 4367                                    return None;
 4368                                }
 4369
 4370                                let (snapshot, range) =
 4371                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4372
 4373                                let num_of_whitespaces = snapshot
 4374                                    .chars_for_range(range.clone())
 4375                                    .take_while(|c| c.is_whitespace())
 4376                                    .count();
 4377
 4378                                // 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.
 4379                                let column = start_point.column;
 4380                                let cursor_is_after_start_tag = {
 4381                                    let start_tag_len = start_tag.len();
 4382                                    let start_tag_line = snapshot
 4383                                        .chars_for_range(range.clone())
 4384                                        .skip(num_of_whitespaces)
 4385                                        .take(start_tag_len)
 4386                                        .collect::<String>();
 4387                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4388                                        num_of_whitespaces + start_tag_len <= column as usize
 4389                                    } else {
 4390                                        false
 4391                                    }
 4392                                };
 4393
 4394                                let cursor_is_after_delimiter = {
 4395                                    let delimiter_trim = delimiter.trim_end();
 4396                                    let delimiter_line = snapshot
 4397                                        .chars_for_range(range.clone())
 4398                                        .skip(num_of_whitespaces)
 4399                                        .take(delimiter_trim.len())
 4400                                        .collect::<String>();
 4401                                    if delimiter_line.starts_with(delimiter_trim) {
 4402                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4403                                    } else {
 4404                                        false
 4405                                    }
 4406                                };
 4407
 4408                                let cursor_is_before_end_tag_if_exists = {
 4409                                    let mut char_position = 0u32;
 4410                                    let mut end_tag_offset = None;
 4411
 4412                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4413                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4414                                            let chars_before_match =
 4415                                                chunk[..byte_pos].chars().count() as u32;
 4416                                            end_tag_offset =
 4417                                                Some(char_position + chars_before_match);
 4418                                            break 'outer;
 4419                                        }
 4420                                        char_position += chunk.chars().count() as u32;
 4421                                    }
 4422
 4423                                    if let Some(end_tag_offset) = end_tag_offset {
 4424                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4425                                        if cursor_is_after_start_tag {
 4426                                            if cursor_is_before_end_tag {
 4427                                                insert_extra_newline = true;
 4428                                            }
 4429                                            let cursor_is_at_start_of_end_tag =
 4430                                                column == end_tag_offset;
 4431                                            if cursor_is_at_start_of_end_tag {
 4432                                                indent_on_extra_newline.len = (*len).into();
 4433                                            }
 4434                                        }
 4435                                        cursor_is_before_end_tag
 4436                                    } else {
 4437                                        true
 4438                                    }
 4439                                };
 4440
 4441                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4442                                    && cursor_is_before_end_tag_if_exists
 4443                                {
 4444                                    if cursor_is_after_start_tag {
 4445                                        indent_on_newline.len = (*len).into();
 4446                                    }
 4447                                    Some(delimiter.clone())
 4448                                } else {
 4449                                    None
 4450                                }
 4451                            });
 4452
 4453                            (
 4454                                comment_delimiter,
 4455                                doc_delimiter,
 4456                                insert_extra_newline,
 4457                                indent_on_newline,
 4458                                indent_on_extra_newline,
 4459                            )
 4460                        } else {
 4461                            (
 4462                                None,
 4463                                None,
 4464                                false,
 4465                                IndentSize::default(),
 4466                                IndentSize::default(),
 4467                            )
 4468                        };
 4469
 4470                        let prevent_auto_indent = doc_delimiter.is_some();
 4471                        let delimiter = comment_delimiter.or(doc_delimiter);
 4472
 4473                        let capacity_for_delimiter =
 4474                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4475                        let mut new_text = String::with_capacity(
 4476                            1 + capacity_for_delimiter
 4477                                + existing_indent.len as usize
 4478                                + indent_on_newline.len as usize
 4479                                + indent_on_extra_newline.len as usize,
 4480                        );
 4481                        new_text.push('\n');
 4482                        new_text.extend(existing_indent.chars());
 4483                        new_text.extend(indent_on_newline.chars());
 4484
 4485                        if let Some(delimiter) = &delimiter {
 4486                            new_text.push_str(delimiter);
 4487                        }
 4488
 4489                        if insert_extra_newline {
 4490                            new_text.push('\n');
 4491                            new_text.extend(existing_indent.chars());
 4492                            new_text.extend(indent_on_extra_newline.chars());
 4493                        }
 4494
 4495                        let anchor = buffer.anchor_after(end);
 4496                        let new_selection = selection.map(|_| anchor);
 4497                        (
 4498                            ((start..end, new_text), prevent_auto_indent),
 4499                            (insert_extra_newline, new_selection),
 4500                        )
 4501                    })
 4502                    .unzip()
 4503            };
 4504
 4505            let mut auto_indent_edits = Vec::new();
 4506            let mut edits = Vec::new();
 4507            for (edit, prevent_auto_indent) in edits_with_flags {
 4508                if prevent_auto_indent {
 4509                    edits.push(edit);
 4510                } else {
 4511                    auto_indent_edits.push(edit);
 4512                }
 4513            }
 4514            if !edits.is_empty() {
 4515                this.edit(edits, cx);
 4516            }
 4517            if !auto_indent_edits.is_empty() {
 4518                this.edit_with_autoindent(auto_indent_edits, cx);
 4519            }
 4520
 4521            let buffer = this.buffer.read(cx).snapshot(cx);
 4522            let new_selections = selection_info
 4523                .into_iter()
 4524                .map(|(extra_newline_inserted, new_selection)| {
 4525                    let mut cursor = new_selection.end.to_point(&buffer);
 4526                    if extra_newline_inserted {
 4527                        cursor.row -= 1;
 4528                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4529                    }
 4530                    new_selection.map(|_| cursor)
 4531                })
 4532                .collect();
 4533
 4534            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4535                s.select(new_selections)
 4536            });
 4537            this.refresh_inline_completion(true, false, window, cx);
 4538        });
 4539    }
 4540
 4541    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4542        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4543
 4544        let buffer = self.buffer.read(cx);
 4545        let snapshot = buffer.snapshot(cx);
 4546
 4547        let mut edits = Vec::new();
 4548        let mut rows = Vec::new();
 4549
 4550        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4551            let cursor = selection.head();
 4552            let row = cursor.row;
 4553
 4554            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4555
 4556            let newline = "\n".to_string();
 4557            edits.push((start_of_line..start_of_line, newline));
 4558
 4559            rows.push(row + rows_inserted as u32);
 4560        }
 4561
 4562        self.transact(window, cx, |editor, window, cx| {
 4563            editor.edit(edits, cx);
 4564
 4565            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4566                let mut index = 0;
 4567                s.move_cursors_with(|map, _, _| {
 4568                    let row = rows[index];
 4569                    index += 1;
 4570
 4571                    let point = Point::new(row, 0);
 4572                    let boundary = map.next_line_boundary(point).1;
 4573                    let clipped = map.clip_point(boundary, Bias::Left);
 4574
 4575                    (clipped, SelectionGoal::None)
 4576                });
 4577            });
 4578
 4579            let mut indent_edits = Vec::new();
 4580            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4581            for row in rows {
 4582                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4583                for (row, indent) in indents {
 4584                    if indent.len == 0 {
 4585                        continue;
 4586                    }
 4587
 4588                    let text = match indent.kind {
 4589                        IndentKind::Space => " ".repeat(indent.len as usize),
 4590                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4591                    };
 4592                    let point = Point::new(row.0, 0);
 4593                    indent_edits.push((point..point, text));
 4594                }
 4595            }
 4596            editor.edit(indent_edits, cx);
 4597        });
 4598    }
 4599
 4600    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4601        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4602
 4603        let buffer = self.buffer.read(cx);
 4604        let snapshot = buffer.snapshot(cx);
 4605
 4606        let mut edits = Vec::new();
 4607        let mut rows = Vec::new();
 4608        let mut rows_inserted = 0;
 4609
 4610        for selection in self.selections.all_adjusted(cx) {
 4611            let cursor = selection.head();
 4612            let row = cursor.row;
 4613
 4614            let point = Point::new(row + 1, 0);
 4615            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4616
 4617            let newline = "\n".to_string();
 4618            edits.push((start_of_line..start_of_line, newline));
 4619
 4620            rows_inserted += 1;
 4621            rows.push(row + rows_inserted);
 4622        }
 4623
 4624        self.transact(window, cx, |editor, window, cx| {
 4625            editor.edit(edits, cx);
 4626
 4627            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4628                let mut index = 0;
 4629                s.move_cursors_with(|map, _, _| {
 4630                    let row = rows[index];
 4631                    index += 1;
 4632
 4633                    let point = Point::new(row, 0);
 4634                    let boundary = map.next_line_boundary(point).1;
 4635                    let clipped = map.clip_point(boundary, Bias::Left);
 4636
 4637                    (clipped, SelectionGoal::None)
 4638                });
 4639            });
 4640
 4641            let mut indent_edits = Vec::new();
 4642            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4643            for row in rows {
 4644                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4645                for (row, indent) in indents {
 4646                    if indent.len == 0 {
 4647                        continue;
 4648                    }
 4649
 4650                    let text = match indent.kind {
 4651                        IndentKind::Space => " ".repeat(indent.len as usize),
 4652                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4653                    };
 4654                    let point = Point::new(row.0, 0);
 4655                    indent_edits.push((point..point, text));
 4656                }
 4657            }
 4658            editor.edit(indent_edits, cx);
 4659        });
 4660    }
 4661
 4662    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4663        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4664            original_indent_columns: Vec::new(),
 4665        });
 4666        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4667    }
 4668
 4669    fn insert_with_autoindent_mode(
 4670        &mut self,
 4671        text: &str,
 4672        autoindent_mode: Option<AutoindentMode>,
 4673        window: &mut Window,
 4674        cx: &mut Context<Self>,
 4675    ) {
 4676        if self.read_only(cx) {
 4677            return;
 4678        }
 4679
 4680        let text: Arc<str> = text.into();
 4681        self.transact(window, cx, |this, window, cx| {
 4682            let old_selections = this.selections.all_adjusted(cx);
 4683            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4684                let anchors = {
 4685                    let snapshot = buffer.read(cx);
 4686                    old_selections
 4687                        .iter()
 4688                        .map(|s| {
 4689                            let anchor = snapshot.anchor_after(s.head());
 4690                            s.map(|_| anchor)
 4691                        })
 4692                        .collect::<Vec<_>>()
 4693                };
 4694                buffer.edit(
 4695                    old_selections
 4696                        .iter()
 4697                        .map(|s| (s.start..s.end, text.clone())),
 4698                    autoindent_mode,
 4699                    cx,
 4700                );
 4701                anchors
 4702            });
 4703
 4704            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4705                s.select_anchors(selection_anchors);
 4706            });
 4707
 4708            cx.notify();
 4709        });
 4710    }
 4711
 4712    fn trigger_completion_on_input(
 4713        &mut self,
 4714        text: &str,
 4715        trigger_in_words: bool,
 4716        window: &mut Window,
 4717        cx: &mut Context<Self>,
 4718    ) {
 4719        let completions_source = self
 4720            .context_menu
 4721            .borrow()
 4722            .as_ref()
 4723            .and_then(|menu| match menu {
 4724                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4725                CodeContextMenu::CodeActions(_) => None,
 4726            });
 4727
 4728        match completions_source {
 4729            Some(CompletionsMenuSource::Words) => {
 4730                self.show_word_completions(&ShowWordCompletions, window, cx)
 4731            }
 4732            Some(CompletionsMenuSource::Normal)
 4733            | Some(CompletionsMenuSource::SnippetChoices)
 4734            | None
 4735                if self.is_completion_trigger(
 4736                    text,
 4737                    trigger_in_words,
 4738                    completions_source.is_some(),
 4739                    cx,
 4740                ) =>
 4741            {
 4742                self.show_completions(
 4743                    &ShowCompletions {
 4744                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4745                    },
 4746                    window,
 4747                    cx,
 4748                )
 4749            }
 4750            _ => {
 4751                self.hide_context_menu(window, cx);
 4752            }
 4753        }
 4754    }
 4755
 4756    fn is_completion_trigger(
 4757        &self,
 4758        text: &str,
 4759        trigger_in_words: bool,
 4760        menu_is_open: bool,
 4761        cx: &mut Context<Self>,
 4762    ) -> bool {
 4763        let position = self.selections.newest_anchor().head();
 4764        let multibuffer = self.buffer.read(cx);
 4765        let Some(buffer) = position
 4766            .buffer_id
 4767            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4768        else {
 4769            return false;
 4770        };
 4771
 4772        if let Some(completion_provider) = &self.completion_provider {
 4773            completion_provider.is_completion_trigger(
 4774                &buffer,
 4775                position.text_anchor,
 4776                text,
 4777                trigger_in_words,
 4778                menu_is_open,
 4779                cx,
 4780            )
 4781        } else {
 4782            false
 4783        }
 4784    }
 4785
 4786    /// If any empty selections is touching the start of its innermost containing autoclose
 4787    /// region, expand it to select the brackets.
 4788    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4789        let selections = self.selections.all::<usize>(cx);
 4790        let buffer = self.buffer.read(cx).read(cx);
 4791        let new_selections = self
 4792            .selections_with_autoclose_regions(selections, &buffer)
 4793            .map(|(mut selection, region)| {
 4794                if !selection.is_empty() {
 4795                    return selection;
 4796                }
 4797
 4798                if let Some(region) = region {
 4799                    let mut range = region.range.to_offset(&buffer);
 4800                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4801                        range.start -= region.pair.start.len();
 4802                        if buffer.contains_str_at(range.start, &region.pair.start)
 4803                            && buffer.contains_str_at(range.end, &region.pair.end)
 4804                        {
 4805                            range.end += region.pair.end.len();
 4806                            selection.start = range.start;
 4807                            selection.end = range.end;
 4808
 4809                            return selection;
 4810                        }
 4811                    }
 4812                }
 4813
 4814                let always_treat_brackets_as_autoclosed = buffer
 4815                    .language_settings_at(selection.start, cx)
 4816                    .always_treat_brackets_as_autoclosed;
 4817
 4818                if !always_treat_brackets_as_autoclosed {
 4819                    return selection;
 4820                }
 4821
 4822                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4823                    for (pair, enabled) in scope.brackets() {
 4824                        if !enabled || !pair.close {
 4825                            continue;
 4826                        }
 4827
 4828                        if buffer.contains_str_at(selection.start, &pair.end) {
 4829                            let pair_start_len = pair.start.len();
 4830                            if buffer.contains_str_at(
 4831                                selection.start.saturating_sub(pair_start_len),
 4832                                &pair.start,
 4833                            ) {
 4834                                selection.start -= pair_start_len;
 4835                                selection.end += pair.end.len();
 4836
 4837                                return selection;
 4838                            }
 4839                        }
 4840                    }
 4841                }
 4842
 4843                selection
 4844            })
 4845            .collect();
 4846
 4847        drop(buffer);
 4848        self.change_selections(None, window, cx, |selections| {
 4849            selections.select(new_selections)
 4850        });
 4851    }
 4852
 4853    /// Iterate the given selections, and for each one, find the smallest surrounding
 4854    /// autoclose region. This uses the ordering of the selections and the autoclose
 4855    /// regions to avoid repeated comparisons.
 4856    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4857        &'a self,
 4858        selections: impl IntoIterator<Item = Selection<D>>,
 4859        buffer: &'a MultiBufferSnapshot,
 4860    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4861        let mut i = 0;
 4862        let mut regions = self.autoclose_regions.as_slice();
 4863        selections.into_iter().map(move |selection| {
 4864            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4865
 4866            let mut enclosing = None;
 4867            while let Some(pair_state) = regions.get(i) {
 4868                if pair_state.range.end.to_offset(buffer) < range.start {
 4869                    regions = &regions[i + 1..];
 4870                    i = 0;
 4871                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4872                    break;
 4873                } else {
 4874                    if pair_state.selection_id == selection.id {
 4875                        enclosing = Some(pair_state);
 4876                    }
 4877                    i += 1;
 4878                }
 4879            }
 4880
 4881            (selection, enclosing)
 4882        })
 4883    }
 4884
 4885    /// Remove any autoclose regions that no longer contain their selection.
 4886    fn invalidate_autoclose_regions(
 4887        &mut self,
 4888        mut selections: &[Selection<Anchor>],
 4889        buffer: &MultiBufferSnapshot,
 4890    ) {
 4891        self.autoclose_regions.retain(|state| {
 4892            let mut i = 0;
 4893            while let Some(selection) = selections.get(i) {
 4894                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4895                    selections = &selections[1..];
 4896                    continue;
 4897                }
 4898                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4899                    break;
 4900                }
 4901                if selection.id == state.selection_id {
 4902                    return true;
 4903                } else {
 4904                    i += 1;
 4905                }
 4906            }
 4907            false
 4908        });
 4909    }
 4910
 4911    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4912        let offset = position.to_offset(buffer);
 4913        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4914        if offset > word_range.start && kind == Some(CharKind::Word) {
 4915            Some(
 4916                buffer
 4917                    .text_for_range(word_range.start..offset)
 4918                    .collect::<String>(),
 4919            )
 4920        } else {
 4921            None
 4922        }
 4923    }
 4924
 4925    pub fn toggle_inline_values(
 4926        &mut self,
 4927        _: &ToggleInlineValues,
 4928        _: &mut Window,
 4929        cx: &mut Context<Self>,
 4930    ) {
 4931        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4932
 4933        self.refresh_inline_values(cx);
 4934    }
 4935
 4936    pub fn toggle_inlay_hints(
 4937        &mut self,
 4938        _: &ToggleInlayHints,
 4939        _: &mut Window,
 4940        cx: &mut Context<Self>,
 4941    ) {
 4942        self.refresh_inlay_hints(
 4943            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4944            cx,
 4945        );
 4946    }
 4947
 4948    pub fn inlay_hints_enabled(&self) -> bool {
 4949        self.inlay_hint_cache.enabled
 4950    }
 4951
 4952    pub fn inline_values_enabled(&self) -> bool {
 4953        self.inline_value_cache.enabled
 4954    }
 4955
 4956    #[cfg(any(test, feature = "test-support"))]
 4957    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4958        self.display_map
 4959            .read(cx)
 4960            .current_inlays()
 4961            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4962            .cloned()
 4963            .collect()
 4964    }
 4965
 4966    #[cfg(any(test, feature = "test-support"))]
 4967    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 4968        self.display_map
 4969            .read(cx)
 4970            .current_inlays()
 4971            .cloned()
 4972            .collect()
 4973    }
 4974
 4975    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4976        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4977            return;
 4978        }
 4979
 4980        let reason_description = reason.description();
 4981        let ignore_debounce = matches!(
 4982            reason,
 4983            InlayHintRefreshReason::SettingsChange(_)
 4984                | InlayHintRefreshReason::Toggle(_)
 4985                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4986                | InlayHintRefreshReason::ModifiersChanged(_)
 4987        );
 4988        let (invalidate_cache, required_languages) = match reason {
 4989            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4990                match self.inlay_hint_cache.modifiers_override(enabled) {
 4991                    Some(enabled) => {
 4992                        if enabled {
 4993                            (InvalidationStrategy::RefreshRequested, None)
 4994                        } else {
 4995                            self.splice_inlays(
 4996                                &self
 4997                                    .visible_inlay_hints(cx)
 4998                                    .iter()
 4999                                    .map(|inlay| inlay.id)
 5000                                    .collect::<Vec<InlayId>>(),
 5001                                Vec::new(),
 5002                                cx,
 5003                            );
 5004                            return;
 5005                        }
 5006                    }
 5007                    None => return,
 5008                }
 5009            }
 5010            InlayHintRefreshReason::Toggle(enabled) => {
 5011                if self.inlay_hint_cache.toggle(enabled) {
 5012                    if enabled {
 5013                        (InvalidationStrategy::RefreshRequested, None)
 5014                    } else {
 5015                        self.splice_inlays(
 5016                            &self
 5017                                .visible_inlay_hints(cx)
 5018                                .iter()
 5019                                .map(|inlay| inlay.id)
 5020                                .collect::<Vec<InlayId>>(),
 5021                            Vec::new(),
 5022                            cx,
 5023                        );
 5024                        return;
 5025                    }
 5026                } else {
 5027                    return;
 5028                }
 5029            }
 5030            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5031                match self.inlay_hint_cache.update_settings(
 5032                    &self.buffer,
 5033                    new_settings,
 5034                    self.visible_inlay_hints(cx),
 5035                    cx,
 5036                ) {
 5037                    ControlFlow::Break(Some(InlaySplice {
 5038                        to_remove,
 5039                        to_insert,
 5040                    })) => {
 5041                        self.splice_inlays(&to_remove, to_insert, cx);
 5042                        return;
 5043                    }
 5044                    ControlFlow::Break(None) => return,
 5045                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5046                }
 5047            }
 5048            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5049                if let Some(InlaySplice {
 5050                    to_remove,
 5051                    to_insert,
 5052                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5053                {
 5054                    self.splice_inlays(&to_remove, to_insert, cx);
 5055                }
 5056                self.display_map.update(cx, |display_map, _| {
 5057                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5058                });
 5059                return;
 5060            }
 5061            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5062            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5063                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5064            }
 5065            InlayHintRefreshReason::RefreshRequested => {
 5066                (InvalidationStrategy::RefreshRequested, None)
 5067            }
 5068        };
 5069
 5070        if let Some(InlaySplice {
 5071            to_remove,
 5072            to_insert,
 5073        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5074            reason_description,
 5075            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 5076            invalidate_cache,
 5077            ignore_debounce,
 5078            cx,
 5079        ) {
 5080            self.splice_inlays(&to_remove, to_insert, cx);
 5081        }
 5082    }
 5083
 5084    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5085        self.display_map
 5086            .read(cx)
 5087            .current_inlays()
 5088            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5089            .cloned()
 5090            .collect()
 5091    }
 5092
 5093    pub fn excerpts_for_inlay_hints_query(
 5094        &self,
 5095        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5096        cx: &mut Context<Editor>,
 5097    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5098        let Some(project) = self.project.as_ref() else {
 5099            return HashMap::default();
 5100        };
 5101        let project = project.read(cx);
 5102        let multi_buffer = self.buffer().read(cx);
 5103        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5104        let multi_buffer_visible_start = self
 5105            .scroll_manager
 5106            .anchor()
 5107            .anchor
 5108            .to_point(&multi_buffer_snapshot);
 5109        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5110            multi_buffer_visible_start
 5111                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5112            Bias::Left,
 5113        );
 5114        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5115        multi_buffer_snapshot
 5116            .range_to_buffer_ranges(multi_buffer_visible_range)
 5117            .into_iter()
 5118            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5119            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5120                let buffer_file = project::File::from_dyn(buffer.file())?;
 5121                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5122                let worktree_entry = buffer_worktree
 5123                    .read(cx)
 5124                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5125                if worktree_entry.is_ignored {
 5126                    return None;
 5127                }
 5128
 5129                let language = buffer.language()?;
 5130                if let Some(restrict_to_languages) = restrict_to_languages {
 5131                    if !restrict_to_languages.contains(language) {
 5132                        return None;
 5133                    }
 5134                }
 5135                Some((
 5136                    excerpt_id,
 5137                    (
 5138                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5139                        buffer.version().clone(),
 5140                        excerpt_visible_range,
 5141                    ),
 5142                ))
 5143            })
 5144            .collect()
 5145    }
 5146
 5147    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5148        TextLayoutDetails {
 5149            text_system: window.text_system().clone(),
 5150            editor_style: self.style.clone().unwrap(),
 5151            rem_size: window.rem_size(),
 5152            scroll_anchor: self.scroll_manager.anchor(),
 5153            visible_rows: self.visible_line_count(),
 5154            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5155        }
 5156    }
 5157
 5158    pub fn splice_inlays(
 5159        &self,
 5160        to_remove: &[InlayId],
 5161        to_insert: Vec<Inlay>,
 5162        cx: &mut Context<Self>,
 5163    ) {
 5164        self.display_map.update(cx, |display_map, cx| {
 5165            display_map.splice_inlays(to_remove, to_insert, cx)
 5166        });
 5167        cx.notify();
 5168    }
 5169
 5170    fn trigger_on_type_formatting(
 5171        &self,
 5172        input: String,
 5173        window: &mut Window,
 5174        cx: &mut Context<Self>,
 5175    ) -> Option<Task<Result<()>>> {
 5176        if input.len() != 1 {
 5177            return None;
 5178        }
 5179
 5180        let project = self.project.as_ref()?;
 5181        let position = self.selections.newest_anchor().head();
 5182        let (buffer, buffer_position) = self
 5183            .buffer
 5184            .read(cx)
 5185            .text_anchor_for_position(position, cx)?;
 5186
 5187        let settings = language_settings::language_settings(
 5188            buffer
 5189                .read(cx)
 5190                .language_at(buffer_position)
 5191                .map(|l| l.name()),
 5192            buffer.read(cx).file(),
 5193            cx,
 5194        );
 5195        if !settings.use_on_type_format {
 5196            return None;
 5197        }
 5198
 5199        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5200        // hence we do LSP request & edit on host side only — add formats to host's history.
 5201        let push_to_lsp_host_history = true;
 5202        // If this is not the host, append its history with new edits.
 5203        let push_to_client_history = project.read(cx).is_via_collab();
 5204
 5205        let on_type_formatting = project.update(cx, |project, cx| {
 5206            project.on_type_format(
 5207                buffer.clone(),
 5208                buffer_position,
 5209                input,
 5210                push_to_lsp_host_history,
 5211                cx,
 5212            )
 5213        });
 5214        Some(cx.spawn_in(window, async move |editor, cx| {
 5215            if let Some(transaction) = on_type_formatting.await? {
 5216                if push_to_client_history {
 5217                    buffer
 5218                        .update(cx, |buffer, _| {
 5219                            buffer.push_transaction(transaction, Instant::now());
 5220                            buffer.finalize_last_transaction();
 5221                        })
 5222                        .ok();
 5223                }
 5224                editor.update(cx, |editor, cx| {
 5225                    editor.refresh_document_highlights(cx);
 5226                })?;
 5227            }
 5228            Ok(())
 5229        }))
 5230    }
 5231
 5232    pub fn show_word_completions(
 5233        &mut self,
 5234        _: &ShowWordCompletions,
 5235        window: &mut Window,
 5236        cx: &mut Context<Self>,
 5237    ) {
 5238        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5239    }
 5240
 5241    pub fn show_completions(
 5242        &mut self,
 5243        options: &ShowCompletions,
 5244        window: &mut Window,
 5245        cx: &mut Context<Self>,
 5246    ) {
 5247        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5248    }
 5249
 5250    fn open_or_update_completions_menu(
 5251        &mut self,
 5252        requested_source: Option<CompletionsMenuSource>,
 5253        trigger: Option<&str>,
 5254        window: &mut Window,
 5255        cx: &mut Context<Self>,
 5256    ) {
 5257        if self.pending_rename.is_some() {
 5258            return;
 5259        }
 5260
 5261        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5262
 5263        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5264        // inserted and selected. To handle that case, the start of the selection is used so that
 5265        // the menu starts with all choices.
 5266        let position = self
 5267            .selections
 5268            .newest_anchor()
 5269            .start
 5270            .bias_right(&multibuffer_snapshot);
 5271        if position.diff_base_anchor.is_some() {
 5272            return;
 5273        }
 5274        let (buffer, buffer_position) =
 5275            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5276                output
 5277            } else {
 5278                return;
 5279            };
 5280        let buffer_snapshot = buffer.read(cx).snapshot();
 5281
 5282        let query: Option<Arc<String>> =
 5283            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5284
 5285        drop(multibuffer_snapshot);
 5286
 5287        let provider = match requested_source {
 5288            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5289            Some(CompletionsMenuSource::Words) => None,
 5290            Some(CompletionsMenuSource::SnippetChoices) => {
 5291                log::error!("bug: SnippetChoices requested_source is not handled");
 5292                None
 5293            }
 5294        };
 5295
 5296        let sort_completions = provider
 5297            .as_ref()
 5298            .map_or(false, |provider| provider.sort_completions());
 5299
 5300        let filter_completions = provider
 5301            .as_ref()
 5302            .map_or(true, |provider| provider.filter_completions());
 5303
 5304        let trigger_kind = match trigger {
 5305            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5306                CompletionTriggerKind::TRIGGER_CHARACTER
 5307            }
 5308            _ => CompletionTriggerKind::INVOKED,
 5309        };
 5310        let completion_context = CompletionContext {
 5311            trigger_character: trigger.and_then(|trigger| {
 5312                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5313                    Some(String::from(trigger))
 5314                } else {
 5315                    None
 5316                }
 5317            }),
 5318            trigger_kind,
 5319        };
 5320
 5321        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5322        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5323        // involve trigger chars, so this is skipped in that case.
 5324        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5325        {
 5326            let menu_is_open = matches!(
 5327                self.context_menu.borrow().as_ref(),
 5328                Some(CodeContextMenu::Completions(_))
 5329            );
 5330            if menu_is_open {
 5331                self.hide_context_menu(window, cx);
 5332            }
 5333        }
 5334
 5335        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5336            if filter_completions {
 5337                menu.filter(query.clone(), provider.clone(), window, cx);
 5338            }
 5339            // When `is_incomplete` is false, no need to re-query completions when the current query
 5340            // is a suffix of the initial query.
 5341            if !menu.is_incomplete {
 5342                // If the new query is a suffix of the old query (typing more characters) and
 5343                // the previous result was complete, the existing completions can be filtered.
 5344                //
 5345                // Note that this is always true for snippet completions.
 5346                let query_matches = match (&menu.initial_query, &query) {
 5347                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5348                    (None, _) => true,
 5349                    _ => false,
 5350                };
 5351                if query_matches {
 5352                    let position_matches = if menu.initial_position == position {
 5353                        true
 5354                    } else {
 5355                        let snapshot = self.buffer.read(cx).read(cx);
 5356                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5357                    };
 5358                    if position_matches {
 5359                        return;
 5360                    }
 5361                }
 5362            }
 5363        };
 5364
 5365        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5366            buffer_snapshot.surrounding_word(buffer_position)
 5367        {
 5368            let word_to_exclude = buffer_snapshot
 5369                .text_for_range(word_range.clone())
 5370                .collect::<String>();
 5371            (
 5372                buffer_snapshot.anchor_before(word_range.start)
 5373                    ..buffer_snapshot.anchor_after(buffer_position),
 5374                Some(word_to_exclude),
 5375            )
 5376        } else {
 5377            (buffer_position..buffer_position, None)
 5378        };
 5379
 5380        let language = buffer_snapshot
 5381            .language_at(buffer_position)
 5382            .map(|language| language.name());
 5383
 5384        let completion_settings =
 5385            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5386
 5387        let show_completion_documentation = buffer_snapshot
 5388            .settings_at(buffer_position, cx)
 5389            .show_completion_documentation;
 5390
 5391        // The document can be large, so stay in reasonable bounds when searching for words,
 5392        // otherwise completion pop-up might be slow to appear.
 5393        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5394        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5395        let min_word_search = buffer_snapshot.clip_point(
 5396            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5397            Bias::Left,
 5398        );
 5399        let max_word_search = buffer_snapshot.clip_point(
 5400            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5401            Bias::Right,
 5402        );
 5403        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5404            ..buffer_snapshot.point_to_offset(max_word_search);
 5405
 5406        let skip_digits = query
 5407            .as_ref()
 5408            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5409
 5410        let (mut words, provider_responses) = match &provider {
 5411            Some(provider) => {
 5412                let provider_responses = provider.completions(
 5413                    position.excerpt_id,
 5414                    &buffer,
 5415                    buffer_position,
 5416                    completion_context,
 5417                    window,
 5418                    cx,
 5419                );
 5420
 5421                let words = match completion_settings.words {
 5422                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5423                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5424                        .background_spawn(async move {
 5425                            buffer_snapshot.words_in_range(WordsQuery {
 5426                                fuzzy_contents: None,
 5427                                range: word_search_range,
 5428                                skip_digits,
 5429                            })
 5430                        }),
 5431                };
 5432
 5433                (words, provider_responses)
 5434            }
 5435            None => (
 5436                cx.background_spawn(async move {
 5437                    buffer_snapshot.words_in_range(WordsQuery {
 5438                        fuzzy_contents: None,
 5439                        range: word_search_range,
 5440                        skip_digits,
 5441                    })
 5442                }),
 5443                Task::ready(Ok(Vec::new())),
 5444            ),
 5445        };
 5446
 5447        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5448
 5449        let id = post_inc(&mut self.next_completion_id);
 5450        let task = cx.spawn_in(window, async move |editor, cx| {
 5451            let Ok(()) = editor.update(cx, |this, _| {
 5452                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5453            }) else {
 5454                return;
 5455            };
 5456
 5457            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5458            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5459            let mut completions = Vec::new();
 5460            let mut is_incomplete = false;
 5461            if let Some(provider_responses) = provider_responses.await.log_err() {
 5462                if !provider_responses.is_empty() {
 5463                    for response in provider_responses {
 5464                        completions.extend(response.completions);
 5465                        is_incomplete = is_incomplete || response.is_incomplete;
 5466                    }
 5467                    if completion_settings.words == WordsCompletionMode::Fallback {
 5468                        words = Task::ready(BTreeMap::default());
 5469                    }
 5470                }
 5471            }
 5472
 5473            let mut words = words.await;
 5474            if let Some(word_to_exclude) = &word_to_exclude {
 5475                words.remove(word_to_exclude);
 5476            }
 5477            for lsp_completion in &completions {
 5478                words.remove(&lsp_completion.new_text);
 5479            }
 5480            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5481                replace_range: word_replace_range.clone(),
 5482                new_text: word.clone(),
 5483                label: CodeLabel::plain(word, None),
 5484                icon_path: None,
 5485                documentation: None,
 5486                source: CompletionSource::BufferWord {
 5487                    word_range,
 5488                    resolved: false,
 5489                },
 5490                insert_text_mode: Some(InsertTextMode::AS_IS),
 5491                confirm: None,
 5492            }));
 5493
 5494            let menu = if completions.is_empty() {
 5495                None
 5496            } else {
 5497                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5498                    let languages = editor
 5499                        .workspace
 5500                        .as_ref()
 5501                        .and_then(|(workspace, _)| workspace.upgrade())
 5502                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5503                    let menu = CompletionsMenu::new(
 5504                        id,
 5505                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5506                        sort_completions,
 5507                        show_completion_documentation,
 5508                        position,
 5509                        query.clone(),
 5510                        is_incomplete,
 5511                        buffer.clone(),
 5512                        completions.into(),
 5513                        snippet_sort_order,
 5514                        languages,
 5515                        language,
 5516                        cx,
 5517                    );
 5518
 5519                    let query = if filter_completions { query } else { None };
 5520                    let matches_task = if let Some(query) = query {
 5521                        menu.do_async_filtering(query, cx)
 5522                    } else {
 5523                        Task::ready(menu.unfiltered_matches())
 5524                    };
 5525                    (menu, matches_task)
 5526                }) else {
 5527                    return;
 5528                };
 5529
 5530                let matches = matches_task.await;
 5531
 5532                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5533                    // Newer menu already set, so exit.
 5534                    match editor.context_menu.borrow().as_ref() {
 5535                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5536                            if prev_menu.id > id {
 5537                                return;
 5538                            }
 5539                        }
 5540                        _ => {}
 5541                    };
 5542
 5543                    // Only valid to take prev_menu because it the new menu is immediately set
 5544                    // below, or the menu is hidden.
 5545                    match editor.context_menu.borrow_mut().take() {
 5546                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5547                            let position_matches =
 5548                                if prev_menu.initial_position == menu.initial_position {
 5549                                    true
 5550                                } else {
 5551                                    let snapshot = editor.buffer.read(cx).read(cx);
 5552                                    prev_menu.initial_position.to_offset(&snapshot)
 5553                                        == menu.initial_position.to_offset(&snapshot)
 5554                                };
 5555                            if position_matches {
 5556                                // Preserve markdown cache before `set_filter_results` because it will
 5557                                // try to populate the documentation cache.
 5558                                menu.preserve_markdown_cache(prev_menu);
 5559                            }
 5560                        }
 5561                        _ => {}
 5562                    };
 5563
 5564                    menu.set_filter_results(matches, provider, window, cx);
 5565                }) else {
 5566                    return;
 5567                };
 5568
 5569                menu.visible().then_some(menu)
 5570            };
 5571
 5572            editor
 5573                .update_in(cx, |editor, window, cx| {
 5574                    if editor.focus_handle.is_focused(window) {
 5575                        if let Some(menu) = menu {
 5576                            *editor.context_menu.borrow_mut() =
 5577                                Some(CodeContextMenu::Completions(menu));
 5578
 5579                            crate::hover_popover::hide_hover(editor, cx);
 5580                            if editor.show_edit_predictions_in_menu() {
 5581                                editor.update_visible_inline_completion(window, cx);
 5582                            } else {
 5583                                editor.discard_inline_completion(false, cx);
 5584                            }
 5585
 5586                            cx.notify();
 5587                            return;
 5588                        }
 5589                    }
 5590
 5591                    if editor.completion_tasks.len() <= 1 {
 5592                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5593                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5594                        // If it was already hidden and we don't show inline completions in the menu, we should
 5595                        // also show the inline-completion when available.
 5596                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5597                            editor.update_visible_inline_completion(window, cx);
 5598                        }
 5599                    }
 5600                })
 5601                .ok();
 5602        });
 5603
 5604        self.completion_tasks.push((id, task));
 5605    }
 5606
 5607    #[cfg(feature = "test-support")]
 5608    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5609        let menu = self.context_menu.borrow();
 5610        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5611            let completions = menu.completions.borrow();
 5612            Some(completions.to_vec())
 5613        } else {
 5614            None
 5615        }
 5616    }
 5617
 5618    pub fn with_completions_menu_matching_id<R>(
 5619        &self,
 5620        id: CompletionId,
 5621        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5622    ) -> R {
 5623        let mut context_menu = self.context_menu.borrow_mut();
 5624        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5625            return f(None);
 5626        };
 5627        if completions_menu.id != id {
 5628            return f(None);
 5629        }
 5630        f(Some(completions_menu))
 5631    }
 5632
 5633    pub fn confirm_completion(
 5634        &mut self,
 5635        action: &ConfirmCompletion,
 5636        window: &mut Window,
 5637        cx: &mut Context<Self>,
 5638    ) -> Option<Task<Result<()>>> {
 5639        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5640        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5641    }
 5642
 5643    pub fn confirm_completion_insert(
 5644        &mut self,
 5645        _: &ConfirmCompletionInsert,
 5646        window: &mut Window,
 5647        cx: &mut Context<Self>,
 5648    ) -> Option<Task<Result<()>>> {
 5649        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5650        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5651    }
 5652
 5653    pub fn confirm_completion_replace(
 5654        &mut self,
 5655        _: &ConfirmCompletionReplace,
 5656        window: &mut Window,
 5657        cx: &mut Context<Self>,
 5658    ) -> Option<Task<Result<()>>> {
 5659        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5660        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5661    }
 5662
 5663    pub fn compose_completion(
 5664        &mut self,
 5665        action: &ComposeCompletion,
 5666        window: &mut Window,
 5667        cx: &mut Context<Self>,
 5668    ) -> Option<Task<Result<()>>> {
 5669        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5670        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5671    }
 5672
 5673    fn do_completion(
 5674        &mut self,
 5675        item_ix: Option<usize>,
 5676        intent: CompletionIntent,
 5677        window: &mut Window,
 5678        cx: &mut Context<Editor>,
 5679    ) -> Option<Task<Result<()>>> {
 5680        use language::ToOffset as _;
 5681
 5682        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5683        else {
 5684            return None;
 5685        };
 5686
 5687        let candidate_id = {
 5688            let entries = completions_menu.entries.borrow();
 5689            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5690            if self.show_edit_predictions_in_menu() {
 5691                self.discard_inline_completion(true, cx);
 5692            }
 5693            mat.candidate_id
 5694        };
 5695
 5696        let completion = completions_menu
 5697            .completions
 5698            .borrow()
 5699            .get(candidate_id)?
 5700            .clone();
 5701        cx.stop_propagation();
 5702
 5703        let buffer_handle = completions_menu.buffer.clone();
 5704
 5705        let CompletionEdit {
 5706            new_text,
 5707            snippet,
 5708            replace_range,
 5709        } = process_completion_for_edit(
 5710            &completion,
 5711            intent,
 5712            &buffer_handle,
 5713            &completions_menu.initial_position.text_anchor,
 5714            cx,
 5715        );
 5716
 5717        let buffer = buffer_handle.read(cx);
 5718        let snapshot = self.buffer.read(cx).snapshot(cx);
 5719        let newest_anchor = self.selections.newest_anchor();
 5720        let replace_range_multibuffer = {
 5721            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5722            let multibuffer_anchor = snapshot
 5723                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5724                .unwrap()
 5725                ..snapshot
 5726                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5727                    .unwrap();
 5728            multibuffer_anchor.start.to_offset(&snapshot)
 5729                ..multibuffer_anchor.end.to_offset(&snapshot)
 5730        };
 5731        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5732            return None;
 5733        }
 5734
 5735        let old_text = buffer
 5736            .text_for_range(replace_range.clone())
 5737            .collect::<String>();
 5738        let lookbehind = newest_anchor
 5739            .start
 5740            .text_anchor
 5741            .to_offset(buffer)
 5742            .saturating_sub(replace_range.start);
 5743        let lookahead = replace_range
 5744            .end
 5745            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5746        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5747        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5748
 5749        let selections = self.selections.all::<usize>(cx);
 5750        let mut ranges = Vec::new();
 5751        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5752
 5753        for selection in &selections {
 5754            let range = if selection.id == newest_anchor.id {
 5755                replace_range_multibuffer.clone()
 5756            } else {
 5757                let mut range = selection.range();
 5758
 5759                // if prefix is present, don't duplicate it
 5760                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5761                    range.start = range.start.saturating_sub(lookbehind);
 5762
 5763                    // if suffix is also present, mimic the newest cursor and replace it
 5764                    if selection.id != newest_anchor.id
 5765                        && snapshot.contains_str_at(range.end, suffix)
 5766                    {
 5767                        range.end += lookahead;
 5768                    }
 5769                }
 5770                range
 5771            };
 5772
 5773            ranges.push(range.clone());
 5774
 5775            if !self.linked_edit_ranges.is_empty() {
 5776                let start_anchor = snapshot.anchor_before(range.start);
 5777                let end_anchor = snapshot.anchor_after(range.end);
 5778                if let Some(ranges) = self
 5779                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5780                {
 5781                    for (buffer, edits) in ranges {
 5782                        linked_edits
 5783                            .entry(buffer.clone())
 5784                            .or_default()
 5785                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5786                    }
 5787                }
 5788            }
 5789        }
 5790
 5791        let common_prefix_len = old_text
 5792            .chars()
 5793            .zip(new_text.chars())
 5794            .take_while(|(a, b)| a == b)
 5795            .map(|(a, _)| a.len_utf8())
 5796            .sum::<usize>();
 5797
 5798        cx.emit(EditorEvent::InputHandled {
 5799            utf16_range_to_replace: None,
 5800            text: new_text[common_prefix_len..].into(),
 5801        });
 5802
 5803        self.transact(window, cx, |this, window, cx| {
 5804            if let Some(mut snippet) = snippet {
 5805                snippet.text = new_text.to_string();
 5806                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5807            } else {
 5808                this.buffer.update(cx, |buffer, cx| {
 5809                    let auto_indent = match completion.insert_text_mode {
 5810                        Some(InsertTextMode::AS_IS) => None,
 5811                        _ => this.autoindent_mode.clone(),
 5812                    };
 5813                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5814                    buffer.edit(edits, auto_indent, cx);
 5815                });
 5816            }
 5817            for (buffer, edits) in linked_edits {
 5818                buffer.update(cx, |buffer, cx| {
 5819                    let snapshot = buffer.snapshot();
 5820                    let edits = edits
 5821                        .into_iter()
 5822                        .map(|(range, text)| {
 5823                            use text::ToPoint as TP;
 5824                            let end_point = TP::to_point(&range.end, &snapshot);
 5825                            let start_point = TP::to_point(&range.start, &snapshot);
 5826                            (start_point..end_point, text)
 5827                        })
 5828                        .sorted_by_key(|(range, _)| range.start);
 5829                    buffer.edit(edits, None, cx);
 5830                })
 5831            }
 5832
 5833            this.refresh_inline_completion(true, false, window, cx);
 5834        });
 5835
 5836        let show_new_completions_on_confirm = completion
 5837            .confirm
 5838            .as_ref()
 5839            .map_or(false, |confirm| confirm(intent, window, cx));
 5840        if show_new_completions_on_confirm {
 5841            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5842        }
 5843
 5844        let provider = self.completion_provider.as_ref()?;
 5845        drop(completion);
 5846        let apply_edits = provider.apply_additional_edits_for_completion(
 5847            buffer_handle,
 5848            completions_menu.completions.clone(),
 5849            candidate_id,
 5850            true,
 5851            cx,
 5852        );
 5853
 5854        let editor_settings = EditorSettings::get_global(cx);
 5855        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5856            // After the code completion is finished, users often want to know what signatures are needed.
 5857            // so we should automatically call signature_help
 5858            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5859        }
 5860
 5861        Some(cx.foreground_executor().spawn(async move {
 5862            apply_edits.await?;
 5863            Ok(())
 5864        }))
 5865    }
 5866
 5867    pub fn toggle_code_actions(
 5868        &mut self,
 5869        action: &ToggleCodeActions,
 5870        window: &mut Window,
 5871        cx: &mut Context<Self>,
 5872    ) {
 5873        let quick_launch = action.quick_launch;
 5874        let mut context_menu = self.context_menu.borrow_mut();
 5875        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5876            if code_actions.deployed_from == action.deployed_from {
 5877                // Toggle if we're selecting the same one
 5878                *context_menu = None;
 5879                cx.notify();
 5880                return;
 5881            } else {
 5882                // Otherwise, clear it and start a new one
 5883                *context_menu = None;
 5884                cx.notify();
 5885            }
 5886        }
 5887        drop(context_menu);
 5888        let snapshot = self.snapshot(window, cx);
 5889        let deployed_from = action.deployed_from.clone();
 5890        let action = action.clone();
 5891        self.completion_tasks.clear();
 5892        self.discard_inline_completion(false, cx);
 5893
 5894        let multibuffer_point = match &action.deployed_from {
 5895            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5896                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5897            }
 5898            _ => self.selections.newest::<Point>(cx).head(),
 5899        };
 5900        let Some((buffer, buffer_row)) = snapshot
 5901            .buffer_snapshot
 5902            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5903            .and_then(|(buffer_snapshot, range)| {
 5904                self.buffer()
 5905                    .read(cx)
 5906                    .buffer(buffer_snapshot.remote_id())
 5907                    .map(|buffer| (buffer, range.start.row))
 5908            })
 5909        else {
 5910            return;
 5911        };
 5912        let buffer_id = buffer.read(cx).remote_id();
 5913        let tasks = self
 5914            .tasks
 5915            .get(&(buffer_id, buffer_row))
 5916            .map(|t| Arc::new(t.to_owned()));
 5917
 5918        if !self.focus_handle.is_focused(window) {
 5919            return;
 5920        }
 5921        let project = self.project.clone();
 5922
 5923        let code_actions_task = match deployed_from {
 5924            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 5925            _ => self.code_actions(buffer_row, window, cx),
 5926        };
 5927
 5928        let runnable_task = match deployed_from {
 5929            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 5930            _ => {
 5931                let mut task_context_task = Task::ready(None);
 5932                if let Some(tasks) = &tasks {
 5933                    if let Some(project) = project {
 5934                        task_context_task =
 5935                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 5936                    }
 5937                }
 5938
 5939                cx.spawn_in(window, {
 5940                    let buffer = buffer.clone();
 5941                    async move |editor, cx| {
 5942                        let task_context = task_context_task.await;
 5943
 5944                        let resolved_tasks =
 5945                            tasks
 5946                                .zip(task_context.clone())
 5947                                .map(|(tasks, task_context)| ResolvedTasks {
 5948                                    templates: tasks.resolve(&task_context).collect(),
 5949                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5950                                        multibuffer_point.row,
 5951                                        tasks.column,
 5952                                    )),
 5953                                });
 5954                        let debug_scenarios = editor
 5955                            .update(cx, |editor, cx| {
 5956                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 5957                            })?
 5958                            .await;
 5959                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 5960                    }
 5961                })
 5962            }
 5963        };
 5964
 5965        cx.spawn_in(window, async move |editor, cx| {
 5966            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 5967            let code_actions = code_actions_task.await;
 5968            let spawn_straight_away = quick_launch
 5969                && resolved_tasks
 5970                    .as_ref()
 5971                    .map_or(false, |tasks| tasks.templates.len() == 1)
 5972                && code_actions
 5973                    .as_ref()
 5974                    .map_or(true, |actions| actions.is_empty())
 5975                && debug_scenarios.is_empty();
 5976
 5977            editor.update_in(cx, |editor, window, cx| {
 5978                crate::hover_popover::hide_hover(editor, cx);
 5979                *editor.context_menu.borrow_mut() =
 5980                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5981                        buffer,
 5982                        actions: CodeActionContents::new(
 5983                            resolved_tasks,
 5984                            code_actions,
 5985                            debug_scenarios,
 5986                            task_context.unwrap_or_default(),
 5987                        ),
 5988                        selected_item: Default::default(),
 5989                        scroll_handle: UniformListScrollHandle::default(),
 5990                        deployed_from,
 5991                    }));
 5992                cx.notify();
 5993                if spawn_straight_away {
 5994                    if let Some(task) = editor.confirm_code_action(
 5995                        &ConfirmCodeAction { item_ix: Some(0) },
 5996                        window,
 5997                        cx,
 5998                    ) {
 5999                        return task;
 6000                    }
 6001                }
 6002
 6003                Task::ready(Ok(()))
 6004            })
 6005        })
 6006        .detach_and_log_err(cx);
 6007    }
 6008
 6009    fn debug_scenarios(
 6010        &mut self,
 6011        resolved_tasks: &Option<ResolvedTasks>,
 6012        buffer: &Entity<Buffer>,
 6013        cx: &mut App,
 6014    ) -> Task<Vec<task::DebugScenario>> {
 6015        maybe!({
 6016            let project = self.project.as_ref()?;
 6017            let dap_store = project.read(cx).dap_store();
 6018            let mut scenarios = vec![];
 6019            let resolved_tasks = resolved_tasks.as_ref()?;
 6020            let buffer = buffer.read(cx);
 6021            let language = buffer.language()?;
 6022            let file = buffer.file();
 6023            let debug_adapter = language_settings(language.name().into(), file, cx)
 6024                .debuggers
 6025                .first()
 6026                .map(SharedString::from)
 6027                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6028
 6029            dap_store.update(cx, |dap_store, cx| {
 6030                for (_, task) in &resolved_tasks.templates {
 6031                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6032                        task.original_task().clone(),
 6033                        debug_adapter.clone().into(),
 6034                        task.display_label().to_owned().into(),
 6035                        cx,
 6036                    );
 6037                    scenarios.push(maybe_scenario);
 6038                }
 6039            });
 6040            Some(cx.background_spawn(async move {
 6041                let scenarios = futures::future::join_all(scenarios)
 6042                    .await
 6043                    .into_iter()
 6044                    .flatten()
 6045                    .collect::<Vec<_>>();
 6046                scenarios
 6047            }))
 6048        })
 6049        .unwrap_or_else(|| Task::ready(vec![]))
 6050    }
 6051
 6052    fn code_actions(
 6053        &mut self,
 6054        buffer_row: u32,
 6055        window: &mut Window,
 6056        cx: &mut Context<Self>,
 6057    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6058        let mut task = self.code_actions_task.take();
 6059        cx.spawn_in(window, async move |editor, cx| {
 6060            while let Some(prev_task) = task {
 6061                prev_task.await.log_err();
 6062                task = editor
 6063                    .update(cx, |this, _| this.code_actions_task.take())
 6064                    .ok()?;
 6065            }
 6066
 6067            editor
 6068                .update(cx, |editor, cx| {
 6069                    editor
 6070                        .available_code_actions
 6071                        .clone()
 6072                        .and_then(|(location, code_actions)| {
 6073                            let snapshot = location.buffer.read(cx).snapshot();
 6074                            let point_range = location.range.to_point(&snapshot);
 6075                            let point_range = point_range.start.row..=point_range.end.row;
 6076                            if point_range.contains(&buffer_row) {
 6077                                Some(code_actions)
 6078                            } else {
 6079                                None
 6080                            }
 6081                        })
 6082                })
 6083                .ok()
 6084                .flatten()
 6085        })
 6086    }
 6087
 6088    pub fn confirm_code_action(
 6089        &mut self,
 6090        action: &ConfirmCodeAction,
 6091        window: &mut Window,
 6092        cx: &mut Context<Self>,
 6093    ) -> Option<Task<Result<()>>> {
 6094        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6095
 6096        let actions_menu =
 6097            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6098                menu
 6099            } else {
 6100                return None;
 6101            };
 6102
 6103        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6104        let action = actions_menu.actions.get(action_ix)?;
 6105        let title = action.label();
 6106        let buffer = actions_menu.buffer;
 6107        let workspace = self.workspace()?;
 6108
 6109        match action {
 6110            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6111                workspace.update(cx, |workspace, cx| {
 6112                    workspace.schedule_resolved_task(
 6113                        task_source_kind,
 6114                        resolved_task,
 6115                        false,
 6116                        window,
 6117                        cx,
 6118                    );
 6119
 6120                    Some(Task::ready(Ok(())))
 6121                })
 6122            }
 6123            CodeActionsItem::CodeAction {
 6124                excerpt_id,
 6125                action,
 6126                provider,
 6127            } => {
 6128                let apply_code_action =
 6129                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6130                let workspace = workspace.downgrade();
 6131                Some(cx.spawn_in(window, async move |editor, cx| {
 6132                    let project_transaction = apply_code_action.await?;
 6133                    Self::open_project_transaction(
 6134                        &editor,
 6135                        workspace,
 6136                        project_transaction,
 6137                        title,
 6138                        cx,
 6139                    )
 6140                    .await
 6141                }))
 6142            }
 6143            CodeActionsItem::DebugScenario(scenario) => {
 6144                let context = actions_menu.actions.context.clone();
 6145
 6146                workspace.update(cx, |workspace, cx| {
 6147                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6148                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 6149                });
 6150                Some(Task::ready(Ok(())))
 6151            }
 6152        }
 6153    }
 6154
 6155    pub async fn open_project_transaction(
 6156        this: &WeakEntity<Editor>,
 6157        workspace: WeakEntity<Workspace>,
 6158        transaction: ProjectTransaction,
 6159        title: String,
 6160        cx: &mut AsyncWindowContext,
 6161    ) -> Result<()> {
 6162        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6163        cx.update(|_, cx| {
 6164            entries.sort_unstable_by_key(|(buffer, _)| {
 6165                buffer.read(cx).file().map(|f| f.path().clone())
 6166            });
 6167        })?;
 6168
 6169        // If the project transaction's edits are all contained within this editor, then
 6170        // avoid opening a new editor to display them.
 6171
 6172        if let Some((buffer, transaction)) = entries.first() {
 6173            if entries.len() == 1 {
 6174                let excerpt = this.update(cx, |editor, cx| {
 6175                    editor
 6176                        .buffer()
 6177                        .read(cx)
 6178                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6179                })?;
 6180                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6181                    if excerpted_buffer == *buffer {
 6182                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6183                            let excerpt_range = excerpt_range.to_offset(buffer);
 6184                            buffer
 6185                                .edited_ranges_for_transaction::<usize>(transaction)
 6186                                .all(|range| {
 6187                                    excerpt_range.start <= range.start
 6188                                        && excerpt_range.end >= range.end
 6189                                })
 6190                        })?;
 6191
 6192                        if all_edits_within_excerpt {
 6193                            return Ok(());
 6194                        }
 6195                    }
 6196                }
 6197            }
 6198        } else {
 6199            return Ok(());
 6200        }
 6201
 6202        let mut ranges_to_highlight = Vec::new();
 6203        let excerpt_buffer = cx.new(|cx| {
 6204            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6205            for (buffer_handle, transaction) in &entries {
 6206                let edited_ranges = buffer_handle
 6207                    .read(cx)
 6208                    .edited_ranges_for_transaction::<Point>(transaction)
 6209                    .collect::<Vec<_>>();
 6210                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6211                    PathKey::for_buffer(buffer_handle, cx),
 6212                    buffer_handle.clone(),
 6213                    edited_ranges,
 6214                    DEFAULT_MULTIBUFFER_CONTEXT,
 6215                    cx,
 6216                );
 6217
 6218                ranges_to_highlight.extend(ranges);
 6219            }
 6220            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6221            multibuffer
 6222        })?;
 6223
 6224        workspace.update_in(cx, |workspace, window, cx| {
 6225            let project = workspace.project().clone();
 6226            let editor =
 6227                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6228            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6229            editor.update(cx, |editor, cx| {
 6230                editor.highlight_background::<Self>(
 6231                    &ranges_to_highlight,
 6232                    |theme| theme.colors().editor_highlighted_line_background,
 6233                    cx,
 6234                );
 6235            });
 6236        })?;
 6237
 6238        Ok(())
 6239    }
 6240
 6241    pub fn clear_code_action_providers(&mut self) {
 6242        self.code_action_providers.clear();
 6243        self.available_code_actions.take();
 6244    }
 6245
 6246    pub fn add_code_action_provider(
 6247        &mut self,
 6248        provider: Rc<dyn CodeActionProvider>,
 6249        window: &mut Window,
 6250        cx: &mut Context<Self>,
 6251    ) {
 6252        if self
 6253            .code_action_providers
 6254            .iter()
 6255            .any(|existing_provider| existing_provider.id() == provider.id())
 6256        {
 6257            return;
 6258        }
 6259
 6260        self.code_action_providers.push(provider);
 6261        self.refresh_code_actions(window, cx);
 6262    }
 6263
 6264    pub fn remove_code_action_provider(
 6265        &mut self,
 6266        id: Arc<str>,
 6267        window: &mut Window,
 6268        cx: &mut Context<Self>,
 6269    ) {
 6270        self.code_action_providers
 6271            .retain(|provider| provider.id() != id);
 6272        self.refresh_code_actions(window, cx);
 6273    }
 6274
 6275    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6276        !self.code_action_providers.is_empty()
 6277            && EditorSettings::get_global(cx).toolbar.code_actions
 6278    }
 6279
 6280    pub fn has_available_code_actions(&self) -> bool {
 6281        self.available_code_actions
 6282            .as_ref()
 6283            .is_some_and(|(_, actions)| !actions.is_empty())
 6284    }
 6285
 6286    fn render_inline_code_actions(
 6287        &self,
 6288        icon_size: ui::IconSize,
 6289        display_row: DisplayRow,
 6290        is_active: bool,
 6291        cx: &mut Context<Self>,
 6292    ) -> AnyElement {
 6293        let show_tooltip = !self.context_menu_visible();
 6294        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6295            .icon_size(icon_size)
 6296            .shape(ui::IconButtonShape::Square)
 6297            .style(ButtonStyle::Transparent)
 6298            .icon_color(ui::Color::Hidden)
 6299            .toggle_state(is_active)
 6300            .when(show_tooltip, |this| {
 6301                this.tooltip({
 6302                    let focus_handle = self.focus_handle.clone();
 6303                    move |window, cx| {
 6304                        Tooltip::for_action_in(
 6305                            "Toggle Code Actions",
 6306                            &ToggleCodeActions {
 6307                                deployed_from: None,
 6308                                quick_launch: false,
 6309                            },
 6310                            &focus_handle,
 6311                            window,
 6312                            cx,
 6313                        )
 6314                    }
 6315                })
 6316            })
 6317            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6318                window.focus(&editor.focus_handle(cx));
 6319                editor.toggle_code_actions(
 6320                    &crate::actions::ToggleCodeActions {
 6321                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6322                            display_row,
 6323                        )),
 6324                        quick_launch: false,
 6325                    },
 6326                    window,
 6327                    cx,
 6328                );
 6329            }))
 6330            .into_any_element()
 6331    }
 6332
 6333    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6334        &self.context_menu
 6335    }
 6336
 6337    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6338        let newest_selection = self.selections.newest_anchor().clone();
 6339        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6340        let buffer = self.buffer.read(cx);
 6341        if newest_selection.head().diff_base_anchor.is_some() {
 6342            return None;
 6343        }
 6344        let (start_buffer, start) =
 6345            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6346        let (end_buffer, end) =
 6347            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6348        if start_buffer != end_buffer {
 6349            return None;
 6350        }
 6351
 6352        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6353            cx.background_executor()
 6354                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6355                .await;
 6356
 6357            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6358                let providers = this.code_action_providers.clone();
 6359                let tasks = this
 6360                    .code_action_providers
 6361                    .iter()
 6362                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6363                    .collect::<Vec<_>>();
 6364                (providers, tasks)
 6365            })?;
 6366
 6367            let mut actions = Vec::new();
 6368            for (provider, provider_actions) in
 6369                providers.into_iter().zip(future::join_all(tasks).await)
 6370            {
 6371                if let Some(provider_actions) = provider_actions.log_err() {
 6372                    actions.extend(provider_actions.into_iter().map(|action| {
 6373                        AvailableCodeAction {
 6374                            excerpt_id: newest_selection.start.excerpt_id,
 6375                            action,
 6376                            provider: provider.clone(),
 6377                        }
 6378                    }));
 6379                }
 6380            }
 6381
 6382            this.update(cx, |this, cx| {
 6383                this.available_code_actions = if actions.is_empty() {
 6384                    None
 6385                } else {
 6386                    Some((
 6387                        Location {
 6388                            buffer: start_buffer,
 6389                            range: start..end,
 6390                        },
 6391                        actions.into(),
 6392                    ))
 6393                };
 6394                cx.notify();
 6395            })
 6396        }));
 6397        None
 6398    }
 6399
 6400    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6401        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6402            self.show_git_blame_inline = false;
 6403
 6404            self.show_git_blame_inline_delay_task =
 6405                Some(cx.spawn_in(window, async move |this, cx| {
 6406                    cx.background_executor().timer(delay).await;
 6407
 6408                    this.update(cx, |this, cx| {
 6409                        this.show_git_blame_inline = true;
 6410                        cx.notify();
 6411                    })
 6412                    .log_err();
 6413                }));
 6414        }
 6415    }
 6416
 6417    fn show_blame_popover(
 6418        &mut self,
 6419        blame_entry: &BlameEntry,
 6420        position: gpui::Point<Pixels>,
 6421        cx: &mut Context<Self>,
 6422    ) {
 6423        if let Some(state) = &mut self.inline_blame_popover {
 6424            state.hide_task.take();
 6425        } else {
 6426            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6427            let blame_entry = blame_entry.clone();
 6428            let show_task = cx.spawn(async move |editor, cx| {
 6429                cx.background_executor()
 6430                    .timer(std::time::Duration::from_millis(delay))
 6431                    .await;
 6432                editor
 6433                    .update(cx, |editor, cx| {
 6434                        editor.inline_blame_popover_show_task.take();
 6435                        let Some(blame) = editor.blame.as_ref() else {
 6436                            return;
 6437                        };
 6438                        let blame = blame.read(cx);
 6439                        let details = blame.details_for_entry(&blame_entry);
 6440                        let markdown = cx.new(|cx| {
 6441                            Markdown::new(
 6442                                details
 6443                                    .as_ref()
 6444                                    .map(|message| message.message.clone())
 6445                                    .unwrap_or_default(),
 6446                                None,
 6447                                None,
 6448                                cx,
 6449                            )
 6450                        });
 6451                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6452                            position,
 6453                            hide_task: None,
 6454                            popover_bounds: None,
 6455                            popover_state: InlineBlamePopoverState {
 6456                                scroll_handle: ScrollHandle::new(),
 6457                                commit_message: details,
 6458                                markdown,
 6459                            },
 6460                        });
 6461                        cx.notify();
 6462                    })
 6463                    .ok();
 6464            });
 6465            self.inline_blame_popover_show_task = Some(show_task);
 6466        }
 6467    }
 6468
 6469    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6470        self.inline_blame_popover_show_task.take();
 6471        if let Some(state) = &mut self.inline_blame_popover {
 6472            let hide_task = cx.spawn(async move |editor, cx| {
 6473                cx.background_executor()
 6474                    .timer(std::time::Duration::from_millis(100))
 6475                    .await;
 6476                editor
 6477                    .update(cx, |editor, cx| {
 6478                        editor.inline_blame_popover.take();
 6479                        cx.notify();
 6480                    })
 6481                    .ok();
 6482            });
 6483            state.hide_task = Some(hide_task);
 6484        }
 6485    }
 6486
 6487    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6488        if self.pending_rename.is_some() {
 6489            return None;
 6490        }
 6491
 6492        let provider = self.semantics_provider.clone()?;
 6493        let buffer = self.buffer.read(cx);
 6494        let newest_selection = self.selections.newest_anchor().clone();
 6495        let cursor_position = newest_selection.head();
 6496        let (cursor_buffer, cursor_buffer_position) =
 6497            buffer.text_anchor_for_position(cursor_position, cx)?;
 6498        let (tail_buffer, tail_buffer_position) =
 6499            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6500        if cursor_buffer != tail_buffer {
 6501            return None;
 6502        }
 6503
 6504        let snapshot = cursor_buffer.read(cx).snapshot();
 6505        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6506        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6507        if start_word_range != end_word_range {
 6508            self.document_highlights_task.take();
 6509            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6510            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6511            return None;
 6512        }
 6513
 6514        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6515        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6516            cx.background_executor()
 6517                .timer(Duration::from_millis(debounce))
 6518                .await;
 6519
 6520            let highlights = if let Some(highlights) = cx
 6521                .update(|cx| {
 6522                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6523                })
 6524                .ok()
 6525                .flatten()
 6526            {
 6527                highlights.await.log_err()
 6528            } else {
 6529                None
 6530            };
 6531
 6532            if let Some(highlights) = highlights {
 6533                this.update(cx, |this, cx| {
 6534                    if this.pending_rename.is_some() {
 6535                        return;
 6536                    }
 6537
 6538                    let buffer_id = cursor_position.buffer_id;
 6539                    let buffer = this.buffer.read(cx);
 6540                    if !buffer
 6541                        .text_anchor_for_position(cursor_position, cx)
 6542                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6543                    {
 6544                        return;
 6545                    }
 6546
 6547                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6548                    let mut write_ranges = Vec::new();
 6549                    let mut read_ranges = Vec::new();
 6550                    for highlight in highlights {
 6551                        for (excerpt_id, excerpt_range) in
 6552                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6553                        {
 6554                            let start = highlight
 6555                                .range
 6556                                .start
 6557                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6558                            let end = highlight
 6559                                .range
 6560                                .end
 6561                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6562                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6563                                continue;
 6564                            }
 6565
 6566                            let range = Anchor {
 6567                                buffer_id,
 6568                                excerpt_id,
 6569                                text_anchor: start,
 6570                                diff_base_anchor: None,
 6571                            }..Anchor {
 6572                                buffer_id,
 6573                                excerpt_id,
 6574                                text_anchor: end,
 6575                                diff_base_anchor: None,
 6576                            };
 6577                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6578                                write_ranges.push(range);
 6579                            } else {
 6580                                read_ranges.push(range);
 6581                            }
 6582                        }
 6583                    }
 6584
 6585                    this.highlight_background::<DocumentHighlightRead>(
 6586                        &read_ranges,
 6587                        |theme| theme.colors().editor_document_highlight_read_background,
 6588                        cx,
 6589                    );
 6590                    this.highlight_background::<DocumentHighlightWrite>(
 6591                        &write_ranges,
 6592                        |theme| theme.colors().editor_document_highlight_write_background,
 6593                        cx,
 6594                    );
 6595                    cx.notify();
 6596                })
 6597                .log_err();
 6598            }
 6599        }));
 6600        None
 6601    }
 6602
 6603    fn prepare_highlight_query_from_selection(
 6604        &mut self,
 6605        cx: &mut Context<Editor>,
 6606    ) -> Option<(String, Range<Anchor>)> {
 6607        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6608            return None;
 6609        }
 6610        if !EditorSettings::get_global(cx).selection_highlight {
 6611            return None;
 6612        }
 6613        if self.selections.count() != 1 || self.selections.line_mode {
 6614            return None;
 6615        }
 6616        let selection = self.selections.newest::<Point>(cx);
 6617        if selection.is_empty() || selection.start.row != selection.end.row {
 6618            return None;
 6619        }
 6620        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6621        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6622        let query = multi_buffer_snapshot
 6623            .text_for_range(selection_anchor_range.clone())
 6624            .collect::<String>();
 6625        if query.trim().is_empty() {
 6626            return None;
 6627        }
 6628        Some((query, selection_anchor_range))
 6629    }
 6630
 6631    fn update_selection_occurrence_highlights(
 6632        &mut self,
 6633        query_text: String,
 6634        query_range: Range<Anchor>,
 6635        multi_buffer_range_to_query: Range<Point>,
 6636        use_debounce: bool,
 6637        window: &mut Window,
 6638        cx: &mut Context<Editor>,
 6639    ) -> Task<()> {
 6640        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6641        cx.spawn_in(window, async move |editor, cx| {
 6642            if use_debounce {
 6643                cx.background_executor()
 6644                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6645                    .await;
 6646            }
 6647            let match_task = cx.background_spawn(async move {
 6648                let buffer_ranges = multi_buffer_snapshot
 6649                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6650                    .into_iter()
 6651                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6652                let mut match_ranges = Vec::new();
 6653                let Ok(regex) = project::search::SearchQuery::text(
 6654                    query_text.clone(),
 6655                    false,
 6656                    false,
 6657                    false,
 6658                    Default::default(),
 6659                    Default::default(),
 6660                    false,
 6661                    None,
 6662                ) else {
 6663                    return Vec::default();
 6664                };
 6665                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6666                    match_ranges.extend(
 6667                        regex
 6668                            .search(&buffer_snapshot, Some(search_range.clone()))
 6669                            .await
 6670                            .into_iter()
 6671                            .filter_map(|match_range| {
 6672                                let match_start = buffer_snapshot
 6673                                    .anchor_after(search_range.start + match_range.start);
 6674                                let match_end = buffer_snapshot
 6675                                    .anchor_before(search_range.start + match_range.end);
 6676                                let match_anchor_range = Anchor::range_in_buffer(
 6677                                    excerpt_id,
 6678                                    buffer_snapshot.remote_id(),
 6679                                    match_start..match_end,
 6680                                );
 6681                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6682                            }),
 6683                    );
 6684                }
 6685                match_ranges
 6686            });
 6687            let match_ranges = match_task.await;
 6688            editor
 6689                .update_in(cx, |editor, _, cx| {
 6690                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6691                    if !match_ranges.is_empty() {
 6692                        editor.highlight_background::<SelectedTextHighlight>(
 6693                            &match_ranges,
 6694                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6695                            cx,
 6696                        )
 6697                    }
 6698                })
 6699                .log_err();
 6700        })
 6701    }
 6702
 6703    fn refresh_selected_text_highlights(
 6704        &mut self,
 6705        on_buffer_edit: bool,
 6706        window: &mut Window,
 6707        cx: &mut Context<Editor>,
 6708    ) {
 6709        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6710        else {
 6711            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6712            self.quick_selection_highlight_task.take();
 6713            self.debounced_selection_highlight_task.take();
 6714            return;
 6715        };
 6716        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6717        if on_buffer_edit
 6718            || self
 6719                .quick_selection_highlight_task
 6720                .as_ref()
 6721                .map_or(true, |(prev_anchor_range, _)| {
 6722                    prev_anchor_range != &query_range
 6723                })
 6724        {
 6725            let multi_buffer_visible_start = self
 6726                .scroll_manager
 6727                .anchor()
 6728                .anchor
 6729                .to_point(&multi_buffer_snapshot);
 6730            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6731                multi_buffer_visible_start
 6732                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6733                Bias::Left,
 6734            );
 6735            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6736            self.quick_selection_highlight_task = Some((
 6737                query_range.clone(),
 6738                self.update_selection_occurrence_highlights(
 6739                    query_text.clone(),
 6740                    query_range.clone(),
 6741                    multi_buffer_visible_range,
 6742                    false,
 6743                    window,
 6744                    cx,
 6745                ),
 6746            ));
 6747        }
 6748        if on_buffer_edit
 6749            || self
 6750                .debounced_selection_highlight_task
 6751                .as_ref()
 6752                .map_or(true, |(prev_anchor_range, _)| {
 6753                    prev_anchor_range != &query_range
 6754                })
 6755        {
 6756            let multi_buffer_start = multi_buffer_snapshot
 6757                .anchor_before(0)
 6758                .to_point(&multi_buffer_snapshot);
 6759            let multi_buffer_end = multi_buffer_snapshot
 6760                .anchor_after(multi_buffer_snapshot.len())
 6761                .to_point(&multi_buffer_snapshot);
 6762            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6763            self.debounced_selection_highlight_task = Some((
 6764                query_range.clone(),
 6765                self.update_selection_occurrence_highlights(
 6766                    query_text,
 6767                    query_range,
 6768                    multi_buffer_full_range,
 6769                    true,
 6770                    window,
 6771                    cx,
 6772                ),
 6773            ));
 6774        }
 6775    }
 6776
 6777    pub fn refresh_inline_completion(
 6778        &mut self,
 6779        debounce: bool,
 6780        user_requested: bool,
 6781        window: &mut Window,
 6782        cx: &mut Context<Self>,
 6783    ) -> Option<()> {
 6784        let provider = self.edit_prediction_provider()?;
 6785        let cursor = self.selections.newest_anchor().head();
 6786        let (buffer, cursor_buffer_position) =
 6787            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6788
 6789        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6790            self.discard_inline_completion(false, cx);
 6791            return None;
 6792        }
 6793
 6794        if !user_requested
 6795            && (!self.should_show_edit_predictions()
 6796                || !self.is_focused(window)
 6797                || buffer.read(cx).is_empty())
 6798        {
 6799            self.discard_inline_completion(false, cx);
 6800            return None;
 6801        }
 6802
 6803        self.update_visible_inline_completion(window, cx);
 6804        provider.refresh(
 6805            self.project.clone(),
 6806            buffer,
 6807            cursor_buffer_position,
 6808            debounce,
 6809            cx,
 6810        );
 6811        Some(())
 6812    }
 6813
 6814    fn show_edit_predictions_in_menu(&self) -> bool {
 6815        match self.edit_prediction_settings {
 6816            EditPredictionSettings::Disabled => false,
 6817            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6818        }
 6819    }
 6820
 6821    pub fn edit_predictions_enabled(&self) -> bool {
 6822        match self.edit_prediction_settings {
 6823            EditPredictionSettings::Disabled => false,
 6824            EditPredictionSettings::Enabled { .. } => true,
 6825        }
 6826    }
 6827
 6828    fn edit_prediction_requires_modifier(&self) -> bool {
 6829        match self.edit_prediction_settings {
 6830            EditPredictionSettings::Disabled => false,
 6831            EditPredictionSettings::Enabled {
 6832                preview_requires_modifier,
 6833                ..
 6834            } => preview_requires_modifier,
 6835        }
 6836    }
 6837
 6838    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6839        if self.edit_prediction_provider.is_none() {
 6840            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6841        } else {
 6842            let selection = self.selections.newest_anchor();
 6843            let cursor = selection.head();
 6844
 6845            if let Some((buffer, cursor_buffer_position)) =
 6846                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6847            {
 6848                self.edit_prediction_settings =
 6849                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6850            }
 6851        }
 6852    }
 6853
 6854    fn edit_prediction_settings_at_position(
 6855        &self,
 6856        buffer: &Entity<Buffer>,
 6857        buffer_position: language::Anchor,
 6858        cx: &App,
 6859    ) -> EditPredictionSettings {
 6860        if !self.mode.is_full()
 6861            || !self.show_inline_completions_override.unwrap_or(true)
 6862            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6863        {
 6864            return EditPredictionSettings::Disabled;
 6865        }
 6866
 6867        let buffer = buffer.read(cx);
 6868
 6869        let file = buffer.file();
 6870
 6871        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6872            return EditPredictionSettings::Disabled;
 6873        };
 6874
 6875        let by_provider = matches!(
 6876            self.menu_inline_completions_policy,
 6877            MenuInlineCompletionsPolicy::ByProvider
 6878        );
 6879
 6880        let show_in_menu = by_provider
 6881            && self
 6882                .edit_prediction_provider
 6883                .as_ref()
 6884                .map_or(false, |provider| {
 6885                    provider.provider.show_completions_in_menu()
 6886                });
 6887
 6888        let preview_requires_modifier =
 6889            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6890
 6891        EditPredictionSettings::Enabled {
 6892            show_in_menu,
 6893            preview_requires_modifier,
 6894        }
 6895    }
 6896
 6897    fn should_show_edit_predictions(&self) -> bool {
 6898        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6899    }
 6900
 6901    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6902        matches!(
 6903            self.edit_prediction_preview,
 6904            EditPredictionPreview::Active { .. }
 6905        )
 6906    }
 6907
 6908    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6909        let cursor = self.selections.newest_anchor().head();
 6910        if let Some((buffer, cursor_position)) =
 6911            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6912        {
 6913            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6914        } else {
 6915            false
 6916        }
 6917    }
 6918
 6919    pub fn supports_minimap(&self, cx: &App) -> bool {
 6920        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6921    }
 6922
 6923    fn edit_predictions_enabled_in_buffer(
 6924        &self,
 6925        buffer: &Entity<Buffer>,
 6926        buffer_position: language::Anchor,
 6927        cx: &App,
 6928    ) -> bool {
 6929        maybe!({
 6930            if self.read_only(cx) {
 6931                return Some(false);
 6932            }
 6933            let provider = self.edit_prediction_provider()?;
 6934            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6935                return Some(false);
 6936            }
 6937            let buffer = buffer.read(cx);
 6938            let Some(file) = buffer.file() else {
 6939                return Some(true);
 6940            };
 6941            let settings = all_language_settings(Some(file), cx);
 6942            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6943        })
 6944        .unwrap_or(false)
 6945    }
 6946
 6947    fn cycle_inline_completion(
 6948        &mut self,
 6949        direction: Direction,
 6950        window: &mut Window,
 6951        cx: &mut Context<Self>,
 6952    ) -> Option<()> {
 6953        let provider = self.edit_prediction_provider()?;
 6954        let cursor = self.selections.newest_anchor().head();
 6955        let (buffer, cursor_buffer_position) =
 6956            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6957        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6958            return None;
 6959        }
 6960
 6961        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6962        self.update_visible_inline_completion(window, cx);
 6963
 6964        Some(())
 6965    }
 6966
 6967    pub fn show_inline_completion(
 6968        &mut self,
 6969        _: &ShowEditPrediction,
 6970        window: &mut Window,
 6971        cx: &mut Context<Self>,
 6972    ) {
 6973        if !self.has_active_inline_completion() {
 6974            self.refresh_inline_completion(false, true, window, cx);
 6975            return;
 6976        }
 6977
 6978        self.update_visible_inline_completion(window, cx);
 6979    }
 6980
 6981    pub fn display_cursor_names(
 6982        &mut self,
 6983        _: &DisplayCursorNames,
 6984        window: &mut Window,
 6985        cx: &mut Context<Self>,
 6986    ) {
 6987        self.show_cursor_names(window, cx);
 6988    }
 6989
 6990    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6991        self.show_cursor_names = true;
 6992        cx.notify();
 6993        cx.spawn_in(window, async move |this, cx| {
 6994            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6995            this.update(cx, |this, cx| {
 6996                this.show_cursor_names = false;
 6997                cx.notify()
 6998            })
 6999            .ok()
 7000        })
 7001        .detach();
 7002    }
 7003
 7004    pub fn next_edit_prediction(
 7005        &mut self,
 7006        _: &NextEditPrediction,
 7007        window: &mut Window,
 7008        cx: &mut Context<Self>,
 7009    ) {
 7010        if self.has_active_inline_completion() {
 7011            self.cycle_inline_completion(Direction::Next, window, cx);
 7012        } else {
 7013            let is_copilot_disabled = self
 7014                .refresh_inline_completion(false, true, window, cx)
 7015                .is_none();
 7016            if is_copilot_disabled {
 7017                cx.propagate();
 7018            }
 7019        }
 7020    }
 7021
 7022    pub fn previous_edit_prediction(
 7023        &mut self,
 7024        _: &PreviousEditPrediction,
 7025        window: &mut Window,
 7026        cx: &mut Context<Self>,
 7027    ) {
 7028        if self.has_active_inline_completion() {
 7029            self.cycle_inline_completion(Direction::Prev, window, cx);
 7030        } else {
 7031            let is_copilot_disabled = self
 7032                .refresh_inline_completion(false, true, window, cx)
 7033                .is_none();
 7034            if is_copilot_disabled {
 7035                cx.propagate();
 7036            }
 7037        }
 7038    }
 7039
 7040    pub fn accept_edit_prediction(
 7041        &mut self,
 7042        _: &AcceptEditPrediction,
 7043        window: &mut Window,
 7044        cx: &mut Context<Self>,
 7045    ) {
 7046        if self.show_edit_predictions_in_menu() {
 7047            self.hide_context_menu(window, cx);
 7048        }
 7049
 7050        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7051            return;
 7052        };
 7053
 7054        self.report_inline_completion_event(
 7055            active_inline_completion.completion_id.clone(),
 7056            true,
 7057            cx,
 7058        );
 7059
 7060        match &active_inline_completion.completion {
 7061            InlineCompletion::Move { target, .. } => {
 7062                let target = *target;
 7063
 7064                if let Some(position_map) = &self.last_position_map {
 7065                    if position_map
 7066                        .visible_row_range
 7067                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7068                        || !self.edit_prediction_requires_modifier()
 7069                    {
 7070                        self.unfold_ranges(&[target..target], true, false, cx);
 7071                        // Note that this is also done in vim's handler of the Tab action.
 7072                        self.change_selections(
 7073                            Some(Autoscroll::newest()),
 7074                            window,
 7075                            cx,
 7076                            |selections| {
 7077                                selections.select_anchor_ranges([target..target]);
 7078                            },
 7079                        );
 7080                        self.clear_row_highlights::<EditPredictionPreview>();
 7081
 7082                        self.edit_prediction_preview
 7083                            .set_previous_scroll_position(None);
 7084                    } else {
 7085                        self.edit_prediction_preview
 7086                            .set_previous_scroll_position(Some(
 7087                                position_map.snapshot.scroll_anchor,
 7088                            ));
 7089
 7090                        self.highlight_rows::<EditPredictionPreview>(
 7091                            target..target,
 7092                            cx.theme().colors().editor_highlighted_line_background,
 7093                            RowHighlightOptions {
 7094                                autoscroll: true,
 7095                                ..Default::default()
 7096                            },
 7097                            cx,
 7098                        );
 7099                        self.request_autoscroll(Autoscroll::fit(), cx);
 7100                    }
 7101                }
 7102            }
 7103            InlineCompletion::Edit { edits, .. } => {
 7104                if let Some(provider) = self.edit_prediction_provider() {
 7105                    provider.accept(cx);
 7106                }
 7107
 7108                // Store the transaction ID and selections before applying the edit
 7109                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7110
 7111                let snapshot = self.buffer.read(cx).snapshot(cx);
 7112                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7113
 7114                self.buffer.update(cx, |buffer, cx| {
 7115                    buffer.edit(edits.iter().cloned(), None, cx)
 7116                });
 7117
 7118                self.change_selections(None, window, cx, |s| {
 7119                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7120                });
 7121
 7122                let selections = self.selections.disjoint_anchors();
 7123                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7124                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7125                    if has_new_transaction {
 7126                        self.selection_history
 7127                            .insert_transaction(transaction_id_now, selections);
 7128                    }
 7129                }
 7130
 7131                self.update_visible_inline_completion(window, cx);
 7132                if self.active_inline_completion.is_none() {
 7133                    self.refresh_inline_completion(true, true, window, cx);
 7134                }
 7135
 7136                cx.notify();
 7137            }
 7138        }
 7139
 7140        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7141    }
 7142
 7143    pub fn accept_partial_inline_completion(
 7144        &mut self,
 7145        _: &AcceptPartialEditPrediction,
 7146        window: &mut Window,
 7147        cx: &mut Context<Self>,
 7148    ) {
 7149        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 7150            return;
 7151        };
 7152        if self.selections.count() != 1 {
 7153            return;
 7154        }
 7155
 7156        self.report_inline_completion_event(
 7157            active_inline_completion.completion_id.clone(),
 7158            true,
 7159            cx,
 7160        );
 7161
 7162        match &active_inline_completion.completion {
 7163            InlineCompletion::Move { target, .. } => {
 7164                let target = *target;
 7165                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 7166                    selections.select_anchor_ranges([target..target]);
 7167                });
 7168            }
 7169            InlineCompletion::Edit { edits, .. } => {
 7170                // Find an insertion that starts at the cursor position.
 7171                let snapshot = self.buffer.read(cx).snapshot(cx);
 7172                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7173                let insertion = edits.iter().find_map(|(range, text)| {
 7174                    let range = range.to_offset(&snapshot);
 7175                    if range.is_empty() && range.start == cursor_offset {
 7176                        Some(text)
 7177                    } else {
 7178                        None
 7179                    }
 7180                });
 7181
 7182                if let Some(text) = insertion {
 7183                    let mut partial_completion = text
 7184                        .chars()
 7185                        .by_ref()
 7186                        .take_while(|c| c.is_alphabetic())
 7187                        .collect::<String>();
 7188                    if partial_completion.is_empty() {
 7189                        partial_completion = text
 7190                            .chars()
 7191                            .by_ref()
 7192                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7193                            .collect::<String>();
 7194                    }
 7195
 7196                    cx.emit(EditorEvent::InputHandled {
 7197                        utf16_range_to_replace: None,
 7198                        text: partial_completion.clone().into(),
 7199                    });
 7200
 7201                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7202
 7203                    self.refresh_inline_completion(true, true, window, cx);
 7204                    cx.notify();
 7205                } else {
 7206                    self.accept_edit_prediction(&Default::default(), window, cx);
 7207                }
 7208            }
 7209        }
 7210    }
 7211
 7212    fn discard_inline_completion(
 7213        &mut self,
 7214        should_report_inline_completion_event: bool,
 7215        cx: &mut Context<Self>,
 7216    ) -> bool {
 7217        if should_report_inline_completion_event {
 7218            let completion_id = self
 7219                .active_inline_completion
 7220                .as_ref()
 7221                .and_then(|active_completion| active_completion.completion_id.clone());
 7222
 7223            self.report_inline_completion_event(completion_id, false, cx);
 7224        }
 7225
 7226        if let Some(provider) = self.edit_prediction_provider() {
 7227            provider.discard(cx);
 7228        }
 7229
 7230        self.take_active_inline_completion(cx)
 7231    }
 7232
 7233    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7234        let Some(provider) = self.edit_prediction_provider() else {
 7235            return;
 7236        };
 7237
 7238        let Some((_, buffer, _)) = self
 7239            .buffer
 7240            .read(cx)
 7241            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7242        else {
 7243            return;
 7244        };
 7245
 7246        let extension = buffer
 7247            .read(cx)
 7248            .file()
 7249            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7250
 7251        let event_type = match accepted {
 7252            true => "Edit Prediction Accepted",
 7253            false => "Edit Prediction Discarded",
 7254        };
 7255        telemetry::event!(
 7256            event_type,
 7257            provider = provider.name(),
 7258            prediction_id = id,
 7259            suggestion_accepted = accepted,
 7260            file_extension = extension,
 7261        );
 7262    }
 7263
 7264    pub fn has_active_inline_completion(&self) -> bool {
 7265        self.active_inline_completion.is_some()
 7266    }
 7267
 7268    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7269        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7270            return false;
 7271        };
 7272
 7273        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7274        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7275        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7276        true
 7277    }
 7278
 7279    /// Returns true when we're displaying the edit prediction popover below the cursor
 7280    /// like we are not previewing and the LSP autocomplete menu is visible
 7281    /// or we are in `when_holding_modifier` mode.
 7282    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7283        if self.edit_prediction_preview_is_active()
 7284            || !self.show_edit_predictions_in_menu()
 7285            || !self.edit_predictions_enabled()
 7286        {
 7287            return false;
 7288        }
 7289
 7290        if self.has_visible_completions_menu() {
 7291            return true;
 7292        }
 7293
 7294        has_completion && self.edit_prediction_requires_modifier()
 7295    }
 7296
 7297    fn handle_modifiers_changed(
 7298        &mut self,
 7299        modifiers: Modifiers,
 7300        position_map: &PositionMap,
 7301        window: &mut Window,
 7302        cx: &mut Context<Self>,
 7303    ) {
 7304        if self.show_edit_predictions_in_menu() {
 7305            self.update_edit_prediction_preview(&modifiers, window, cx);
 7306        }
 7307
 7308        self.update_selection_mode(&modifiers, position_map, window, cx);
 7309
 7310        let mouse_position = window.mouse_position();
 7311        if !position_map.text_hitbox.is_hovered(window) {
 7312            return;
 7313        }
 7314
 7315        self.update_hovered_link(
 7316            position_map.point_for_position(mouse_position),
 7317            &position_map.snapshot,
 7318            modifiers,
 7319            window,
 7320            cx,
 7321        )
 7322    }
 7323
 7324    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7325        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7326        if invert {
 7327            match multi_cursor_setting {
 7328                MultiCursorModifier::Alt => modifiers.alt,
 7329                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7330            }
 7331        } else {
 7332            match multi_cursor_setting {
 7333                MultiCursorModifier::Alt => modifiers.secondary(),
 7334                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7335            }
 7336        }
 7337    }
 7338
 7339    fn columnar_selection_mode(
 7340        modifiers: &Modifiers,
 7341        cx: &mut Context<Self>,
 7342    ) -> Option<ColumnarMode> {
 7343        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7344            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7345                Some(ColumnarMode::FromMouse)
 7346            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7347                Some(ColumnarMode::FromSelection)
 7348            } else {
 7349                None
 7350            }
 7351        } else {
 7352            None
 7353        }
 7354    }
 7355
 7356    fn update_selection_mode(
 7357        &mut self,
 7358        modifiers: &Modifiers,
 7359        position_map: &PositionMap,
 7360        window: &mut Window,
 7361        cx: &mut Context<Self>,
 7362    ) {
 7363        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7364            return;
 7365        };
 7366        if self.selections.pending.is_none() {
 7367            return;
 7368        }
 7369
 7370        let mouse_position = window.mouse_position();
 7371        let point_for_position = position_map.point_for_position(mouse_position);
 7372        let position = point_for_position.previous_valid;
 7373
 7374        self.select(
 7375            SelectPhase::BeginColumnar {
 7376                position,
 7377                reset: false,
 7378                mode,
 7379                goal_column: point_for_position.exact_unclipped.column(),
 7380            },
 7381            window,
 7382            cx,
 7383        );
 7384    }
 7385
 7386    fn update_edit_prediction_preview(
 7387        &mut self,
 7388        modifiers: &Modifiers,
 7389        window: &mut Window,
 7390        cx: &mut Context<Self>,
 7391    ) {
 7392        let mut modifiers_held = false;
 7393        if let Some(accept_keystroke) = self
 7394            .accept_edit_prediction_keybind(false, window, cx)
 7395            .keystroke()
 7396        {
 7397            modifiers_held = modifiers_held
 7398                || (&accept_keystroke.modifiers == modifiers
 7399                    && accept_keystroke.modifiers.modified());
 7400        };
 7401        if let Some(accept_partial_keystroke) = self
 7402            .accept_edit_prediction_keybind(true, window, cx)
 7403            .keystroke()
 7404        {
 7405            modifiers_held = modifiers_held
 7406                || (&accept_partial_keystroke.modifiers == modifiers
 7407                    && accept_partial_keystroke.modifiers.modified());
 7408        }
 7409
 7410        if modifiers_held {
 7411            if matches!(
 7412                self.edit_prediction_preview,
 7413                EditPredictionPreview::Inactive { .. }
 7414            ) {
 7415                self.edit_prediction_preview = EditPredictionPreview::Active {
 7416                    previous_scroll_position: None,
 7417                    since: Instant::now(),
 7418                };
 7419
 7420                self.update_visible_inline_completion(window, cx);
 7421                cx.notify();
 7422            }
 7423        } else if let EditPredictionPreview::Active {
 7424            previous_scroll_position,
 7425            since,
 7426        } = self.edit_prediction_preview
 7427        {
 7428            if let (Some(previous_scroll_position), Some(position_map)) =
 7429                (previous_scroll_position, self.last_position_map.as_ref())
 7430            {
 7431                self.set_scroll_position(
 7432                    previous_scroll_position
 7433                        .scroll_position(&position_map.snapshot.display_snapshot),
 7434                    window,
 7435                    cx,
 7436                );
 7437            }
 7438
 7439            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7440                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7441            };
 7442            self.clear_row_highlights::<EditPredictionPreview>();
 7443            self.update_visible_inline_completion(window, cx);
 7444            cx.notify();
 7445        }
 7446    }
 7447
 7448    fn update_visible_inline_completion(
 7449        &mut self,
 7450        _window: &mut Window,
 7451        cx: &mut Context<Self>,
 7452    ) -> Option<()> {
 7453        let selection = self.selections.newest_anchor();
 7454        let cursor = selection.head();
 7455        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7456        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7457        let excerpt_id = cursor.excerpt_id;
 7458
 7459        let show_in_menu = self.show_edit_predictions_in_menu();
 7460        let completions_menu_has_precedence = !show_in_menu
 7461            && (self.context_menu.borrow().is_some()
 7462                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7463
 7464        if completions_menu_has_precedence
 7465            || !offset_selection.is_empty()
 7466            || self
 7467                .active_inline_completion
 7468                .as_ref()
 7469                .map_or(false, |completion| {
 7470                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7471                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7472                    !invalidation_range.contains(&offset_selection.head())
 7473                })
 7474        {
 7475            self.discard_inline_completion(false, cx);
 7476            return None;
 7477        }
 7478
 7479        self.take_active_inline_completion(cx);
 7480        let Some(provider) = self.edit_prediction_provider() else {
 7481            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7482            return None;
 7483        };
 7484
 7485        let (buffer, cursor_buffer_position) =
 7486            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7487
 7488        self.edit_prediction_settings =
 7489            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7490
 7491        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7492
 7493        if self.edit_prediction_indent_conflict {
 7494            let cursor_point = cursor.to_point(&multibuffer);
 7495
 7496            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7497
 7498            if let Some((_, indent)) = indents.iter().next() {
 7499                if indent.len == cursor_point.column {
 7500                    self.edit_prediction_indent_conflict = false;
 7501                }
 7502            }
 7503        }
 7504
 7505        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7506        let edits = inline_completion
 7507            .edits
 7508            .into_iter()
 7509            .flat_map(|(range, new_text)| {
 7510                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7511                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7512                Some((start..end, new_text))
 7513            })
 7514            .collect::<Vec<_>>();
 7515        if edits.is_empty() {
 7516            return None;
 7517        }
 7518
 7519        let first_edit_start = edits.first().unwrap().0.start;
 7520        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7521        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7522
 7523        let last_edit_end = edits.last().unwrap().0.end;
 7524        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7525        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7526
 7527        let cursor_row = cursor.to_point(&multibuffer).row;
 7528
 7529        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7530
 7531        let mut inlay_ids = Vec::new();
 7532        let invalidation_row_range;
 7533        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7534            Some(cursor_row..edit_end_row)
 7535        } else if cursor_row > edit_end_row {
 7536            Some(edit_start_row..cursor_row)
 7537        } else {
 7538            None
 7539        };
 7540        let is_move =
 7541            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7542        let completion = if is_move {
 7543            invalidation_row_range =
 7544                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7545            let target = first_edit_start;
 7546            InlineCompletion::Move { target, snapshot }
 7547        } else {
 7548            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7549                && !self.inline_completions_hidden_for_vim_mode;
 7550
 7551            if show_completions_in_buffer {
 7552                if edits
 7553                    .iter()
 7554                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7555                {
 7556                    let mut inlays = Vec::new();
 7557                    for (range, new_text) in &edits {
 7558                        let inlay = Inlay::inline_completion(
 7559                            post_inc(&mut self.next_inlay_id),
 7560                            range.start,
 7561                            new_text.as_str(),
 7562                        );
 7563                        inlay_ids.push(inlay.id);
 7564                        inlays.push(inlay);
 7565                    }
 7566
 7567                    self.splice_inlays(&[], inlays, cx);
 7568                } else {
 7569                    let background_color = cx.theme().status().deleted_background;
 7570                    self.highlight_text::<InlineCompletionHighlight>(
 7571                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7572                        HighlightStyle {
 7573                            background_color: Some(background_color),
 7574                            ..Default::default()
 7575                        },
 7576                        cx,
 7577                    );
 7578                }
 7579            }
 7580
 7581            invalidation_row_range = edit_start_row..edit_end_row;
 7582
 7583            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7584                if provider.show_tab_accept_marker() {
 7585                    EditDisplayMode::TabAccept
 7586                } else {
 7587                    EditDisplayMode::Inline
 7588                }
 7589            } else {
 7590                EditDisplayMode::DiffPopover
 7591            };
 7592
 7593            InlineCompletion::Edit {
 7594                edits,
 7595                edit_preview: inline_completion.edit_preview,
 7596                display_mode,
 7597                snapshot,
 7598            }
 7599        };
 7600
 7601        let invalidation_range = multibuffer
 7602            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7603            ..multibuffer.anchor_after(Point::new(
 7604                invalidation_row_range.end,
 7605                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7606            ));
 7607
 7608        self.stale_inline_completion_in_menu = None;
 7609        self.active_inline_completion = Some(InlineCompletionState {
 7610            inlay_ids,
 7611            completion,
 7612            completion_id: inline_completion.id,
 7613            invalidation_range,
 7614        });
 7615
 7616        cx.notify();
 7617
 7618        Some(())
 7619    }
 7620
 7621    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7622        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7623    }
 7624
 7625    fn clear_tasks(&mut self) {
 7626        self.tasks.clear()
 7627    }
 7628
 7629    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7630        if self.tasks.insert(key, value).is_some() {
 7631            // This case should hopefully be rare, but just in case...
 7632            log::error!(
 7633                "multiple different run targets found on a single line, only the last target will be rendered"
 7634            )
 7635        }
 7636    }
 7637
 7638    /// Get all display points of breakpoints that will be rendered within editor
 7639    ///
 7640    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7641    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7642    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7643    fn active_breakpoints(
 7644        &self,
 7645        range: Range<DisplayRow>,
 7646        window: &mut Window,
 7647        cx: &mut Context<Self>,
 7648    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7649        let mut breakpoint_display_points = HashMap::default();
 7650
 7651        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7652            return breakpoint_display_points;
 7653        };
 7654
 7655        let snapshot = self.snapshot(window, cx);
 7656
 7657        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7658        let Some(project) = self.project.as_ref() else {
 7659            return breakpoint_display_points;
 7660        };
 7661
 7662        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7663            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7664
 7665        for (buffer_snapshot, range, excerpt_id) in
 7666            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7667        {
 7668            let Some(buffer) = project
 7669                .read(cx)
 7670                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7671            else {
 7672                continue;
 7673            };
 7674            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7675                &buffer,
 7676                Some(
 7677                    buffer_snapshot.anchor_before(range.start)
 7678                        ..buffer_snapshot.anchor_after(range.end),
 7679                ),
 7680                buffer_snapshot,
 7681                cx,
 7682            );
 7683            for (breakpoint, state) in breakpoints {
 7684                let multi_buffer_anchor =
 7685                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7686                let position = multi_buffer_anchor
 7687                    .to_point(&multi_buffer_snapshot)
 7688                    .to_display_point(&snapshot);
 7689
 7690                breakpoint_display_points.insert(
 7691                    position.row(),
 7692                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7693                );
 7694            }
 7695        }
 7696
 7697        breakpoint_display_points
 7698    }
 7699
 7700    fn breakpoint_context_menu(
 7701        &self,
 7702        anchor: Anchor,
 7703        window: &mut Window,
 7704        cx: &mut Context<Self>,
 7705    ) -> Entity<ui::ContextMenu> {
 7706        let weak_editor = cx.weak_entity();
 7707        let focus_handle = self.focus_handle(cx);
 7708
 7709        let row = self
 7710            .buffer
 7711            .read(cx)
 7712            .snapshot(cx)
 7713            .summary_for_anchor::<Point>(&anchor)
 7714            .row;
 7715
 7716        let breakpoint = self
 7717            .breakpoint_at_row(row, window, cx)
 7718            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7719
 7720        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7721            "Edit Log Breakpoint"
 7722        } else {
 7723            "Set Log Breakpoint"
 7724        };
 7725
 7726        let condition_breakpoint_msg = if breakpoint
 7727            .as_ref()
 7728            .is_some_and(|bp| bp.1.condition.is_some())
 7729        {
 7730            "Edit Condition Breakpoint"
 7731        } else {
 7732            "Set Condition Breakpoint"
 7733        };
 7734
 7735        let hit_condition_breakpoint_msg = if breakpoint
 7736            .as_ref()
 7737            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7738        {
 7739            "Edit Hit Condition Breakpoint"
 7740        } else {
 7741            "Set Hit Condition Breakpoint"
 7742        };
 7743
 7744        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7745            "Unset Breakpoint"
 7746        } else {
 7747            "Set Breakpoint"
 7748        };
 7749
 7750        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 7751
 7752        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7753            BreakpointState::Enabled => Some("Disable"),
 7754            BreakpointState::Disabled => Some("Enable"),
 7755        });
 7756
 7757        let (anchor, breakpoint) =
 7758            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7759
 7760        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7761            menu.on_blur_subscription(Subscription::new(|| {}))
 7762                .context(focus_handle)
 7763                .when(run_to_cursor, |this| {
 7764                    let weak_editor = weak_editor.clone();
 7765                    this.entry("Run to cursor", None, move |window, cx| {
 7766                        weak_editor
 7767                            .update(cx, |editor, cx| {
 7768                                editor.change_selections(None, window, cx, |s| {
 7769                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7770                                });
 7771                            })
 7772                            .ok();
 7773
 7774                        window.dispatch_action(Box::new(RunToCursor), cx);
 7775                    })
 7776                    .separator()
 7777                })
 7778                .when_some(toggle_state_msg, |this, msg| {
 7779                    this.entry(msg, None, {
 7780                        let weak_editor = weak_editor.clone();
 7781                        let breakpoint = breakpoint.clone();
 7782                        move |_window, cx| {
 7783                            weak_editor
 7784                                .update(cx, |this, cx| {
 7785                                    this.edit_breakpoint_at_anchor(
 7786                                        anchor,
 7787                                        breakpoint.as_ref().clone(),
 7788                                        BreakpointEditAction::InvertState,
 7789                                        cx,
 7790                                    );
 7791                                })
 7792                                .log_err();
 7793                        }
 7794                    })
 7795                })
 7796                .entry(set_breakpoint_msg, None, {
 7797                    let weak_editor = weak_editor.clone();
 7798                    let breakpoint = breakpoint.clone();
 7799                    move |_window, cx| {
 7800                        weak_editor
 7801                            .update(cx, |this, cx| {
 7802                                this.edit_breakpoint_at_anchor(
 7803                                    anchor,
 7804                                    breakpoint.as_ref().clone(),
 7805                                    BreakpointEditAction::Toggle,
 7806                                    cx,
 7807                                );
 7808                            })
 7809                            .log_err();
 7810                    }
 7811                })
 7812                .entry(log_breakpoint_msg, None, {
 7813                    let breakpoint = breakpoint.clone();
 7814                    let weak_editor = weak_editor.clone();
 7815                    move |window, cx| {
 7816                        weak_editor
 7817                            .update(cx, |this, cx| {
 7818                                this.add_edit_breakpoint_block(
 7819                                    anchor,
 7820                                    breakpoint.as_ref(),
 7821                                    BreakpointPromptEditAction::Log,
 7822                                    window,
 7823                                    cx,
 7824                                );
 7825                            })
 7826                            .log_err();
 7827                    }
 7828                })
 7829                .entry(condition_breakpoint_msg, None, {
 7830                    let breakpoint = breakpoint.clone();
 7831                    let weak_editor = weak_editor.clone();
 7832                    move |window, cx| {
 7833                        weak_editor
 7834                            .update(cx, |this, cx| {
 7835                                this.add_edit_breakpoint_block(
 7836                                    anchor,
 7837                                    breakpoint.as_ref(),
 7838                                    BreakpointPromptEditAction::Condition,
 7839                                    window,
 7840                                    cx,
 7841                                );
 7842                            })
 7843                            .log_err();
 7844                    }
 7845                })
 7846                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7847                    weak_editor
 7848                        .update(cx, |this, cx| {
 7849                            this.add_edit_breakpoint_block(
 7850                                anchor,
 7851                                breakpoint.as_ref(),
 7852                                BreakpointPromptEditAction::HitCondition,
 7853                                window,
 7854                                cx,
 7855                            );
 7856                        })
 7857                        .log_err();
 7858                })
 7859        })
 7860    }
 7861
 7862    fn render_breakpoint(
 7863        &self,
 7864        position: Anchor,
 7865        row: DisplayRow,
 7866        breakpoint: &Breakpoint,
 7867        state: Option<BreakpointSessionState>,
 7868        cx: &mut Context<Self>,
 7869    ) -> IconButton {
 7870        let is_rejected = state.is_some_and(|s| !s.verified);
 7871        // Is it a breakpoint that shows up when hovering over gutter?
 7872        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7873            (false, false),
 7874            |PhantomBreakpointIndicator {
 7875                 is_active,
 7876                 display_row,
 7877                 collides_with_existing_breakpoint,
 7878             }| {
 7879                (
 7880                    is_active && display_row == row,
 7881                    collides_with_existing_breakpoint,
 7882                )
 7883            },
 7884        );
 7885
 7886        let (color, icon) = {
 7887            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7888                (false, false) => ui::IconName::DebugBreakpoint,
 7889                (true, false) => ui::IconName::DebugLogBreakpoint,
 7890                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7891                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7892            };
 7893
 7894            let color = if is_phantom {
 7895                Color::Hint
 7896            } else if is_rejected {
 7897                Color::Disabled
 7898            } else {
 7899                Color::Debugger
 7900            };
 7901
 7902            (color, icon)
 7903        };
 7904
 7905        let breakpoint = Arc::from(breakpoint.clone());
 7906
 7907        let alt_as_text = gpui::Keystroke {
 7908            modifiers: Modifiers::secondary_key(),
 7909            ..Default::default()
 7910        };
 7911        let primary_action_text = if breakpoint.is_disabled() {
 7912            "Enable breakpoint"
 7913        } else if is_phantom && !collides_with_existing {
 7914            "Set breakpoint"
 7915        } else {
 7916            "Unset breakpoint"
 7917        };
 7918        let focus_handle = self.focus_handle.clone();
 7919
 7920        let meta = if is_rejected {
 7921            SharedString::from("No executable code is associated with this line.")
 7922        } else if collides_with_existing && !breakpoint.is_disabled() {
 7923            SharedString::from(format!(
 7924                "{alt_as_text}-click to disable,\nright-click for more options."
 7925            ))
 7926        } else {
 7927            SharedString::from("Right-click for more options.")
 7928        };
 7929        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7930            .icon_size(IconSize::XSmall)
 7931            .size(ui::ButtonSize::None)
 7932            .when(is_rejected, |this| {
 7933                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7934            })
 7935            .icon_color(color)
 7936            .style(ButtonStyle::Transparent)
 7937            .on_click(cx.listener({
 7938                let breakpoint = breakpoint.clone();
 7939
 7940                move |editor, event: &ClickEvent, window, cx| {
 7941                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7942                        BreakpointEditAction::InvertState
 7943                    } else {
 7944                        BreakpointEditAction::Toggle
 7945                    };
 7946
 7947                    window.focus(&editor.focus_handle(cx));
 7948                    editor.edit_breakpoint_at_anchor(
 7949                        position,
 7950                        breakpoint.as_ref().clone(),
 7951                        edit_action,
 7952                        cx,
 7953                    );
 7954                }
 7955            }))
 7956            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7957                editor.set_breakpoint_context_menu(
 7958                    row,
 7959                    Some(position),
 7960                    event.down.position,
 7961                    window,
 7962                    cx,
 7963                );
 7964            }))
 7965            .tooltip(move |window, cx| {
 7966                Tooltip::with_meta_in(
 7967                    primary_action_text,
 7968                    Some(&ToggleBreakpoint),
 7969                    meta.clone(),
 7970                    &focus_handle,
 7971                    window,
 7972                    cx,
 7973                )
 7974            })
 7975    }
 7976
 7977    fn build_tasks_context(
 7978        project: &Entity<Project>,
 7979        buffer: &Entity<Buffer>,
 7980        buffer_row: u32,
 7981        tasks: &Arc<RunnableTasks>,
 7982        cx: &mut Context<Self>,
 7983    ) -> Task<Option<task::TaskContext>> {
 7984        let position = Point::new(buffer_row, tasks.column);
 7985        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7986        let location = Location {
 7987            buffer: buffer.clone(),
 7988            range: range_start..range_start,
 7989        };
 7990        // Fill in the environmental variables from the tree-sitter captures
 7991        let mut captured_task_variables = TaskVariables::default();
 7992        for (capture_name, value) in tasks.extra_variables.clone() {
 7993            captured_task_variables.insert(
 7994                task::VariableName::Custom(capture_name.into()),
 7995                value.clone(),
 7996            );
 7997        }
 7998        project.update(cx, |project, cx| {
 7999            project.task_store().update(cx, |task_store, cx| {
 8000                task_store.task_context_for_location(captured_task_variables, location, cx)
 8001            })
 8002        })
 8003    }
 8004
 8005    pub fn spawn_nearest_task(
 8006        &mut self,
 8007        action: &SpawnNearestTask,
 8008        window: &mut Window,
 8009        cx: &mut Context<Self>,
 8010    ) {
 8011        let Some((workspace, _)) = self.workspace.clone() else {
 8012            return;
 8013        };
 8014        let Some(project) = self.project.clone() else {
 8015            return;
 8016        };
 8017
 8018        // Try to find a closest, enclosing node using tree-sitter that has a
 8019        // task
 8020        let Some((buffer, buffer_row, tasks)) = self
 8021            .find_enclosing_node_task(cx)
 8022            // Or find the task that's closest in row-distance.
 8023            .or_else(|| self.find_closest_task(cx))
 8024        else {
 8025            return;
 8026        };
 8027
 8028        let reveal_strategy = action.reveal;
 8029        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8030        cx.spawn_in(window, async move |_, cx| {
 8031            let context = task_context.await?;
 8032            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8033
 8034            let resolved = &mut resolved_task.resolved;
 8035            resolved.reveal = reveal_strategy;
 8036
 8037            workspace
 8038                .update_in(cx, |workspace, window, cx| {
 8039                    workspace.schedule_resolved_task(
 8040                        task_source_kind,
 8041                        resolved_task,
 8042                        false,
 8043                        window,
 8044                        cx,
 8045                    );
 8046                })
 8047                .ok()
 8048        })
 8049        .detach();
 8050    }
 8051
 8052    fn find_closest_task(
 8053        &mut self,
 8054        cx: &mut Context<Self>,
 8055    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8056        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8057
 8058        let ((buffer_id, row), tasks) = self
 8059            .tasks
 8060            .iter()
 8061            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8062
 8063        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8064        let tasks = Arc::new(tasks.to_owned());
 8065        Some((buffer, *row, tasks))
 8066    }
 8067
 8068    fn find_enclosing_node_task(
 8069        &mut self,
 8070        cx: &mut Context<Self>,
 8071    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8072        let snapshot = self.buffer.read(cx).snapshot(cx);
 8073        let offset = self.selections.newest::<usize>(cx).head();
 8074        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8075        let buffer_id = excerpt.buffer().remote_id();
 8076
 8077        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8078        let mut cursor = layer.node().walk();
 8079
 8080        while cursor.goto_first_child_for_byte(offset).is_some() {
 8081            if cursor.node().end_byte() == offset {
 8082                cursor.goto_next_sibling();
 8083            }
 8084        }
 8085
 8086        // Ascend to the smallest ancestor that contains the range and has a task.
 8087        loop {
 8088            let node = cursor.node();
 8089            let node_range = node.byte_range();
 8090            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8091
 8092            // Check if this node contains our offset
 8093            if node_range.start <= offset && node_range.end >= offset {
 8094                // If it contains offset, check for task
 8095                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8096                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8097                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8098                }
 8099            }
 8100
 8101            if !cursor.goto_parent() {
 8102                break;
 8103            }
 8104        }
 8105        None
 8106    }
 8107
 8108    fn render_run_indicator(
 8109        &self,
 8110        _style: &EditorStyle,
 8111        is_active: bool,
 8112        row: DisplayRow,
 8113        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8114        cx: &mut Context<Self>,
 8115    ) -> IconButton {
 8116        let color = Color::Muted;
 8117        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8118
 8119        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 8120            .shape(ui::IconButtonShape::Square)
 8121            .icon_size(IconSize::XSmall)
 8122            .icon_color(color)
 8123            .toggle_state(is_active)
 8124            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8125                let quick_launch = e.down.button == MouseButton::Left;
 8126                window.focus(&editor.focus_handle(cx));
 8127                editor.toggle_code_actions(
 8128                    &ToggleCodeActions {
 8129                        deployed_from: Some(CodeActionSource::RunMenu(row)),
 8130                        quick_launch,
 8131                    },
 8132                    window,
 8133                    cx,
 8134                );
 8135            }))
 8136            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8137                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 8138            }))
 8139    }
 8140
 8141    pub fn context_menu_visible(&self) -> bool {
 8142        !self.edit_prediction_preview_is_active()
 8143            && self
 8144                .context_menu
 8145                .borrow()
 8146                .as_ref()
 8147                .map_or(false, |menu| menu.visible())
 8148    }
 8149
 8150    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8151        self.context_menu
 8152            .borrow()
 8153            .as_ref()
 8154            .map(|menu| menu.origin())
 8155    }
 8156
 8157    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8158        self.context_menu_options = Some(options);
 8159    }
 8160
 8161    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8162    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8163
 8164    fn render_edit_prediction_popover(
 8165        &mut self,
 8166        text_bounds: &Bounds<Pixels>,
 8167        content_origin: gpui::Point<Pixels>,
 8168        right_margin: Pixels,
 8169        editor_snapshot: &EditorSnapshot,
 8170        visible_row_range: Range<DisplayRow>,
 8171        scroll_top: f32,
 8172        scroll_bottom: f32,
 8173        line_layouts: &[LineWithInvisibles],
 8174        line_height: Pixels,
 8175        scroll_pixel_position: gpui::Point<Pixels>,
 8176        newest_selection_head: Option<DisplayPoint>,
 8177        editor_width: Pixels,
 8178        style: &EditorStyle,
 8179        window: &mut Window,
 8180        cx: &mut App,
 8181    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8182        if self.mode().is_minimap() {
 8183            return None;
 8184        }
 8185        let active_inline_completion = self.active_inline_completion.as_ref()?;
 8186
 8187        if self.edit_prediction_visible_in_cursor_popover(true) {
 8188            return None;
 8189        }
 8190
 8191        match &active_inline_completion.completion {
 8192            InlineCompletion::Move { target, .. } => {
 8193                let target_display_point = target.to_display_point(editor_snapshot);
 8194
 8195                if self.edit_prediction_requires_modifier() {
 8196                    if !self.edit_prediction_preview_is_active() {
 8197                        return None;
 8198                    }
 8199
 8200                    self.render_edit_prediction_modifier_jump_popover(
 8201                        text_bounds,
 8202                        content_origin,
 8203                        visible_row_range,
 8204                        line_layouts,
 8205                        line_height,
 8206                        scroll_pixel_position,
 8207                        newest_selection_head,
 8208                        target_display_point,
 8209                        window,
 8210                        cx,
 8211                    )
 8212                } else {
 8213                    self.render_edit_prediction_eager_jump_popover(
 8214                        text_bounds,
 8215                        content_origin,
 8216                        editor_snapshot,
 8217                        visible_row_range,
 8218                        scroll_top,
 8219                        scroll_bottom,
 8220                        line_height,
 8221                        scroll_pixel_position,
 8222                        target_display_point,
 8223                        editor_width,
 8224                        window,
 8225                        cx,
 8226                    )
 8227                }
 8228            }
 8229            InlineCompletion::Edit {
 8230                display_mode: EditDisplayMode::Inline,
 8231                ..
 8232            } => None,
 8233            InlineCompletion::Edit {
 8234                display_mode: EditDisplayMode::TabAccept,
 8235                edits,
 8236                ..
 8237            } => {
 8238                let range = &edits.first()?.0;
 8239                let target_display_point = range.end.to_display_point(editor_snapshot);
 8240
 8241                self.render_edit_prediction_end_of_line_popover(
 8242                    "Accept",
 8243                    editor_snapshot,
 8244                    visible_row_range,
 8245                    target_display_point,
 8246                    line_height,
 8247                    scroll_pixel_position,
 8248                    content_origin,
 8249                    editor_width,
 8250                    window,
 8251                    cx,
 8252                )
 8253            }
 8254            InlineCompletion::Edit {
 8255                edits,
 8256                edit_preview,
 8257                display_mode: EditDisplayMode::DiffPopover,
 8258                snapshot,
 8259            } => self.render_edit_prediction_diff_popover(
 8260                text_bounds,
 8261                content_origin,
 8262                right_margin,
 8263                editor_snapshot,
 8264                visible_row_range,
 8265                line_layouts,
 8266                line_height,
 8267                scroll_pixel_position,
 8268                newest_selection_head,
 8269                editor_width,
 8270                style,
 8271                edits,
 8272                edit_preview,
 8273                snapshot,
 8274                window,
 8275                cx,
 8276            ),
 8277        }
 8278    }
 8279
 8280    fn render_edit_prediction_modifier_jump_popover(
 8281        &mut self,
 8282        text_bounds: &Bounds<Pixels>,
 8283        content_origin: gpui::Point<Pixels>,
 8284        visible_row_range: Range<DisplayRow>,
 8285        line_layouts: &[LineWithInvisibles],
 8286        line_height: Pixels,
 8287        scroll_pixel_position: gpui::Point<Pixels>,
 8288        newest_selection_head: Option<DisplayPoint>,
 8289        target_display_point: DisplayPoint,
 8290        window: &mut Window,
 8291        cx: &mut App,
 8292    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8293        let scrolled_content_origin =
 8294            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8295
 8296        const SCROLL_PADDING_Y: Pixels = px(12.);
 8297
 8298        if target_display_point.row() < visible_row_range.start {
 8299            return self.render_edit_prediction_scroll_popover(
 8300                |_| SCROLL_PADDING_Y,
 8301                IconName::ArrowUp,
 8302                visible_row_range,
 8303                line_layouts,
 8304                newest_selection_head,
 8305                scrolled_content_origin,
 8306                window,
 8307                cx,
 8308            );
 8309        } else if target_display_point.row() >= visible_row_range.end {
 8310            return self.render_edit_prediction_scroll_popover(
 8311                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8312                IconName::ArrowDown,
 8313                visible_row_range,
 8314                line_layouts,
 8315                newest_selection_head,
 8316                scrolled_content_origin,
 8317                window,
 8318                cx,
 8319            );
 8320        }
 8321
 8322        const POLE_WIDTH: Pixels = px(2.);
 8323
 8324        let line_layout =
 8325            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8326        let target_column = target_display_point.column() as usize;
 8327
 8328        let target_x = line_layout.x_for_index(target_column);
 8329        let target_y =
 8330            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8331
 8332        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8333
 8334        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8335        border_color.l += 0.001;
 8336
 8337        let mut element = v_flex()
 8338            .items_end()
 8339            .when(flag_on_right, |el| el.items_start())
 8340            .child(if flag_on_right {
 8341                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8342                    .rounded_bl(px(0.))
 8343                    .rounded_tl(px(0.))
 8344                    .border_l_2()
 8345                    .border_color(border_color)
 8346            } else {
 8347                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8348                    .rounded_br(px(0.))
 8349                    .rounded_tr(px(0.))
 8350                    .border_r_2()
 8351                    .border_color(border_color)
 8352            })
 8353            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8354            .into_any();
 8355
 8356        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8357
 8358        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8359            - point(
 8360                if flag_on_right {
 8361                    POLE_WIDTH
 8362                } else {
 8363                    size.width - POLE_WIDTH
 8364                },
 8365                size.height - line_height,
 8366            );
 8367
 8368        origin.x = origin.x.max(content_origin.x);
 8369
 8370        element.prepaint_at(origin, window, cx);
 8371
 8372        Some((element, origin))
 8373    }
 8374
 8375    fn render_edit_prediction_scroll_popover(
 8376        &mut self,
 8377        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8378        scroll_icon: IconName,
 8379        visible_row_range: Range<DisplayRow>,
 8380        line_layouts: &[LineWithInvisibles],
 8381        newest_selection_head: Option<DisplayPoint>,
 8382        scrolled_content_origin: gpui::Point<Pixels>,
 8383        window: &mut Window,
 8384        cx: &mut App,
 8385    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8386        let mut element = self
 8387            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8388            .into_any();
 8389
 8390        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8391
 8392        let cursor = newest_selection_head?;
 8393        let cursor_row_layout =
 8394            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8395        let cursor_column = cursor.column() as usize;
 8396
 8397        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8398
 8399        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8400
 8401        element.prepaint_at(origin, window, cx);
 8402        Some((element, origin))
 8403    }
 8404
 8405    fn render_edit_prediction_eager_jump_popover(
 8406        &mut self,
 8407        text_bounds: &Bounds<Pixels>,
 8408        content_origin: gpui::Point<Pixels>,
 8409        editor_snapshot: &EditorSnapshot,
 8410        visible_row_range: Range<DisplayRow>,
 8411        scroll_top: f32,
 8412        scroll_bottom: f32,
 8413        line_height: Pixels,
 8414        scroll_pixel_position: gpui::Point<Pixels>,
 8415        target_display_point: DisplayPoint,
 8416        editor_width: Pixels,
 8417        window: &mut Window,
 8418        cx: &mut App,
 8419    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8420        if target_display_point.row().as_f32() < scroll_top {
 8421            let mut element = self
 8422                .render_edit_prediction_line_popover(
 8423                    "Jump to Edit",
 8424                    Some(IconName::ArrowUp),
 8425                    window,
 8426                    cx,
 8427                )?
 8428                .into_any();
 8429
 8430            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8431            let offset = point(
 8432                (text_bounds.size.width - size.width) / 2.,
 8433                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8434            );
 8435
 8436            let origin = text_bounds.origin + offset;
 8437            element.prepaint_at(origin, window, cx);
 8438            Some((element, origin))
 8439        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8440            let mut element = self
 8441                .render_edit_prediction_line_popover(
 8442                    "Jump to Edit",
 8443                    Some(IconName::ArrowDown),
 8444                    window,
 8445                    cx,
 8446                )?
 8447                .into_any();
 8448
 8449            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8450            let offset = point(
 8451                (text_bounds.size.width - size.width) / 2.,
 8452                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8453            );
 8454
 8455            let origin = text_bounds.origin + offset;
 8456            element.prepaint_at(origin, window, cx);
 8457            Some((element, origin))
 8458        } else {
 8459            self.render_edit_prediction_end_of_line_popover(
 8460                "Jump to Edit",
 8461                editor_snapshot,
 8462                visible_row_range,
 8463                target_display_point,
 8464                line_height,
 8465                scroll_pixel_position,
 8466                content_origin,
 8467                editor_width,
 8468                window,
 8469                cx,
 8470            )
 8471        }
 8472    }
 8473
 8474    fn render_edit_prediction_end_of_line_popover(
 8475        self: &mut Editor,
 8476        label: &'static str,
 8477        editor_snapshot: &EditorSnapshot,
 8478        visible_row_range: Range<DisplayRow>,
 8479        target_display_point: DisplayPoint,
 8480        line_height: Pixels,
 8481        scroll_pixel_position: gpui::Point<Pixels>,
 8482        content_origin: gpui::Point<Pixels>,
 8483        editor_width: Pixels,
 8484        window: &mut Window,
 8485        cx: &mut App,
 8486    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8487        let target_line_end = DisplayPoint::new(
 8488            target_display_point.row(),
 8489            editor_snapshot.line_len(target_display_point.row()),
 8490        );
 8491
 8492        let mut element = self
 8493            .render_edit_prediction_line_popover(label, None, window, cx)?
 8494            .into_any();
 8495
 8496        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8497
 8498        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8499
 8500        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8501        let mut origin = start_point
 8502            + line_origin
 8503            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8504        origin.x = origin.x.max(content_origin.x);
 8505
 8506        let max_x = content_origin.x + editor_width - size.width;
 8507
 8508        if origin.x > max_x {
 8509            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8510
 8511            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8512                origin.y += offset;
 8513                IconName::ArrowUp
 8514            } else {
 8515                origin.y -= offset;
 8516                IconName::ArrowDown
 8517            };
 8518
 8519            element = self
 8520                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8521                .into_any();
 8522
 8523            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8524
 8525            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8526        }
 8527
 8528        element.prepaint_at(origin, window, cx);
 8529        Some((element, origin))
 8530    }
 8531
 8532    fn render_edit_prediction_diff_popover(
 8533        self: &Editor,
 8534        text_bounds: &Bounds<Pixels>,
 8535        content_origin: gpui::Point<Pixels>,
 8536        right_margin: Pixels,
 8537        editor_snapshot: &EditorSnapshot,
 8538        visible_row_range: Range<DisplayRow>,
 8539        line_layouts: &[LineWithInvisibles],
 8540        line_height: Pixels,
 8541        scroll_pixel_position: gpui::Point<Pixels>,
 8542        newest_selection_head: Option<DisplayPoint>,
 8543        editor_width: Pixels,
 8544        style: &EditorStyle,
 8545        edits: &Vec<(Range<Anchor>, String)>,
 8546        edit_preview: &Option<language::EditPreview>,
 8547        snapshot: &language::BufferSnapshot,
 8548        window: &mut Window,
 8549        cx: &mut App,
 8550    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8551        let edit_start = edits
 8552            .first()
 8553            .unwrap()
 8554            .0
 8555            .start
 8556            .to_display_point(editor_snapshot);
 8557        let edit_end = edits
 8558            .last()
 8559            .unwrap()
 8560            .0
 8561            .end
 8562            .to_display_point(editor_snapshot);
 8563
 8564        let is_visible = visible_row_range.contains(&edit_start.row())
 8565            || visible_row_range.contains(&edit_end.row());
 8566        if !is_visible {
 8567            return None;
 8568        }
 8569
 8570        let highlighted_edits =
 8571            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8572
 8573        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8574        let line_count = highlighted_edits.text.lines().count();
 8575
 8576        const BORDER_WIDTH: Pixels = px(1.);
 8577
 8578        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8579        let has_keybind = keybind.is_some();
 8580
 8581        let mut element = h_flex()
 8582            .items_start()
 8583            .child(
 8584                h_flex()
 8585                    .bg(cx.theme().colors().editor_background)
 8586                    .border(BORDER_WIDTH)
 8587                    .shadow_sm()
 8588                    .border_color(cx.theme().colors().border)
 8589                    .rounded_l_lg()
 8590                    .when(line_count > 1, |el| el.rounded_br_lg())
 8591                    .pr_1()
 8592                    .child(styled_text),
 8593            )
 8594            .child(
 8595                h_flex()
 8596                    .h(line_height + BORDER_WIDTH * 2.)
 8597                    .px_1p5()
 8598                    .gap_1()
 8599                    // Workaround: For some reason, there's a gap if we don't do this
 8600                    .ml(-BORDER_WIDTH)
 8601                    .shadow(vec![gpui::BoxShadow {
 8602                        color: gpui::black().opacity(0.05),
 8603                        offset: point(px(1.), px(1.)),
 8604                        blur_radius: px(2.),
 8605                        spread_radius: px(0.),
 8606                    }])
 8607                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8608                    .border(BORDER_WIDTH)
 8609                    .border_color(cx.theme().colors().border)
 8610                    .rounded_r_lg()
 8611                    .id("edit_prediction_diff_popover_keybind")
 8612                    .when(!has_keybind, |el| {
 8613                        let status_colors = cx.theme().status();
 8614
 8615                        el.bg(status_colors.error_background)
 8616                            .border_color(status_colors.error.opacity(0.6))
 8617                            .child(Icon::new(IconName::Info).color(Color::Error))
 8618                            .cursor_default()
 8619                            .hoverable_tooltip(move |_window, cx| {
 8620                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8621                            })
 8622                    })
 8623                    .children(keybind),
 8624            )
 8625            .into_any();
 8626
 8627        let longest_row =
 8628            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8629        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8630            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8631        } else {
 8632            layout_line(
 8633                longest_row,
 8634                editor_snapshot,
 8635                style,
 8636                editor_width,
 8637                |_| false,
 8638                window,
 8639                cx,
 8640            )
 8641            .width
 8642        };
 8643
 8644        let viewport_bounds =
 8645            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8646                right: -right_margin,
 8647                ..Default::default()
 8648            });
 8649
 8650        let x_after_longest =
 8651            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8652                - scroll_pixel_position.x;
 8653
 8654        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8655
 8656        // Fully visible if it can be displayed within the window (allow overlapping other
 8657        // panes). However, this is only allowed if the popover starts within text_bounds.
 8658        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8659            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8660
 8661        let mut origin = if can_position_to_the_right {
 8662            point(
 8663                x_after_longest,
 8664                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8665                    - scroll_pixel_position.y,
 8666            )
 8667        } else {
 8668            let cursor_row = newest_selection_head.map(|head| head.row());
 8669            let above_edit = edit_start
 8670                .row()
 8671                .0
 8672                .checked_sub(line_count as u32)
 8673                .map(DisplayRow);
 8674            let below_edit = Some(edit_end.row() + 1);
 8675            let above_cursor =
 8676                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8677            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8678
 8679            // Place the edit popover adjacent to the edit if there is a location
 8680            // available that is onscreen and does not obscure the cursor. Otherwise,
 8681            // place it adjacent to the cursor.
 8682            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8683                .into_iter()
 8684                .flatten()
 8685                .find(|&start_row| {
 8686                    let end_row = start_row + line_count as u32;
 8687                    visible_row_range.contains(&start_row)
 8688                        && visible_row_range.contains(&end_row)
 8689                        && cursor_row.map_or(true, |cursor_row| {
 8690                            !((start_row..end_row).contains(&cursor_row))
 8691                        })
 8692                })?;
 8693
 8694            content_origin
 8695                + point(
 8696                    -scroll_pixel_position.x,
 8697                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8698                )
 8699        };
 8700
 8701        origin.x -= BORDER_WIDTH;
 8702
 8703        window.defer_draw(element, origin, 1);
 8704
 8705        // Do not return an element, since it will already be drawn due to defer_draw.
 8706        None
 8707    }
 8708
 8709    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8710        px(30.)
 8711    }
 8712
 8713    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8714        if self.read_only(cx) {
 8715            cx.theme().players().read_only()
 8716        } else {
 8717            self.style.as_ref().unwrap().local_player
 8718        }
 8719    }
 8720
 8721    fn render_edit_prediction_accept_keybind(
 8722        &self,
 8723        window: &mut Window,
 8724        cx: &App,
 8725    ) -> Option<AnyElement> {
 8726        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8727        let accept_keystroke = accept_binding.keystroke()?;
 8728
 8729        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8730
 8731        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8732            Color::Accent
 8733        } else {
 8734            Color::Muted
 8735        };
 8736
 8737        h_flex()
 8738            .px_0p5()
 8739            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8740            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8741            .text_size(TextSize::XSmall.rems(cx))
 8742            .child(h_flex().children(ui::render_modifiers(
 8743                &accept_keystroke.modifiers,
 8744                PlatformStyle::platform(),
 8745                Some(modifiers_color),
 8746                Some(IconSize::XSmall.rems().into()),
 8747                true,
 8748            )))
 8749            .when(is_platform_style_mac, |parent| {
 8750                parent.child(accept_keystroke.key.clone())
 8751            })
 8752            .when(!is_platform_style_mac, |parent| {
 8753                parent.child(
 8754                    Key::new(
 8755                        util::capitalize(&accept_keystroke.key),
 8756                        Some(Color::Default),
 8757                    )
 8758                    .size(Some(IconSize::XSmall.rems().into())),
 8759                )
 8760            })
 8761            .into_any()
 8762            .into()
 8763    }
 8764
 8765    fn render_edit_prediction_line_popover(
 8766        &self,
 8767        label: impl Into<SharedString>,
 8768        icon: Option<IconName>,
 8769        window: &mut Window,
 8770        cx: &App,
 8771    ) -> Option<Stateful<Div>> {
 8772        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8773
 8774        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8775        let has_keybind = keybind.is_some();
 8776
 8777        let result = h_flex()
 8778            .id("ep-line-popover")
 8779            .py_0p5()
 8780            .pl_1()
 8781            .pr(padding_right)
 8782            .gap_1()
 8783            .rounded_md()
 8784            .border_1()
 8785            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8786            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8787            .shadow_sm()
 8788            .when(!has_keybind, |el| {
 8789                let status_colors = cx.theme().status();
 8790
 8791                el.bg(status_colors.error_background)
 8792                    .border_color(status_colors.error.opacity(0.6))
 8793                    .pl_2()
 8794                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8795                    .cursor_default()
 8796                    .hoverable_tooltip(move |_window, cx| {
 8797                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8798                    })
 8799            })
 8800            .children(keybind)
 8801            .child(
 8802                Label::new(label)
 8803                    .size(LabelSize::Small)
 8804                    .when(!has_keybind, |el| {
 8805                        el.color(cx.theme().status().error.into()).strikethrough()
 8806                    }),
 8807            )
 8808            .when(!has_keybind, |el| {
 8809                el.child(
 8810                    h_flex().ml_1().child(
 8811                        Icon::new(IconName::Info)
 8812                            .size(IconSize::Small)
 8813                            .color(cx.theme().status().error.into()),
 8814                    ),
 8815                )
 8816            })
 8817            .when_some(icon, |element, icon| {
 8818                element.child(
 8819                    div()
 8820                        .mt(px(1.5))
 8821                        .child(Icon::new(icon).size(IconSize::Small)),
 8822                )
 8823            });
 8824
 8825        Some(result)
 8826    }
 8827
 8828    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8829        let accent_color = cx.theme().colors().text_accent;
 8830        let editor_bg_color = cx.theme().colors().editor_background;
 8831        editor_bg_color.blend(accent_color.opacity(0.1))
 8832    }
 8833
 8834    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8835        let accent_color = cx.theme().colors().text_accent;
 8836        let editor_bg_color = cx.theme().colors().editor_background;
 8837        editor_bg_color.blend(accent_color.opacity(0.6))
 8838    }
 8839
 8840    fn render_edit_prediction_cursor_popover(
 8841        &self,
 8842        min_width: Pixels,
 8843        max_width: Pixels,
 8844        cursor_point: Point,
 8845        style: &EditorStyle,
 8846        accept_keystroke: Option<&gpui::Keystroke>,
 8847        _window: &Window,
 8848        cx: &mut Context<Editor>,
 8849    ) -> Option<AnyElement> {
 8850        let provider = self.edit_prediction_provider.as_ref()?;
 8851
 8852        if provider.provider.needs_terms_acceptance(cx) {
 8853            return Some(
 8854                h_flex()
 8855                    .min_w(min_width)
 8856                    .flex_1()
 8857                    .px_2()
 8858                    .py_1()
 8859                    .gap_3()
 8860                    .elevation_2(cx)
 8861                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8862                    .id("accept-terms")
 8863                    .cursor_pointer()
 8864                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8865                    .on_click(cx.listener(|this, _event, window, cx| {
 8866                        cx.stop_propagation();
 8867                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8868                        window.dispatch_action(
 8869                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8870                            cx,
 8871                        );
 8872                    }))
 8873                    .child(
 8874                        h_flex()
 8875                            .flex_1()
 8876                            .gap_2()
 8877                            .child(Icon::new(IconName::ZedPredict))
 8878                            .child(Label::new("Accept Terms of Service"))
 8879                            .child(div().w_full())
 8880                            .child(
 8881                                Icon::new(IconName::ArrowUpRight)
 8882                                    .color(Color::Muted)
 8883                                    .size(IconSize::Small),
 8884                            )
 8885                            .into_any_element(),
 8886                    )
 8887                    .into_any(),
 8888            );
 8889        }
 8890
 8891        let is_refreshing = provider.provider.is_refreshing(cx);
 8892
 8893        fn pending_completion_container() -> Div {
 8894            h_flex()
 8895                .h_full()
 8896                .flex_1()
 8897                .gap_2()
 8898                .child(Icon::new(IconName::ZedPredict))
 8899        }
 8900
 8901        let completion = match &self.active_inline_completion {
 8902            Some(prediction) => {
 8903                if !self.has_visible_completions_menu() {
 8904                    const RADIUS: Pixels = px(6.);
 8905                    const BORDER_WIDTH: Pixels = px(1.);
 8906
 8907                    return Some(
 8908                        h_flex()
 8909                            .elevation_2(cx)
 8910                            .border(BORDER_WIDTH)
 8911                            .border_color(cx.theme().colors().border)
 8912                            .when(accept_keystroke.is_none(), |el| {
 8913                                el.border_color(cx.theme().status().error)
 8914                            })
 8915                            .rounded(RADIUS)
 8916                            .rounded_tl(px(0.))
 8917                            .overflow_hidden()
 8918                            .child(div().px_1p5().child(match &prediction.completion {
 8919                                InlineCompletion::Move { target, snapshot } => {
 8920                                    use text::ToPoint as _;
 8921                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8922                                    {
 8923                                        Icon::new(IconName::ZedPredictDown)
 8924                                    } else {
 8925                                        Icon::new(IconName::ZedPredictUp)
 8926                                    }
 8927                                }
 8928                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8929                            }))
 8930                            .child(
 8931                                h_flex()
 8932                                    .gap_1()
 8933                                    .py_1()
 8934                                    .px_2()
 8935                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8936                                    .border_l_1()
 8937                                    .border_color(cx.theme().colors().border)
 8938                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8939                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8940                                        el.child(
 8941                                            Label::new("Hold")
 8942                                                .size(LabelSize::Small)
 8943                                                .when(accept_keystroke.is_none(), |el| {
 8944                                                    el.strikethrough()
 8945                                                })
 8946                                                .line_height_style(LineHeightStyle::UiLabel),
 8947                                        )
 8948                                    })
 8949                                    .id("edit_prediction_cursor_popover_keybind")
 8950                                    .when(accept_keystroke.is_none(), |el| {
 8951                                        let status_colors = cx.theme().status();
 8952
 8953                                        el.bg(status_colors.error_background)
 8954                                            .border_color(status_colors.error.opacity(0.6))
 8955                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8956                                            .cursor_default()
 8957                                            .hoverable_tooltip(move |_window, cx| {
 8958                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8959                                                    .into()
 8960                                            })
 8961                                    })
 8962                                    .when_some(
 8963                                        accept_keystroke.as_ref(),
 8964                                        |el, accept_keystroke| {
 8965                                            el.child(h_flex().children(ui::render_modifiers(
 8966                                                &accept_keystroke.modifiers,
 8967                                                PlatformStyle::platform(),
 8968                                                Some(Color::Default),
 8969                                                Some(IconSize::XSmall.rems().into()),
 8970                                                false,
 8971                                            )))
 8972                                        },
 8973                                    ),
 8974                            )
 8975                            .into_any(),
 8976                    );
 8977                }
 8978
 8979                self.render_edit_prediction_cursor_popover_preview(
 8980                    prediction,
 8981                    cursor_point,
 8982                    style,
 8983                    cx,
 8984                )?
 8985            }
 8986
 8987            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8988                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8989                    stale_completion,
 8990                    cursor_point,
 8991                    style,
 8992                    cx,
 8993                )?,
 8994
 8995                None => {
 8996                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8997                }
 8998            },
 8999
 9000            None => pending_completion_container().child(Label::new("No Prediction")),
 9001        };
 9002
 9003        let completion = if is_refreshing {
 9004            completion
 9005                .with_animation(
 9006                    "loading-completion",
 9007                    Animation::new(Duration::from_secs(2))
 9008                        .repeat()
 9009                        .with_easing(pulsating_between(0.4, 0.8)),
 9010                    |label, delta| label.opacity(delta),
 9011                )
 9012                .into_any_element()
 9013        } else {
 9014            completion.into_any_element()
 9015        };
 9016
 9017        let has_completion = self.active_inline_completion.is_some();
 9018
 9019        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9020        Some(
 9021            h_flex()
 9022                .min_w(min_width)
 9023                .max_w(max_width)
 9024                .flex_1()
 9025                .elevation_2(cx)
 9026                .border_color(cx.theme().colors().border)
 9027                .child(
 9028                    div()
 9029                        .flex_1()
 9030                        .py_1()
 9031                        .px_2()
 9032                        .overflow_hidden()
 9033                        .child(completion),
 9034                )
 9035                .when_some(accept_keystroke, |el, accept_keystroke| {
 9036                    if !accept_keystroke.modifiers.modified() {
 9037                        return el;
 9038                    }
 9039
 9040                    el.child(
 9041                        h_flex()
 9042                            .h_full()
 9043                            .border_l_1()
 9044                            .rounded_r_lg()
 9045                            .border_color(cx.theme().colors().border)
 9046                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9047                            .gap_1()
 9048                            .py_1()
 9049                            .px_2()
 9050                            .child(
 9051                                h_flex()
 9052                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9053                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9054                                    .child(h_flex().children(ui::render_modifiers(
 9055                                        &accept_keystroke.modifiers,
 9056                                        PlatformStyle::platform(),
 9057                                        Some(if !has_completion {
 9058                                            Color::Muted
 9059                                        } else {
 9060                                            Color::Default
 9061                                        }),
 9062                                        None,
 9063                                        false,
 9064                                    ))),
 9065                            )
 9066                            .child(Label::new("Preview").into_any_element())
 9067                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9068                    )
 9069                })
 9070                .into_any(),
 9071        )
 9072    }
 9073
 9074    fn render_edit_prediction_cursor_popover_preview(
 9075        &self,
 9076        completion: &InlineCompletionState,
 9077        cursor_point: Point,
 9078        style: &EditorStyle,
 9079        cx: &mut Context<Editor>,
 9080    ) -> Option<Div> {
 9081        use text::ToPoint as _;
 9082
 9083        fn render_relative_row_jump(
 9084            prefix: impl Into<String>,
 9085            current_row: u32,
 9086            target_row: u32,
 9087        ) -> Div {
 9088            let (row_diff, arrow) = if target_row < current_row {
 9089                (current_row - target_row, IconName::ArrowUp)
 9090            } else {
 9091                (target_row - current_row, IconName::ArrowDown)
 9092            };
 9093
 9094            h_flex()
 9095                .child(
 9096                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9097                        .color(Color::Muted)
 9098                        .size(LabelSize::Small),
 9099                )
 9100                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9101        }
 9102
 9103        match &completion.completion {
 9104            InlineCompletion::Move {
 9105                target, snapshot, ..
 9106            } => Some(
 9107                h_flex()
 9108                    .px_2()
 9109                    .gap_2()
 9110                    .flex_1()
 9111                    .child(
 9112                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9113                            Icon::new(IconName::ZedPredictDown)
 9114                        } else {
 9115                            Icon::new(IconName::ZedPredictUp)
 9116                        },
 9117                    )
 9118                    .child(Label::new("Jump to Edit")),
 9119            ),
 9120
 9121            InlineCompletion::Edit {
 9122                edits,
 9123                edit_preview,
 9124                snapshot,
 9125                display_mode: _,
 9126            } => {
 9127                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9128
 9129                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 9130                    &snapshot,
 9131                    &edits,
 9132                    edit_preview.as_ref()?,
 9133                    true,
 9134                    cx,
 9135                )
 9136                .first_line_preview();
 9137
 9138                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9139                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9140
 9141                let preview = h_flex()
 9142                    .gap_1()
 9143                    .min_w_16()
 9144                    .child(styled_text)
 9145                    .when(has_more_lines, |parent| parent.child(""));
 9146
 9147                let left = if first_edit_row != cursor_point.row {
 9148                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9149                        .into_any_element()
 9150                } else {
 9151                    Icon::new(IconName::ZedPredict).into_any_element()
 9152                };
 9153
 9154                Some(
 9155                    h_flex()
 9156                        .h_full()
 9157                        .flex_1()
 9158                        .gap_2()
 9159                        .pr_1()
 9160                        .overflow_x_hidden()
 9161                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9162                        .child(left)
 9163                        .child(preview),
 9164                )
 9165            }
 9166        }
 9167    }
 9168
 9169    pub fn render_context_menu(
 9170        &self,
 9171        style: &EditorStyle,
 9172        max_height_in_lines: u32,
 9173        window: &mut Window,
 9174        cx: &mut Context<Editor>,
 9175    ) -> Option<AnyElement> {
 9176        let menu = self.context_menu.borrow();
 9177        let menu = menu.as_ref()?;
 9178        if !menu.visible() {
 9179            return None;
 9180        };
 9181        Some(menu.render(style, max_height_in_lines, window, cx))
 9182    }
 9183
 9184    fn render_context_menu_aside(
 9185        &mut self,
 9186        max_size: Size<Pixels>,
 9187        window: &mut Window,
 9188        cx: &mut Context<Editor>,
 9189    ) -> Option<AnyElement> {
 9190        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9191            if menu.visible() {
 9192                menu.render_aside(max_size, window, cx)
 9193            } else {
 9194                None
 9195            }
 9196        })
 9197    }
 9198
 9199    fn hide_context_menu(
 9200        &mut self,
 9201        window: &mut Window,
 9202        cx: &mut Context<Self>,
 9203    ) -> Option<CodeContextMenu> {
 9204        cx.notify();
 9205        self.completion_tasks.clear();
 9206        let context_menu = self.context_menu.borrow_mut().take();
 9207        self.stale_inline_completion_in_menu.take();
 9208        self.update_visible_inline_completion(window, cx);
 9209        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9210            if let Some(completion_provider) = &self.completion_provider {
 9211                completion_provider.selection_changed(None, window, cx);
 9212            }
 9213        }
 9214        context_menu
 9215    }
 9216
 9217    fn show_snippet_choices(
 9218        &mut self,
 9219        choices: &Vec<String>,
 9220        selection: Range<Anchor>,
 9221        cx: &mut Context<Self>,
 9222    ) {
 9223        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9224            (Some(a), Some(b)) if a == b => a,
 9225            _ => {
 9226                log::error!("expected anchor range to have matching buffer IDs");
 9227                return;
 9228            }
 9229        };
 9230        let multi_buffer = self.buffer().read(cx);
 9231        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9232            return;
 9233        };
 9234
 9235        let id = post_inc(&mut self.next_completion_id);
 9236        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9237        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9238            CompletionsMenu::new_snippet_choices(
 9239                id,
 9240                true,
 9241                choices,
 9242                selection,
 9243                buffer,
 9244                snippet_sort_order,
 9245            ),
 9246        ));
 9247    }
 9248
 9249    pub fn insert_snippet(
 9250        &mut self,
 9251        insertion_ranges: &[Range<usize>],
 9252        snippet: Snippet,
 9253        window: &mut Window,
 9254        cx: &mut Context<Self>,
 9255    ) -> Result<()> {
 9256        struct Tabstop<T> {
 9257            is_end_tabstop: bool,
 9258            ranges: Vec<Range<T>>,
 9259            choices: Option<Vec<String>>,
 9260        }
 9261
 9262        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9263            let snippet_text: Arc<str> = snippet.text.clone().into();
 9264            let edits = insertion_ranges
 9265                .iter()
 9266                .cloned()
 9267                .map(|range| (range, snippet_text.clone()));
 9268            let autoindent_mode = AutoindentMode::Block {
 9269                original_indent_columns: Vec::new(),
 9270            };
 9271            buffer.edit(edits, Some(autoindent_mode), cx);
 9272
 9273            let snapshot = &*buffer.read(cx);
 9274            let snippet = &snippet;
 9275            snippet
 9276                .tabstops
 9277                .iter()
 9278                .map(|tabstop| {
 9279                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9280                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9281                    });
 9282                    let mut tabstop_ranges = tabstop
 9283                        .ranges
 9284                        .iter()
 9285                        .flat_map(|tabstop_range| {
 9286                            let mut delta = 0_isize;
 9287                            insertion_ranges.iter().map(move |insertion_range| {
 9288                                let insertion_start = insertion_range.start as isize + delta;
 9289                                delta +=
 9290                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9291
 9292                                let start = ((insertion_start + tabstop_range.start) as usize)
 9293                                    .min(snapshot.len());
 9294                                let end = ((insertion_start + tabstop_range.end) as usize)
 9295                                    .min(snapshot.len());
 9296                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9297                            })
 9298                        })
 9299                        .collect::<Vec<_>>();
 9300                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9301
 9302                    Tabstop {
 9303                        is_end_tabstop,
 9304                        ranges: tabstop_ranges,
 9305                        choices: tabstop.choices.clone(),
 9306                    }
 9307                })
 9308                .collect::<Vec<_>>()
 9309        });
 9310        if let Some(tabstop) = tabstops.first() {
 9311            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9312                // Reverse order so that the first range is the newest created selection.
 9313                // Completions will use it and autoscroll will prioritize it.
 9314                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9315            });
 9316
 9317            if let Some(choices) = &tabstop.choices {
 9318                if let Some(selection) = tabstop.ranges.first() {
 9319                    self.show_snippet_choices(choices, selection.clone(), cx)
 9320                }
 9321            }
 9322
 9323            // If we're already at the last tabstop and it's at the end of the snippet,
 9324            // we're done, we don't need to keep the state around.
 9325            if !tabstop.is_end_tabstop {
 9326                let choices = tabstops
 9327                    .iter()
 9328                    .map(|tabstop| tabstop.choices.clone())
 9329                    .collect();
 9330
 9331                let ranges = tabstops
 9332                    .into_iter()
 9333                    .map(|tabstop| tabstop.ranges)
 9334                    .collect::<Vec<_>>();
 9335
 9336                self.snippet_stack.push(SnippetState {
 9337                    active_index: 0,
 9338                    ranges,
 9339                    choices,
 9340                });
 9341            }
 9342
 9343            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9344            if self.autoclose_regions.is_empty() {
 9345                let snapshot = self.buffer.read(cx).snapshot(cx);
 9346                for selection in &mut self.selections.all::<Point>(cx) {
 9347                    let selection_head = selection.head();
 9348                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9349                        continue;
 9350                    };
 9351
 9352                    let mut bracket_pair = None;
 9353                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9354                    let prev_chars = snapshot
 9355                        .reversed_chars_at(selection_head)
 9356                        .collect::<String>();
 9357                    for (pair, enabled) in scope.brackets() {
 9358                        if enabled
 9359                            && pair.close
 9360                            && prev_chars.starts_with(pair.start.as_str())
 9361                            && next_chars.starts_with(pair.end.as_str())
 9362                        {
 9363                            bracket_pair = Some(pair.clone());
 9364                            break;
 9365                        }
 9366                    }
 9367                    if let Some(pair) = bracket_pair {
 9368                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9369                        let autoclose_enabled =
 9370                            self.use_autoclose && snapshot_settings.use_autoclose;
 9371                        if autoclose_enabled {
 9372                            let start = snapshot.anchor_after(selection_head);
 9373                            let end = snapshot.anchor_after(selection_head);
 9374                            self.autoclose_regions.push(AutocloseRegion {
 9375                                selection_id: selection.id,
 9376                                range: start..end,
 9377                                pair,
 9378                            });
 9379                        }
 9380                    }
 9381                }
 9382            }
 9383        }
 9384        Ok(())
 9385    }
 9386
 9387    pub fn move_to_next_snippet_tabstop(
 9388        &mut self,
 9389        window: &mut Window,
 9390        cx: &mut Context<Self>,
 9391    ) -> bool {
 9392        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9393    }
 9394
 9395    pub fn move_to_prev_snippet_tabstop(
 9396        &mut self,
 9397        window: &mut Window,
 9398        cx: &mut Context<Self>,
 9399    ) -> bool {
 9400        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9401    }
 9402
 9403    pub fn move_to_snippet_tabstop(
 9404        &mut self,
 9405        bias: Bias,
 9406        window: &mut Window,
 9407        cx: &mut Context<Self>,
 9408    ) -> bool {
 9409        if let Some(mut snippet) = self.snippet_stack.pop() {
 9410            match bias {
 9411                Bias::Left => {
 9412                    if snippet.active_index > 0 {
 9413                        snippet.active_index -= 1;
 9414                    } else {
 9415                        self.snippet_stack.push(snippet);
 9416                        return false;
 9417                    }
 9418                }
 9419                Bias::Right => {
 9420                    if snippet.active_index + 1 < snippet.ranges.len() {
 9421                        snippet.active_index += 1;
 9422                    } else {
 9423                        self.snippet_stack.push(snippet);
 9424                        return false;
 9425                    }
 9426                }
 9427            }
 9428            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9429                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9430                    // Reverse order so that the first range is the newest created selection.
 9431                    // Completions will use it and autoscroll will prioritize it.
 9432                    s.select_ranges(current_ranges.iter().rev().cloned())
 9433                });
 9434
 9435                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9436                    if let Some(selection) = current_ranges.first() {
 9437                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9438                    }
 9439                }
 9440
 9441                // If snippet state is not at the last tabstop, push it back on the stack
 9442                if snippet.active_index + 1 < snippet.ranges.len() {
 9443                    self.snippet_stack.push(snippet);
 9444                }
 9445                return true;
 9446            }
 9447        }
 9448
 9449        false
 9450    }
 9451
 9452    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9453        self.transact(window, cx, |this, window, cx| {
 9454            this.select_all(&SelectAll, window, cx);
 9455            this.insert("", window, cx);
 9456        });
 9457    }
 9458
 9459    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9460        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9461        self.transact(window, cx, |this, window, cx| {
 9462            this.select_autoclose_pair(window, cx);
 9463            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9464            if !this.linked_edit_ranges.is_empty() {
 9465                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9466                let snapshot = this.buffer.read(cx).snapshot(cx);
 9467
 9468                for selection in selections.iter() {
 9469                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9470                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9471                    if selection_start.buffer_id != selection_end.buffer_id {
 9472                        continue;
 9473                    }
 9474                    if let Some(ranges) =
 9475                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9476                    {
 9477                        for (buffer, entries) in ranges {
 9478                            linked_ranges.entry(buffer).or_default().extend(entries);
 9479                        }
 9480                    }
 9481                }
 9482            }
 9483
 9484            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9485            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9486            for selection in &mut selections {
 9487                if selection.is_empty() {
 9488                    let old_head = selection.head();
 9489                    let mut new_head =
 9490                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9491                            .to_point(&display_map);
 9492                    if let Some((buffer, line_buffer_range)) = display_map
 9493                        .buffer_snapshot
 9494                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9495                    {
 9496                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9497                        let indent_len = match indent_size.kind {
 9498                            IndentKind::Space => {
 9499                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9500                            }
 9501                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9502                        };
 9503                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9504                            let indent_len = indent_len.get();
 9505                            new_head = cmp::min(
 9506                                new_head,
 9507                                MultiBufferPoint::new(
 9508                                    old_head.row,
 9509                                    ((old_head.column - 1) / indent_len) * indent_len,
 9510                                ),
 9511                            );
 9512                        }
 9513                    }
 9514
 9515                    selection.set_head(new_head, SelectionGoal::None);
 9516                }
 9517            }
 9518
 9519            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9520                s.select(selections)
 9521            });
 9522            this.insert("", window, cx);
 9523            let empty_str: Arc<str> = Arc::from("");
 9524            for (buffer, edits) in linked_ranges {
 9525                let snapshot = buffer.read(cx).snapshot();
 9526                use text::ToPoint as TP;
 9527
 9528                let edits = edits
 9529                    .into_iter()
 9530                    .map(|range| {
 9531                        let end_point = TP::to_point(&range.end, &snapshot);
 9532                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9533
 9534                        if end_point == start_point {
 9535                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9536                                .saturating_sub(1);
 9537                            start_point =
 9538                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9539                        };
 9540
 9541                        (start_point..end_point, empty_str.clone())
 9542                    })
 9543                    .sorted_by_key(|(range, _)| range.start)
 9544                    .collect::<Vec<_>>();
 9545                buffer.update(cx, |this, cx| {
 9546                    this.edit(edits, None, cx);
 9547                })
 9548            }
 9549            this.refresh_inline_completion(true, false, window, cx);
 9550            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9551        });
 9552    }
 9553
 9554    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9555        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9556        self.transact(window, cx, |this, window, cx| {
 9557            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9558                s.move_with(|map, selection| {
 9559                    if selection.is_empty() {
 9560                        let cursor = movement::right(map, selection.head());
 9561                        selection.end = cursor;
 9562                        selection.reversed = true;
 9563                        selection.goal = SelectionGoal::None;
 9564                    }
 9565                })
 9566            });
 9567            this.insert("", window, cx);
 9568            this.refresh_inline_completion(true, false, window, cx);
 9569        });
 9570    }
 9571
 9572    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9573        if self.mode.is_single_line() {
 9574            cx.propagate();
 9575            return;
 9576        }
 9577
 9578        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9579        if self.move_to_prev_snippet_tabstop(window, cx) {
 9580            return;
 9581        }
 9582        self.outdent(&Outdent, window, cx);
 9583    }
 9584
 9585    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9586        if self.mode.is_single_line() {
 9587            cx.propagate();
 9588            return;
 9589        }
 9590
 9591        if self.move_to_next_snippet_tabstop(window, cx) {
 9592            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9593            return;
 9594        }
 9595        if self.read_only(cx) {
 9596            return;
 9597        }
 9598        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9599        let mut selections = self.selections.all_adjusted(cx);
 9600        let buffer = self.buffer.read(cx);
 9601        let snapshot = buffer.snapshot(cx);
 9602        let rows_iter = selections.iter().map(|s| s.head().row);
 9603        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9604
 9605        let has_some_cursor_in_whitespace = selections
 9606            .iter()
 9607            .filter(|selection| selection.is_empty())
 9608            .any(|selection| {
 9609                let cursor = selection.head();
 9610                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9611                cursor.column < current_indent.len
 9612            });
 9613
 9614        let mut edits = Vec::new();
 9615        let mut prev_edited_row = 0;
 9616        let mut row_delta = 0;
 9617        for selection in &mut selections {
 9618            if selection.start.row != prev_edited_row {
 9619                row_delta = 0;
 9620            }
 9621            prev_edited_row = selection.end.row;
 9622
 9623            // If the selection is non-empty, then increase the indentation of the selected lines.
 9624            if !selection.is_empty() {
 9625                row_delta =
 9626                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9627                continue;
 9628            }
 9629
 9630            let cursor = selection.head();
 9631            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9632            if let Some(suggested_indent) =
 9633                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9634            {
 9635                // Don't do anything if already at suggested indent
 9636                // and there is any other cursor which is not
 9637                if has_some_cursor_in_whitespace
 9638                    && cursor.column == current_indent.len
 9639                    && current_indent.len == suggested_indent.len
 9640                {
 9641                    continue;
 9642                }
 9643
 9644                // Adjust line and move cursor to suggested indent
 9645                // if cursor is not at suggested indent
 9646                if cursor.column < suggested_indent.len
 9647                    && cursor.column <= current_indent.len
 9648                    && current_indent.len <= suggested_indent.len
 9649                {
 9650                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9651                    selection.end = selection.start;
 9652                    if row_delta == 0 {
 9653                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9654                            cursor.row,
 9655                            current_indent,
 9656                            suggested_indent,
 9657                        ));
 9658                        row_delta = suggested_indent.len - current_indent.len;
 9659                    }
 9660                    continue;
 9661                }
 9662
 9663                // If current indent is more than suggested indent
 9664                // only move cursor to current indent and skip indent
 9665                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9666                    selection.start = Point::new(cursor.row, current_indent.len);
 9667                    selection.end = selection.start;
 9668                    continue;
 9669                }
 9670            }
 9671
 9672            // Otherwise, insert a hard or soft tab.
 9673            let settings = buffer.language_settings_at(cursor, cx);
 9674            let tab_size = if settings.hard_tabs {
 9675                IndentSize::tab()
 9676            } else {
 9677                let tab_size = settings.tab_size.get();
 9678                let indent_remainder = snapshot
 9679                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9680                    .flat_map(str::chars)
 9681                    .fold(row_delta % tab_size, |counter: u32, c| {
 9682                        if c == '\t' {
 9683                            0
 9684                        } else {
 9685                            (counter + 1) % tab_size
 9686                        }
 9687                    });
 9688
 9689                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9690                IndentSize::spaces(chars_to_next_tab_stop)
 9691            };
 9692            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9693            selection.end = selection.start;
 9694            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9695            row_delta += tab_size.len;
 9696        }
 9697
 9698        self.transact(window, cx, |this, window, cx| {
 9699            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9700            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9701                s.select(selections)
 9702            });
 9703            this.refresh_inline_completion(true, false, window, cx);
 9704        });
 9705    }
 9706
 9707    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9708        if self.read_only(cx) {
 9709            return;
 9710        }
 9711        if self.mode.is_single_line() {
 9712            cx.propagate();
 9713            return;
 9714        }
 9715
 9716        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9717        let mut selections = self.selections.all::<Point>(cx);
 9718        let mut prev_edited_row = 0;
 9719        let mut row_delta = 0;
 9720        let mut edits = Vec::new();
 9721        let buffer = self.buffer.read(cx);
 9722        let snapshot = buffer.snapshot(cx);
 9723        for selection in &mut selections {
 9724            if selection.start.row != prev_edited_row {
 9725                row_delta = 0;
 9726            }
 9727            prev_edited_row = selection.end.row;
 9728
 9729            row_delta =
 9730                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9731        }
 9732
 9733        self.transact(window, cx, |this, window, cx| {
 9734            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9735            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9736                s.select(selections)
 9737            });
 9738        });
 9739    }
 9740
 9741    fn indent_selection(
 9742        buffer: &MultiBuffer,
 9743        snapshot: &MultiBufferSnapshot,
 9744        selection: &mut Selection<Point>,
 9745        edits: &mut Vec<(Range<Point>, String)>,
 9746        delta_for_start_row: u32,
 9747        cx: &App,
 9748    ) -> u32 {
 9749        let settings = buffer.language_settings_at(selection.start, cx);
 9750        let tab_size = settings.tab_size.get();
 9751        let indent_kind = if settings.hard_tabs {
 9752            IndentKind::Tab
 9753        } else {
 9754            IndentKind::Space
 9755        };
 9756        let mut start_row = selection.start.row;
 9757        let mut end_row = selection.end.row + 1;
 9758
 9759        // If a selection ends at the beginning of a line, don't indent
 9760        // that last line.
 9761        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9762            end_row -= 1;
 9763        }
 9764
 9765        // Avoid re-indenting a row that has already been indented by a
 9766        // previous selection, but still update this selection's column
 9767        // to reflect that indentation.
 9768        if delta_for_start_row > 0 {
 9769            start_row += 1;
 9770            selection.start.column += delta_for_start_row;
 9771            if selection.end.row == selection.start.row {
 9772                selection.end.column += delta_for_start_row;
 9773            }
 9774        }
 9775
 9776        let mut delta_for_end_row = 0;
 9777        let has_multiple_rows = start_row + 1 != end_row;
 9778        for row in start_row..end_row {
 9779            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9780            let indent_delta = match (current_indent.kind, indent_kind) {
 9781                (IndentKind::Space, IndentKind::Space) => {
 9782                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9783                    IndentSize::spaces(columns_to_next_tab_stop)
 9784                }
 9785                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9786                (_, IndentKind::Tab) => IndentSize::tab(),
 9787            };
 9788
 9789            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9790                0
 9791            } else {
 9792                selection.start.column
 9793            };
 9794            let row_start = Point::new(row, start);
 9795            edits.push((
 9796                row_start..row_start,
 9797                indent_delta.chars().collect::<String>(),
 9798            ));
 9799
 9800            // Update this selection's endpoints to reflect the indentation.
 9801            if row == selection.start.row {
 9802                selection.start.column += indent_delta.len;
 9803            }
 9804            if row == selection.end.row {
 9805                selection.end.column += indent_delta.len;
 9806                delta_for_end_row = indent_delta.len;
 9807            }
 9808        }
 9809
 9810        if selection.start.row == selection.end.row {
 9811            delta_for_start_row + delta_for_end_row
 9812        } else {
 9813            delta_for_end_row
 9814        }
 9815    }
 9816
 9817    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9818        if self.read_only(cx) {
 9819            return;
 9820        }
 9821        if self.mode.is_single_line() {
 9822            cx.propagate();
 9823            return;
 9824        }
 9825
 9826        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9827        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9828        let selections = self.selections.all::<Point>(cx);
 9829        let mut deletion_ranges = Vec::new();
 9830        let mut last_outdent = None;
 9831        {
 9832            let buffer = self.buffer.read(cx);
 9833            let snapshot = buffer.snapshot(cx);
 9834            for selection in &selections {
 9835                let settings = buffer.language_settings_at(selection.start, cx);
 9836                let tab_size = settings.tab_size.get();
 9837                let mut rows = selection.spanned_rows(false, &display_map);
 9838
 9839                // Avoid re-outdenting a row that has already been outdented by a
 9840                // previous selection.
 9841                if let Some(last_row) = last_outdent {
 9842                    if last_row == rows.start {
 9843                        rows.start = rows.start.next_row();
 9844                    }
 9845                }
 9846                let has_multiple_rows = rows.len() > 1;
 9847                for row in rows.iter_rows() {
 9848                    let indent_size = snapshot.indent_size_for_line(row);
 9849                    if indent_size.len > 0 {
 9850                        let deletion_len = match indent_size.kind {
 9851                            IndentKind::Space => {
 9852                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9853                                if columns_to_prev_tab_stop == 0 {
 9854                                    tab_size
 9855                                } else {
 9856                                    columns_to_prev_tab_stop
 9857                                }
 9858                            }
 9859                            IndentKind::Tab => 1,
 9860                        };
 9861                        let start = if has_multiple_rows
 9862                            || deletion_len > selection.start.column
 9863                            || indent_size.len < selection.start.column
 9864                        {
 9865                            0
 9866                        } else {
 9867                            selection.start.column - deletion_len
 9868                        };
 9869                        deletion_ranges.push(
 9870                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9871                        );
 9872                        last_outdent = Some(row);
 9873                    }
 9874                }
 9875            }
 9876        }
 9877
 9878        self.transact(window, cx, |this, window, cx| {
 9879            this.buffer.update(cx, |buffer, cx| {
 9880                let empty_str: Arc<str> = Arc::default();
 9881                buffer.edit(
 9882                    deletion_ranges
 9883                        .into_iter()
 9884                        .map(|range| (range, empty_str.clone())),
 9885                    None,
 9886                    cx,
 9887                );
 9888            });
 9889            let selections = this.selections.all::<usize>(cx);
 9890            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9891                s.select(selections)
 9892            });
 9893        });
 9894    }
 9895
 9896    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9897        if self.read_only(cx) {
 9898            return;
 9899        }
 9900        if self.mode.is_single_line() {
 9901            cx.propagate();
 9902            return;
 9903        }
 9904
 9905        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9906        let selections = self
 9907            .selections
 9908            .all::<usize>(cx)
 9909            .into_iter()
 9910            .map(|s| s.range());
 9911
 9912        self.transact(window, cx, |this, window, cx| {
 9913            this.buffer.update(cx, |buffer, cx| {
 9914                buffer.autoindent_ranges(selections, cx);
 9915            });
 9916            let selections = this.selections.all::<usize>(cx);
 9917            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9918                s.select(selections)
 9919            });
 9920        });
 9921    }
 9922
 9923    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9924        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9925        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9926        let selections = self.selections.all::<Point>(cx);
 9927
 9928        let mut new_cursors = Vec::new();
 9929        let mut edit_ranges = Vec::new();
 9930        let mut selections = selections.iter().peekable();
 9931        while let Some(selection) = selections.next() {
 9932            let mut rows = selection.spanned_rows(false, &display_map);
 9933            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9934
 9935            // Accumulate contiguous regions of rows that we want to delete.
 9936            while let Some(next_selection) = selections.peek() {
 9937                let next_rows = next_selection.spanned_rows(false, &display_map);
 9938                if next_rows.start <= rows.end {
 9939                    rows.end = next_rows.end;
 9940                    selections.next().unwrap();
 9941                } else {
 9942                    break;
 9943                }
 9944            }
 9945
 9946            let buffer = &display_map.buffer_snapshot;
 9947            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9948            let edit_end;
 9949            let cursor_buffer_row;
 9950            if buffer.max_point().row >= rows.end.0 {
 9951                // If there's a line after the range, delete the \n from the end of the row range
 9952                // and position the cursor on the next line.
 9953                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9954                cursor_buffer_row = rows.end;
 9955            } else {
 9956                // If there isn't a line after the range, delete the \n from the line before the
 9957                // start of the row range and position the cursor there.
 9958                edit_start = edit_start.saturating_sub(1);
 9959                edit_end = buffer.len();
 9960                cursor_buffer_row = rows.start.previous_row();
 9961            }
 9962
 9963            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9964            *cursor.column_mut() =
 9965                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9966
 9967            new_cursors.push((
 9968                selection.id,
 9969                buffer.anchor_after(cursor.to_point(&display_map)),
 9970            ));
 9971            edit_ranges.push(edit_start..edit_end);
 9972        }
 9973
 9974        self.transact(window, cx, |this, window, cx| {
 9975            let buffer = this.buffer.update(cx, |buffer, cx| {
 9976                let empty_str: Arc<str> = Arc::default();
 9977                buffer.edit(
 9978                    edit_ranges
 9979                        .into_iter()
 9980                        .map(|range| (range, empty_str.clone())),
 9981                    None,
 9982                    cx,
 9983                );
 9984                buffer.snapshot(cx)
 9985            });
 9986            let new_selections = new_cursors
 9987                .into_iter()
 9988                .map(|(id, cursor)| {
 9989                    let cursor = cursor.to_point(&buffer);
 9990                    Selection {
 9991                        id,
 9992                        start: cursor,
 9993                        end: cursor,
 9994                        reversed: false,
 9995                        goal: SelectionGoal::None,
 9996                    }
 9997                })
 9998                .collect();
 9999
10000            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10001                s.select(new_selections);
10002            });
10003        });
10004    }
10005
10006    pub fn join_lines_impl(
10007        &mut self,
10008        insert_whitespace: bool,
10009        window: &mut Window,
10010        cx: &mut Context<Self>,
10011    ) {
10012        if self.read_only(cx) {
10013            return;
10014        }
10015        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10016        for selection in self.selections.all::<Point>(cx) {
10017            let start = MultiBufferRow(selection.start.row);
10018            // Treat single line selections as if they include the next line. Otherwise this action
10019            // would do nothing for single line selections individual cursors.
10020            let end = if selection.start.row == selection.end.row {
10021                MultiBufferRow(selection.start.row + 1)
10022            } else {
10023                MultiBufferRow(selection.end.row)
10024            };
10025
10026            if let Some(last_row_range) = row_ranges.last_mut() {
10027                if start <= last_row_range.end {
10028                    last_row_range.end = end;
10029                    continue;
10030                }
10031            }
10032            row_ranges.push(start..end);
10033        }
10034
10035        let snapshot = self.buffer.read(cx).snapshot(cx);
10036        let mut cursor_positions = Vec::new();
10037        for row_range in &row_ranges {
10038            let anchor = snapshot.anchor_before(Point::new(
10039                row_range.end.previous_row().0,
10040                snapshot.line_len(row_range.end.previous_row()),
10041            ));
10042            cursor_positions.push(anchor..anchor);
10043        }
10044
10045        self.transact(window, cx, |this, window, cx| {
10046            for row_range in row_ranges.into_iter().rev() {
10047                for row in row_range.iter_rows().rev() {
10048                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10049                    let next_line_row = row.next_row();
10050                    let indent = snapshot.indent_size_for_line(next_line_row);
10051                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10052
10053                    let replace =
10054                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10055                            " "
10056                        } else {
10057                            ""
10058                        };
10059
10060                    this.buffer.update(cx, |buffer, cx| {
10061                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10062                    });
10063                }
10064            }
10065
10066            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10067                s.select_anchor_ranges(cursor_positions)
10068            });
10069        });
10070    }
10071
10072    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10073        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10074        self.join_lines_impl(true, window, cx);
10075    }
10076
10077    pub fn sort_lines_case_sensitive(
10078        &mut self,
10079        _: &SortLinesCaseSensitive,
10080        window: &mut Window,
10081        cx: &mut Context<Self>,
10082    ) {
10083        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10084    }
10085
10086    pub fn sort_lines_case_insensitive(
10087        &mut self,
10088        _: &SortLinesCaseInsensitive,
10089        window: &mut Window,
10090        cx: &mut Context<Self>,
10091    ) {
10092        self.manipulate_immutable_lines(window, cx, |lines| {
10093            lines.sort_by_key(|line| line.to_lowercase())
10094        })
10095    }
10096
10097    pub fn unique_lines_case_insensitive(
10098        &mut self,
10099        _: &UniqueLinesCaseInsensitive,
10100        window: &mut Window,
10101        cx: &mut Context<Self>,
10102    ) {
10103        self.manipulate_immutable_lines(window, cx, |lines| {
10104            let mut seen = HashSet::default();
10105            lines.retain(|line| seen.insert(line.to_lowercase()));
10106        })
10107    }
10108
10109    pub fn unique_lines_case_sensitive(
10110        &mut self,
10111        _: &UniqueLinesCaseSensitive,
10112        window: &mut Window,
10113        cx: &mut Context<Self>,
10114    ) {
10115        self.manipulate_immutable_lines(window, cx, |lines| {
10116            let mut seen = HashSet::default();
10117            lines.retain(|line| seen.insert(*line));
10118        })
10119    }
10120
10121    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10122        let Some(project) = self.project.clone() else {
10123            return;
10124        };
10125        self.reload(project, window, cx)
10126            .detach_and_notify_err(window, cx);
10127    }
10128
10129    pub fn restore_file(
10130        &mut self,
10131        _: &::git::RestoreFile,
10132        window: &mut Window,
10133        cx: &mut Context<Self>,
10134    ) {
10135        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10136        let mut buffer_ids = HashSet::default();
10137        let snapshot = self.buffer().read(cx).snapshot(cx);
10138        for selection in self.selections.all::<usize>(cx) {
10139            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10140        }
10141
10142        let buffer = self.buffer().read(cx);
10143        let ranges = buffer_ids
10144            .into_iter()
10145            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10146            .collect::<Vec<_>>();
10147
10148        self.restore_hunks_in_ranges(ranges, window, cx);
10149    }
10150
10151    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10152        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10153        let selections = self
10154            .selections
10155            .all(cx)
10156            .into_iter()
10157            .map(|s| s.range())
10158            .collect();
10159        self.restore_hunks_in_ranges(selections, window, cx);
10160    }
10161
10162    pub fn restore_hunks_in_ranges(
10163        &mut self,
10164        ranges: Vec<Range<Point>>,
10165        window: &mut Window,
10166        cx: &mut Context<Editor>,
10167    ) {
10168        let mut revert_changes = HashMap::default();
10169        let chunk_by = self
10170            .snapshot(window, cx)
10171            .hunks_for_ranges(ranges)
10172            .into_iter()
10173            .chunk_by(|hunk| hunk.buffer_id);
10174        for (buffer_id, hunks) in &chunk_by {
10175            let hunks = hunks.collect::<Vec<_>>();
10176            for hunk in &hunks {
10177                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10178            }
10179            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10180        }
10181        drop(chunk_by);
10182        if !revert_changes.is_empty() {
10183            self.transact(window, cx, |editor, window, cx| {
10184                editor.restore(revert_changes, window, cx);
10185            });
10186        }
10187    }
10188
10189    pub fn open_active_item_in_terminal(
10190        &mut self,
10191        _: &OpenInTerminal,
10192        window: &mut Window,
10193        cx: &mut Context<Self>,
10194    ) {
10195        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10196            let project_path = buffer.read(cx).project_path(cx)?;
10197            let project = self.project.as_ref()?.read(cx);
10198            let entry = project.entry_for_path(&project_path, cx)?;
10199            let parent = match &entry.canonical_path {
10200                Some(canonical_path) => canonical_path.to_path_buf(),
10201                None => project.absolute_path(&project_path, cx)?,
10202            }
10203            .parent()?
10204            .to_path_buf();
10205            Some(parent)
10206        }) {
10207            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10208        }
10209    }
10210
10211    fn set_breakpoint_context_menu(
10212        &mut self,
10213        display_row: DisplayRow,
10214        position: Option<Anchor>,
10215        clicked_point: gpui::Point<Pixels>,
10216        window: &mut Window,
10217        cx: &mut Context<Self>,
10218    ) {
10219        let source = self
10220            .buffer
10221            .read(cx)
10222            .snapshot(cx)
10223            .anchor_before(Point::new(display_row.0, 0u32));
10224
10225        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10226
10227        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10228            self,
10229            source,
10230            clicked_point,
10231            context_menu,
10232            window,
10233            cx,
10234        );
10235    }
10236
10237    fn add_edit_breakpoint_block(
10238        &mut self,
10239        anchor: Anchor,
10240        breakpoint: &Breakpoint,
10241        edit_action: BreakpointPromptEditAction,
10242        window: &mut Window,
10243        cx: &mut Context<Self>,
10244    ) {
10245        let weak_editor = cx.weak_entity();
10246        let bp_prompt = cx.new(|cx| {
10247            BreakpointPromptEditor::new(
10248                weak_editor,
10249                anchor,
10250                breakpoint.clone(),
10251                edit_action,
10252                window,
10253                cx,
10254            )
10255        });
10256
10257        let height = bp_prompt.update(cx, |this, cx| {
10258            this.prompt
10259                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10260        });
10261        let cloned_prompt = bp_prompt.clone();
10262        let blocks = vec![BlockProperties {
10263            style: BlockStyle::Sticky,
10264            placement: BlockPlacement::Above(anchor),
10265            height: Some(height),
10266            render: Arc::new(move |cx| {
10267                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10268                cloned_prompt.clone().into_any_element()
10269            }),
10270            priority: 0,
10271            render_in_minimap: true,
10272        }];
10273
10274        let focus_handle = bp_prompt.focus_handle(cx);
10275        window.focus(&focus_handle);
10276
10277        let block_ids = self.insert_blocks(blocks, None, cx);
10278        bp_prompt.update(cx, |prompt, _| {
10279            prompt.add_block_ids(block_ids);
10280        });
10281    }
10282
10283    pub(crate) fn breakpoint_at_row(
10284        &self,
10285        row: u32,
10286        window: &mut Window,
10287        cx: &mut Context<Self>,
10288    ) -> Option<(Anchor, Breakpoint)> {
10289        let snapshot = self.snapshot(window, cx);
10290        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10291
10292        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10293    }
10294
10295    pub(crate) fn breakpoint_at_anchor(
10296        &self,
10297        breakpoint_position: Anchor,
10298        snapshot: &EditorSnapshot,
10299        cx: &mut Context<Self>,
10300    ) -> Option<(Anchor, Breakpoint)> {
10301        let project = self.project.clone()?;
10302
10303        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10304            snapshot
10305                .buffer_snapshot
10306                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10307        })?;
10308
10309        let enclosing_excerpt = breakpoint_position.excerpt_id;
10310        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10311        let buffer_snapshot = buffer.read(cx).snapshot();
10312
10313        let row = buffer_snapshot
10314            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10315            .row;
10316
10317        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10318        let anchor_end = snapshot
10319            .buffer_snapshot
10320            .anchor_after(Point::new(row, line_len));
10321
10322        let bp = self
10323            .breakpoint_store
10324            .as_ref()?
10325            .read_with(cx, |breakpoint_store, cx| {
10326                breakpoint_store
10327                    .breakpoints(
10328                        &buffer,
10329                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10330                        &buffer_snapshot,
10331                        cx,
10332                    )
10333                    .next()
10334                    .and_then(|(bp, _)| {
10335                        let breakpoint_row = buffer_snapshot
10336                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10337                            .row;
10338
10339                        if breakpoint_row == row {
10340                            snapshot
10341                                .buffer_snapshot
10342                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10343                                .map(|position| (position, bp.bp.clone()))
10344                        } else {
10345                            None
10346                        }
10347                    })
10348            });
10349        bp
10350    }
10351
10352    pub fn edit_log_breakpoint(
10353        &mut self,
10354        _: &EditLogBreakpoint,
10355        window: &mut Window,
10356        cx: &mut Context<Self>,
10357    ) {
10358        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10359            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10360                message: None,
10361                state: BreakpointState::Enabled,
10362                condition: None,
10363                hit_condition: None,
10364            });
10365
10366            self.add_edit_breakpoint_block(
10367                anchor,
10368                &breakpoint,
10369                BreakpointPromptEditAction::Log,
10370                window,
10371                cx,
10372            );
10373        }
10374    }
10375
10376    fn breakpoints_at_cursors(
10377        &self,
10378        window: &mut Window,
10379        cx: &mut Context<Self>,
10380    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10381        let snapshot = self.snapshot(window, cx);
10382        let cursors = self
10383            .selections
10384            .disjoint_anchors()
10385            .into_iter()
10386            .map(|selection| {
10387                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10388
10389                let breakpoint_position = self
10390                    .breakpoint_at_row(cursor_position.row, window, cx)
10391                    .map(|bp| bp.0)
10392                    .unwrap_or_else(|| {
10393                        snapshot
10394                            .display_snapshot
10395                            .buffer_snapshot
10396                            .anchor_after(Point::new(cursor_position.row, 0))
10397                    });
10398
10399                let breakpoint = self
10400                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10401                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10402
10403                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10404            })
10405            // 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.
10406            .collect::<HashMap<Anchor, _>>();
10407
10408        cursors.into_iter().collect()
10409    }
10410
10411    pub fn enable_breakpoint(
10412        &mut self,
10413        _: &crate::actions::EnableBreakpoint,
10414        window: &mut Window,
10415        cx: &mut Context<Self>,
10416    ) {
10417        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10418            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10419                continue;
10420            };
10421            self.edit_breakpoint_at_anchor(
10422                anchor,
10423                breakpoint,
10424                BreakpointEditAction::InvertState,
10425                cx,
10426            );
10427        }
10428    }
10429
10430    pub fn disable_breakpoint(
10431        &mut self,
10432        _: &crate::actions::DisableBreakpoint,
10433        window: &mut Window,
10434        cx: &mut Context<Self>,
10435    ) {
10436        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10437            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10438                continue;
10439            };
10440            self.edit_breakpoint_at_anchor(
10441                anchor,
10442                breakpoint,
10443                BreakpointEditAction::InvertState,
10444                cx,
10445            );
10446        }
10447    }
10448
10449    pub fn toggle_breakpoint(
10450        &mut self,
10451        _: &crate::actions::ToggleBreakpoint,
10452        window: &mut Window,
10453        cx: &mut Context<Self>,
10454    ) {
10455        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10456            if let Some(breakpoint) = breakpoint {
10457                self.edit_breakpoint_at_anchor(
10458                    anchor,
10459                    breakpoint,
10460                    BreakpointEditAction::Toggle,
10461                    cx,
10462                );
10463            } else {
10464                self.edit_breakpoint_at_anchor(
10465                    anchor,
10466                    Breakpoint::new_standard(),
10467                    BreakpointEditAction::Toggle,
10468                    cx,
10469                );
10470            }
10471        }
10472    }
10473
10474    pub fn edit_breakpoint_at_anchor(
10475        &mut self,
10476        breakpoint_position: Anchor,
10477        breakpoint: Breakpoint,
10478        edit_action: BreakpointEditAction,
10479        cx: &mut Context<Self>,
10480    ) {
10481        let Some(breakpoint_store) = &self.breakpoint_store else {
10482            return;
10483        };
10484
10485        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10486            if breakpoint_position == Anchor::min() {
10487                self.buffer()
10488                    .read(cx)
10489                    .excerpt_buffer_ids()
10490                    .into_iter()
10491                    .next()
10492            } else {
10493                None
10494            }
10495        }) else {
10496            return;
10497        };
10498
10499        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10500            return;
10501        };
10502
10503        breakpoint_store.update(cx, |breakpoint_store, cx| {
10504            breakpoint_store.toggle_breakpoint(
10505                buffer,
10506                BreakpointWithPosition {
10507                    position: breakpoint_position.text_anchor,
10508                    bp: breakpoint,
10509                },
10510                edit_action,
10511                cx,
10512            );
10513        });
10514
10515        cx.notify();
10516    }
10517
10518    #[cfg(any(test, feature = "test-support"))]
10519    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10520        self.breakpoint_store.clone()
10521    }
10522
10523    pub fn prepare_restore_change(
10524        &self,
10525        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10526        hunk: &MultiBufferDiffHunk,
10527        cx: &mut App,
10528    ) -> Option<()> {
10529        if hunk.is_created_file() {
10530            return None;
10531        }
10532        let buffer = self.buffer.read(cx);
10533        let diff = buffer.diff_for(hunk.buffer_id)?;
10534        let buffer = buffer.buffer(hunk.buffer_id)?;
10535        let buffer = buffer.read(cx);
10536        let original_text = diff
10537            .read(cx)
10538            .base_text()
10539            .as_rope()
10540            .slice(hunk.diff_base_byte_range.clone());
10541        let buffer_snapshot = buffer.snapshot();
10542        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10543        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10544            probe
10545                .0
10546                .start
10547                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10548                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10549        }) {
10550            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10551            Some(())
10552        } else {
10553            None
10554        }
10555    }
10556
10557    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10558        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10559    }
10560
10561    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10562        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10563    }
10564
10565    fn manipulate_lines<M>(
10566        &mut self,
10567        window: &mut Window,
10568        cx: &mut Context<Self>,
10569        mut manipulate: M,
10570    ) where
10571        M: FnMut(&str) -> LineManipulationResult,
10572    {
10573        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10574
10575        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10576        let buffer = self.buffer.read(cx).snapshot(cx);
10577
10578        let mut edits = Vec::new();
10579
10580        let selections = self.selections.all::<Point>(cx);
10581        let mut selections = selections.iter().peekable();
10582        let mut contiguous_row_selections = Vec::new();
10583        let mut new_selections = Vec::new();
10584        let mut added_lines = 0;
10585        let mut removed_lines = 0;
10586
10587        while let Some(selection) = selections.next() {
10588            let (start_row, end_row) = consume_contiguous_rows(
10589                &mut contiguous_row_selections,
10590                selection,
10591                &display_map,
10592                &mut selections,
10593            );
10594
10595            let start_point = Point::new(start_row.0, 0);
10596            let end_point = Point::new(
10597                end_row.previous_row().0,
10598                buffer.line_len(end_row.previous_row()),
10599            );
10600            let text = buffer
10601                .text_for_range(start_point..end_point)
10602                .collect::<String>();
10603
10604            let LineManipulationResult {
10605                new_text,
10606                line_count_before,
10607                line_count_after,
10608            } = manipulate(&text);
10609
10610            edits.push((start_point..end_point, new_text));
10611
10612            // Selections must change based on added and removed line count
10613            let start_row =
10614                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10615            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10616            new_selections.push(Selection {
10617                id: selection.id,
10618                start: start_row,
10619                end: end_row,
10620                goal: SelectionGoal::None,
10621                reversed: selection.reversed,
10622            });
10623
10624            if line_count_after > line_count_before {
10625                added_lines += line_count_after - line_count_before;
10626            } else if line_count_before > line_count_after {
10627                removed_lines += line_count_before - line_count_after;
10628            }
10629        }
10630
10631        self.transact(window, cx, |this, window, cx| {
10632            let buffer = this.buffer.update(cx, |buffer, cx| {
10633                buffer.edit(edits, None, cx);
10634                buffer.snapshot(cx)
10635            });
10636
10637            // Recalculate offsets on newly edited buffer
10638            let new_selections = new_selections
10639                .iter()
10640                .map(|s| {
10641                    let start_point = Point::new(s.start.0, 0);
10642                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10643                    Selection {
10644                        id: s.id,
10645                        start: buffer.point_to_offset(start_point),
10646                        end: buffer.point_to_offset(end_point),
10647                        goal: s.goal,
10648                        reversed: s.reversed,
10649                    }
10650                })
10651                .collect();
10652
10653            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10654                s.select(new_selections);
10655            });
10656
10657            this.request_autoscroll(Autoscroll::fit(), cx);
10658        });
10659    }
10660
10661    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10662        self.manipulate_text(window, cx, |text| {
10663            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10664            if has_upper_case_characters {
10665                text.to_lowercase()
10666            } else {
10667                text.to_uppercase()
10668            }
10669        })
10670    }
10671
10672    fn manipulate_immutable_lines<Fn>(
10673        &mut self,
10674        window: &mut Window,
10675        cx: &mut Context<Self>,
10676        mut callback: Fn,
10677    ) where
10678        Fn: FnMut(&mut Vec<&str>),
10679    {
10680        self.manipulate_lines(window, cx, |text| {
10681            let mut lines: Vec<&str> = text.split('\n').collect();
10682            let line_count_before = lines.len();
10683
10684            callback(&mut lines);
10685
10686            LineManipulationResult {
10687                new_text: lines.join("\n"),
10688                line_count_before,
10689                line_count_after: lines.len(),
10690            }
10691        });
10692    }
10693
10694    fn manipulate_mutable_lines<Fn>(
10695        &mut self,
10696        window: &mut Window,
10697        cx: &mut Context<Self>,
10698        mut callback: Fn,
10699    ) where
10700        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10701    {
10702        self.manipulate_lines(window, cx, |text| {
10703            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10704            let line_count_before = lines.len();
10705
10706            callback(&mut lines);
10707
10708            LineManipulationResult {
10709                new_text: lines.join("\n"),
10710                line_count_before,
10711                line_count_after: lines.len(),
10712            }
10713        });
10714    }
10715
10716    pub fn convert_indentation_to_spaces(
10717        &mut self,
10718        _: &ConvertIndentationToSpaces,
10719        window: &mut Window,
10720        cx: &mut Context<Self>,
10721    ) {
10722        let settings = self.buffer.read(cx).language_settings(cx);
10723        let tab_size = settings.tab_size.get() as usize;
10724
10725        self.manipulate_mutable_lines(window, cx, |lines| {
10726            // Allocates a reasonably sized scratch buffer once for the whole loop
10727            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10728            // Avoids recomputing spaces that could be inserted many times
10729            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10730                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10731                .collect();
10732
10733            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10734                let mut chars = line.as_ref().chars();
10735                let mut col = 0;
10736                let mut changed = false;
10737
10738                while let Some(ch) = chars.next() {
10739                    match ch {
10740                        ' ' => {
10741                            reindented_line.push(' ');
10742                            col += 1;
10743                        }
10744                        '\t' => {
10745                            // \t are converted to spaces depending on the current column
10746                            let spaces_len = tab_size - (col % tab_size);
10747                            reindented_line.extend(&space_cache[spaces_len - 1]);
10748                            col += spaces_len;
10749                            changed = true;
10750                        }
10751                        _ => {
10752                            // If we dont append before break, the character is consumed
10753                            reindented_line.push(ch);
10754                            break;
10755                        }
10756                    }
10757                }
10758
10759                if !changed {
10760                    reindented_line.clear();
10761                    continue;
10762                }
10763                // Append the rest of the line and replace old reference with new one
10764                reindented_line.extend(chars);
10765                *line = Cow::Owned(reindented_line.clone());
10766                reindented_line.clear();
10767            }
10768        });
10769    }
10770
10771    pub fn convert_indentation_to_tabs(
10772        &mut self,
10773        _: &ConvertIndentationToTabs,
10774        window: &mut Window,
10775        cx: &mut Context<Self>,
10776    ) {
10777        let settings = self.buffer.read(cx).language_settings(cx);
10778        let tab_size = settings.tab_size.get() as usize;
10779
10780        self.manipulate_mutable_lines(window, cx, |lines| {
10781            // Allocates a reasonably sized buffer once for the whole loop
10782            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
10783            // Avoids recomputing spaces that could be inserted many times
10784            let space_cache: Vec<Vec<char>> = (1..=tab_size)
10785                .map(|n| IndentSize::spaces(n as u32).chars().collect())
10786                .collect();
10787
10788            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
10789                let mut chars = line.chars();
10790                let mut spaces_count = 0;
10791                let mut first_non_indent_char = None;
10792                let mut changed = false;
10793
10794                while let Some(ch) = chars.next() {
10795                    match ch {
10796                        ' ' => {
10797                            // Keep track of spaces. Append \t when we reach tab_size
10798                            spaces_count += 1;
10799                            changed = true;
10800                            if spaces_count == tab_size {
10801                                reindented_line.push('\t');
10802                                spaces_count = 0;
10803                            }
10804                        }
10805                        '\t' => {
10806                            reindented_line.push('\t');
10807                            spaces_count = 0;
10808                        }
10809                        _ => {
10810                            // Dont append it yet, we might have remaining spaces
10811                            first_non_indent_char = Some(ch);
10812                            break;
10813                        }
10814                    }
10815                }
10816
10817                if !changed {
10818                    reindented_line.clear();
10819                    continue;
10820                }
10821                // Remaining spaces that didn't make a full tab stop
10822                if spaces_count > 0 {
10823                    reindented_line.extend(&space_cache[spaces_count - 1]);
10824                }
10825                // If we consume an extra character that was not indentation, add it back
10826                if let Some(extra_char) = first_non_indent_char {
10827                    reindented_line.push(extra_char);
10828                }
10829                // Append the rest of the line and replace old reference with new one
10830                reindented_line.extend(chars);
10831                *line = Cow::Owned(reindented_line.clone());
10832                reindented_line.clear();
10833            }
10834        });
10835    }
10836
10837    pub fn convert_to_upper_case(
10838        &mut self,
10839        _: &ConvertToUpperCase,
10840        window: &mut Window,
10841        cx: &mut Context<Self>,
10842    ) {
10843        self.manipulate_text(window, cx, |text| text.to_uppercase())
10844    }
10845
10846    pub fn convert_to_lower_case(
10847        &mut self,
10848        _: &ConvertToLowerCase,
10849        window: &mut Window,
10850        cx: &mut Context<Self>,
10851    ) {
10852        self.manipulate_text(window, cx, |text| text.to_lowercase())
10853    }
10854
10855    pub fn convert_to_title_case(
10856        &mut self,
10857        _: &ConvertToTitleCase,
10858        window: &mut Window,
10859        cx: &mut Context<Self>,
10860    ) {
10861        self.manipulate_text(window, cx, |text| {
10862            text.split('\n')
10863                .map(|line| line.to_case(Case::Title))
10864                .join("\n")
10865        })
10866    }
10867
10868    pub fn convert_to_snake_case(
10869        &mut self,
10870        _: &ConvertToSnakeCase,
10871        window: &mut Window,
10872        cx: &mut Context<Self>,
10873    ) {
10874        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10875    }
10876
10877    pub fn convert_to_kebab_case(
10878        &mut self,
10879        _: &ConvertToKebabCase,
10880        window: &mut Window,
10881        cx: &mut Context<Self>,
10882    ) {
10883        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10884    }
10885
10886    pub fn convert_to_upper_camel_case(
10887        &mut self,
10888        _: &ConvertToUpperCamelCase,
10889        window: &mut Window,
10890        cx: &mut Context<Self>,
10891    ) {
10892        self.manipulate_text(window, cx, |text| {
10893            text.split('\n')
10894                .map(|line| line.to_case(Case::UpperCamel))
10895                .join("\n")
10896        })
10897    }
10898
10899    pub fn convert_to_lower_camel_case(
10900        &mut self,
10901        _: &ConvertToLowerCamelCase,
10902        window: &mut Window,
10903        cx: &mut Context<Self>,
10904    ) {
10905        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10906    }
10907
10908    pub fn convert_to_opposite_case(
10909        &mut self,
10910        _: &ConvertToOppositeCase,
10911        window: &mut Window,
10912        cx: &mut Context<Self>,
10913    ) {
10914        self.manipulate_text(window, cx, |text| {
10915            text.chars()
10916                .fold(String::with_capacity(text.len()), |mut t, c| {
10917                    if c.is_uppercase() {
10918                        t.extend(c.to_lowercase());
10919                    } else {
10920                        t.extend(c.to_uppercase());
10921                    }
10922                    t
10923                })
10924        })
10925    }
10926
10927    pub fn convert_to_rot13(
10928        &mut self,
10929        _: &ConvertToRot13,
10930        window: &mut Window,
10931        cx: &mut Context<Self>,
10932    ) {
10933        self.manipulate_text(window, cx, |text| {
10934            text.chars()
10935                .map(|c| match c {
10936                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10937                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10938                    _ => c,
10939                })
10940                .collect()
10941        })
10942    }
10943
10944    pub fn convert_to_rot47(
10945        &mut self,
10946        _: &ConvertToRot47,
10947        window: &mut Window,
10948        cx: &mut Context<Self>,
10949    ) {
10950        self.manipulate_text(window, cx, |text| {
10951            text.chars()
10952                .map(|c| {
10953                    let code_point = c as u32;
10954                    if code_point >= 33 && code_point <= 126 {
10955                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10956                    }
10957                    c
10958                })
10959                .collect()
10960        })
10961    }
10962
10963    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10964    where
10965        Fn: FnMut(&str) -> String,
10966    {
10967        let buffer = self.buffer.read(cx).snapshot(cx);
10968
10969        let mut new_selections = Vec::new();
10970        let mut edits = Vec::new();
10971        let mut selection_adjustment = 0i32;
10972
10973        for selection in self.selections.all::<usize>(cx) {
10974            let selection_is_empty = selection.is_empty();
10975
10976            let (start, end) = if selection_is_empty {
10977                let (word_range, _) = buffer.surrounding_word(selection.start, false);
10978                (word_range.start, word_range.end)
10979            } else {
10980                (selection.start, selection.end)
10981            };
10982
10983            let text = buffer.text_for_range(start..end).collect::<String>();
10984            let old_length = text.len() as i32;
10985            let text = callback(&text);
10986
10987            new_selections.push(Selection {
10988                start: (start as i32 - selection_adjustment) as usize,
10989                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10990                goal: SelectionGoal::None,
10991                ..selection
10992            });
10993
10994            selection_adjustment += old_length - text.len() as i32;
10995
10996            edits.push((start..end, text));
10997        }
10998
10999        self.transact(window, cx, |this, window, cx| {
11000            this.buffer.update(cx, |buffer, cx| {
11001                buffer.edit(edits, None, cx);
11002            });
11003
11004            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11005                s.select(new_selections);
11006            });
11007
11008            this.request_autoscroll(Autoscroll::fit(), cx);
11009        });
11010    }
11011
11012    pub fn move_selection_on_drop(
11013        &mut self,
11014        selection: &Selection<Anchor>,
11015        target: DisplayPoint,
11016        is_cut: bool,
11017        window: &mut Window,
11018        cx: &mut Context<Self>,
11019    ) {
11020        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11021        let buffer = &display_map.buffer_snapshot;
11022        let mut edits = Vec::new();
11023        let insert_point = display_map
11024            .clip_point(target, Bias::Left)
11025            .to_point(&display_map);
11026        let text = buffer
11027            .text_for_range(selection.start..selection.end)
11028            .collect::<String>();
11029        if is_cut {
11030            edits.push(((selection.start..selection.end), String::new()));
11031        }
11032        let insert_anchor = buffer.anchor_before(insert_point);
11033        edits.push(((insert_anchor..insert_anchor), text));
11034        let last_edit_start = insert_anchor.bias_left(buffer);
11035        let last_edit_end = insert_anchor.bias_right(buffer);
11036        self.transact(window, cx, |this, window, cx| {
11037            this.buffer.update(cx, |buffer, cx| {
11038                buffer.edit(edits, None, cx);
11039            });
11040            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11041                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11042            });
11043        });
11044    }
11045
11046    pub fn clear_selection_drag_state(&mut self) {
11047        self.selection_drag_state = SelectionDragState::None;
11048    }
11049
11050    pub fn duplicate(
11051        &mut self,
11052        upwards: bool,
11053        whole_lines: bool,
11054        window: &mut Window,
11055        cx: &mut Context<Self>,
11056    ) {
11057        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11058
11059        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11060        let buffer = &display_map.buffer_snapshot;
11061        let selections = self.selections.all::<Point>(cx);
11062
11063        let mut edits = Vec::new();
11064        let mut selections_iter = selections.iter().peekable();
11065        while let Some(selection) = selections_iter.next() {
11066            let mut rows = selection.spanned_rows(false, &display_map);
11067            // duplicate line-wise
11068            if whole_lines || selection.start == selection.end {
11069                // Avoid duplicating the same lines twice.
11070                while let Some(next_selection) = selections_iter.peek() {
11071                    let next_rows = next_selection.spanned_rows(false, &display_map);
11072                    if next_rows.start < rows.end {
11073                        rows.end = next_rows.end;
11074                        selections_iter.next().unwrap();
11075                    } else {
11076                        break;
11077                    }
11078                }
11079
11080                // Copy the text from the selected row region and splice it either at the start
11081                // or end of the region.
11082                let start = Point::new(rows.start.0, 0);
11083                let end = Point::new(
11084                    rows.end.previous_row().0,
11085                    buffer.line_len(rows.end.previous_row()),
11086                );
11087                let text = buffer
11088                    .text_for_range(start..end)
11089                    .chain(Some("\n"))
11090                    .collect::<String>();
11091                let insert_location = if upwards {
11092                    Point::new(rows.end.0, 0)
11093                } else {
11094                    start
11095                };
11096                edits.push((insert_location..insert_location, text));
11097            } else {
11098                // duplicate character-wise
11099                let start = selection.start;
11100                let end = selection.end;
11101                let text = buffer.text_for_range(start..end).collect::<String>();
11102                edits.push((selection.end..selection.end, text));
11103            }
11104        }
11105
11106        self.transact(window, cx, |this, _, cx| {
11107            this.buffer.update(cx, |buffer, cx| {
11108                buffer.edit(edits, None, cx);
11109            });
11110
11111            this.request_autoscroll(Autoscroll::fit(), cx);
11112        });
11113    }
11114
11115    pub fn duplicate_line_up(
11116        &mut self,
11117        _: &DuplicateLineUp,
11118        window: &mut Window,
11119        cx: &mut Context<Self>,
11120    ) {
11121        self.duplicate(true, true, window, cx);
11122    }
11123
11124    pub fn duplicate_line_down(
11125        &mut self,
11126        _: &DuplicateLineDown,
11127        window: &mut Window,
11128        cx: &mut Context<Self>,
11129    ) {
11130        self.duplicate(false, true, window, cx);
11131    }
11132
11133    pub fn duplicate_selection(
11134        &mut self,
11135        _: &DuplicateSelection,
11136        window: &mut Window,
11137        cx: &mut Context<Self>,
11138    ) {
11139        self.duplicate(false, false, window, cx);
11140    }
11141
11142    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11143        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11144        if self.mode.is_single_line() {
11145            cx.propagate();
11146            return;
11147        }
11148
11149        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11150        let buffer = self.buffer.read(cx).snapshot(cx);
11151
11152        let mut edits = Vec::new();
11153        let mut unfold_ranges = Vec::new();
11154        let mut refold_creases = Vec::new();
11155
11156        let selections = self.selections.all::<Point>(cx);
11157        let mut selections = selections.iter().peekable();
11158        let mut contiguous_row_selections = Vec::new();
11159        let mut new_selections = Vec::new();
11160
11161        while let Some(selection) = selections.next() {
11162            // Find all the selections that span a contiguous row range
11163            let (start_row, end_row) = consume_contiguous_rows(
11164                &mut contiguous_row_selections,
11165                selection,
11166                &display_map,
11167                &mut selections,
11168            );
11169
11170            // Move the text spanned by the row range to be before the line preceding the row range
11171            if start_row.0 > 0 {
11172                let range_to_move = Point::new(
11173                    start_row.previous_row().0,
11174                    buffer.line_len(start_row.previous_row()),
11175                )
11176                    ..Point::new(
11177                        end_row.previous_row().0,
11178                        buffer.line_len(end_row.previous_row()),
11179                    );
11180                let insertion_point = display_map
11181                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11182                    .0;
11183
11184                // Don't move lines across excerpts
11185                if buffer
11186                    .excerpt_containing(insertion_point..range_to_move.end)
11187                    .is_some()
11188                {
11189                    let text = buffer
11190                        .text_for_range(range_to_move.clone())
11191                        .flat_map(|s| s.chars())
11192                        .skip(1)
11193                        .chain(['\n'])
11194                        .collect::<String>();
11195
11196                    edits.push((
11197                        buffer.anchor_after(range_to_move.start)
11198                            ..buffer.anchor_before(range_to_move.end),
11199                        String::new(),
11200                    ));
11201                    let insertion_anchor = buffer.anchor_after(insertion_point);
11202                    edits.push((insertion_anchor..insertion_anchor, text));
11203
11204                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11205
11206                    // Move selections up
11207                    new_selections.extend(contiguous_row_selections.drain(..).map(
11208                        |mut selection| {
11209                            selection.start.row -= row_delta;
11210                            selection.end.row -= row_delta;
11211                            selection
11212                        },
11213                    ));
11214
11215                    // Move folds up
11216                    unfold_ranges.push(range_to_move.clone());
11217                    for fold in display_map.folds_in_range(
11218                        buffer.anchor_before(range_to_move.start)
11219                            ..buffer.anchor_after(range_to_move.end),
11220                    ) {
11221                        let mut start = fold.range.start.to_point(&buffer);
11222                        let mut end = fold.range.end.to_point(&buffer);
11223                        start.row -= row_delta;
11224                        end.row -= row_delta;
11225                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11226                    }
11227                }
11228            }
11229
11230            // If we didn't move line(s), preserve the existing selections
11231            new_selections.append(&mut contiguous_row_selections);
11232        }
11233
11234        self.transact(window, cx, |this, window, cx| {
11235            this.unfold_ranges(&unfold_ranges, true, true, cx);
11236            this.buffer.update(cx, |buffer, cx| {
11237                for (range, text) in edits {
11238                    buffer.edit([(range, text)], None, cx);
11239                }
11240            });
11241            this.fold_creases(refold_creases, true, window, cx);
11242            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11243                s.select(new_selections);
11244            })
11245        });
11246    }
11247
11248    pub fn move_line_down(
11249        &mut self,
11250        _: &MoveLineDown,
11251        window: &mut Window,
11252        cx: &mut Context<Self>,
11253    ) {
11254        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11255        if self.mode.is_single_line() {
11256            cx.propagate();
11257            return;
11258        }
11259
11260        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11261        let buffer = self.buffer.read(cx).snapshot(cx);
11262
11263        let mut edits = Vec::new();
11264        let mut unfold_ranges = Vec::new();
11265        let mut refold_creases = Vec::new();
11266
11267        let selections = self.selections.all::<Point>(cx);
11268        let mut selections = selections.iter().peekable();
11269        let mut contiguous_row_selections = Vec::new();
11270        let mut new_selections = Vec::new();
11271
11272        while let Some(selection) = selections.next() {
11273            // Find all the selections that span a contiguous row range
11274            let (start_row, end_row) = consume_contiguous_rows(
11275                &mut contiguous_row_selections,
11276                selection,
11277                &display_map,
11278                &mut selections,
11279            );
11280
11281            // Move the text spanned by the row range to be after the last line of the row range
11282            if end_row.0 <= buffer.max_point().row {
11283                let range_to_move =
11284                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11285                let insertion_point = display_map
11286                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11287                    .0;
11288
11289                // Don't move lines across excerpt boundaries
11290                if buffer
11291                    .excerpt_containing(range_to_move.start..insertion_point)
11292                    .is_some()
11293                {
11294                    let mut text = String::from("\n");
11295                    text.extend(buffer.text_for_range(range_to_move.clone()));
11296                    text.pop(); // Drop trailing newline
11297                    edits.push((
11298                        buffer.anchor_after(range_to_move.start)
11299                            ..buffer.anchor_before(range_to_move.end),
11300                        String::new(),
11301                    ));
11302                    let insertion_anchor = buffer.anchor_after(insertion_point);
11303                    edits.push((insertion_anchor..insertion_anchor, text));
11304
11305                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11306
11307                    // Move selections down
11308                    new_selections.extend(contiguous_row_selections.drain(..).map(
11309                        |mut selection| {
11310                            selection.start.row += row_delta;
11311                            selection.end.row += row_delta;
11312                            selection
11313                        },
11314                    ));
11315
11316                    // Move folds down
11317                    unfold_ranges.push(range_to_move.clone());
11318                    for fold in display_map.folds_in_range(
11319                        buffer.anchor_before(range_to_move.start)
11320                            ..buffer.anchor_after(range_to_move.end),
11321                    ) {
11322                        let mut start = fold.range.start.to_point(&buffer);
11323                        let mut end = fold.range.end.to_point(&buffer);
11324                        start.row += row_delta;
11325                        end.row += row_delta;
11326                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11327                    }
11328                }
11329            }
11330
11331            // If we didn't move line(s), preserve the existing selections
11332            new_selections.append(&mut contiguous_row_selections);
11333        }
11334
11335        self.transact(window, cx, |this, window, cx| {
11336            this.unfold_ranges(&unfold_ranges, true, true, cx);
11337            this.buffer.update(cx, |buffer, cx| {
11338                for (range, text) in edits {
11339                    buffer.edit([(range, text)], None, cx);
11340                }
11341            });
11342            this.fold_creases(refold_creases, true, window, cx);
11343            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11344                s.select(new_selections)
11345            });
11346        });
11347    }
11348
11349    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11350        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11351        let text_layout_details = &self.text_layout_details(window);
11352        self.transact(window, cx, |this, window, cx| {
11353            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11354                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11355                s.move_with(|display_map, selection| {
11356                    if !selection.is_empty() {
11357                        return;
11358                    }
11359
11360                    let mut head = selection.head();
11361                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11362                    if head.column() == display_map.line_len(head.row()) {
11363                        transpose_offset = display_map
11364                            .buffer_snapshot
11365                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11366                    }
11367
11368                    if transpose_offset == 0 {
11369                        return;
11370                    }
11371
11372                    *head.column_mut() += 1;
11373                    head = display_map.clip_point(head, Bias::Right);
11374                    let goal = SelectionGoal::HorizontalPosition(
11375                        display_map
11376                            .x_for_display_point(head, text_layout_details)
11377                            .into(),
11378                    );
11379                    selection.collapse_to(head, goal);
11380
11381                    let transpose_start = display_map
11382                        .buffer_snapshot
11383                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11384                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11385                        let transpose_end = display_map
11386                            .buffer_snapshot
11387                            .clip_offset(transpose_offset + 1, Bias::Right);
11388                        if let Some(ch) =
11389                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11390                        {
11391                            edits.push((transpose_start..transpose_offset, String::new()));
11392                            edits.push((transpose_end..transpose_end, ch.to_string()));
11393                        }
11394                    }
11395                });
11396                edits
11397            });
11398            this.buffer
11399                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11400            let selections = this.selections.all::<usize>(cx);
11401            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11402                s.select(selections);
11403            });
11404        });
11405    }
11406
11407    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11408        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11409        if self.mode.is_single_line() {
11410            cx.propagate();
11411            return;
11412        }
11413
11414        self.rewrap_impl(RewrapOptions::default(), cx)
11415    }
11416
11417    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11418        let buffer = self.buffer.read(cx).snapshot(cx);
11419        let selections = self.selections.all::<Point>(cx);
11420
11421        // Shrink and split selections to respect paragraph boundaries.
11422        let ranges = selections.into_iter().flat_map(|selection| {
11423            let language_settings = buffer.language_settings_at(selection.head(), cx);
11424            let language_scope = buffer.language_scope_at(selection.head());
11425
11426            let Some(start_row) = (selection.start.row..=selection.end.row)
11427                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11428            else {
11429                return vec![];
11430            };
11431            let Some(end_row) = (selection.start.row..=selection.end.row)
11432                .rev()
11433                .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11434            else {
11435                return vec![];
11436            };
11437
11438            let mut row = start_row;
11439            let mut ranges = Vec::new();
11440            while let Some(blank_row) =
11441                (row..end_row).find(|row| buffer.is_line_blank(MultiBufferRow(*row)))
11442            {
11443                let next_paragraph_start = (blank_row + 1..=end_row)
11444                    .find(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11445                    .unwrap();
11446                ranges.push((
11447                    language_settings.clone(),
11448                    language_scope.clone(),
11449                    Point::new(row, 0)..Point::new(blank_row - 1, 0),
11450                ));
11451                row = next_paragraph_start;
11452            }
11453            ranges.push((
11454                language_settings.clone(),
11455                language_scope.clone(),
11456                Point::new(row, 0)..Point::new(end_row, 0),
11457            ));
11458
11459            ranges
11460        });
11461
11462        let mut edits = Vec::new();
11463        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11464
11465        for (language_settings, language_scope, range) in ranges {
11466            let mut start_row = range.start.row;
11467            let mut end_row = range.end.row;
11468
11469            // Skip selections that overlap with a range that has already been rewrapped.
11470            let selection_range = start_row..end_row;
11471            if rewrapped_row_ranges
11472                .iter()
11473                .any(|range| range.overlaps(&selection_range))
11474            {
11475                continue;
11476            }
11477
11478            let tab_size = language_settings.tab_size;
11479
11480            // Since not all lines in the selection may be at the same indent
11481            // level, choose the indent size that is the most common between all
11482            // of the lines.
11483            //
11484            // If there is a tie, we use the deepest indent.
11485            let (indent_size, indent_end) = {
11486                let mut indent_size_occurrences = HashMap::default();
11487                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
11488
11489                for row in start_row..=end_row {
11490                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11491                    rows_by_indent_size.entry(indent).or_default().push(row);
11492                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
11493                }
11494
11495                let indent_size = indent_size_occurrences
11496                    .into_iter()
11497                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
11498                    .map(|(indent, _)| indent)
11499                    .unwrap_or_default();
11500                let row = rows_by_indent_size[&indent_size][0];
11501                let indent_end = Point::new(row, indent_size.len);
11502
11503                (indent_size, indent_end)
11504            };
11505
11506            let mut line_prefix = indent_size.chars().collect::<String>();
11507
11508            let mut inside_comment = false;
11509            if let Some(comment_prefix) = language_scope.and_then(|language| {
11510                language
11511                    .line_comment_prefixes()
11512                    .iter()
11513                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11514                    .cloned()
11515            }) {
11516                line_prefix.push_str(&comment_prefix);
11517                inside_comment = true;
11518            }
11519
11520            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11521                RewrapBehavior::InComments => inside_comment,
11522                RewrapBehavior::InSelections => !range.is_empty(),
11523                RewrapBehavior::Anywhere => true,
11524            };
11525
11526            let should_rewrap = options.override_language_settings
11527                || allow_rewrap_based_on_language
11528                || self.hard_wrap.is_some();
11529            if !should_rewrap {
11530                continue;
11531            }
11532
11533            if range.is_empty() {
11534                'expand_upwards: while start_row > 0 {
11535                    let prev_row = start_row - 1;
11536                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11537                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11538                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11539                    {
11540                        start_row = prev_row;
11541                    } else {
11542                        break 'expand_upwards;
11543                    }
11544                }
11545
11546                'expand_downwards: while end_row < buffer.max_point().row {
11547                    let next_row = end_row + 1;
11548                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11549                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11550                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11551                    {
11552                        end_row = next_row;
11553                    } else {
11554                        break 'expand_downwards;
11555                    }
11556                }
11557            }
11558
11559            let start = Point::new(start_row, 0);
11560            let start_offset = start.to_offset(&buffer);
11561            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11562            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11563            let Some(lines_without_prefixes) = selection_text
11564                .lines()
11565                .map(|line| {
11566                    line.strip_prefix(&line_prefix)
11567                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11568                        .with_context(|| {
11569                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11570                        })
11571                })
11572                .collect::<Result<Vec<_>, _>>()
11573                .log_err()
11574            else {
11575                continue;
11576            };
11577
11578            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11579                buffer
11580                    .language_settings_at(Point::new(start_row, 0), cx)
11581                    .preferred_line_length as usize
11582            });
11583            let wrapped_text = wrap_with_prefix(
11584                line_prefix,
11585                lines_without_prefixes.join("\n"),
11586                wrap_column,
11587                tab_size,
11588                options.preserve_existing_whitespace,
11589            );
11590
11591            // TODO: should always use char-based diff while still supporting cursor behavior that
11592            // matches vim.
11593            let mut diff_options = DiffOptions::default();
11594            if options.override_language_settings {
11595                diff_options.max_word_diff_len = 0;
11596                diff_options.max_word_diff_line_count = 0;
11597            } else {
11598                diff_options.max_word_diff_len = usize::MAX;
11599                diff_options.max_word_diff_line_count = usize::MAX;
11600            }
11601
11602            for (old_range, new_text) in
11603                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11604            {
11605                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11606                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11607                edits.push((edit_start..edit_end, new_text));
11608            }
11609
11610            rewrapped_row_ranges.push(start_row..=end_row);
11611        }
11612
11613        self.buffer
11614            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11615    }
11616
11617    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11618        let mut text = String::new();
11619        let buffer = self.buffer.read(cx).snapshot(cx);
11620        let mut selections = self.selections.all::<Point>(cx);
11621        let mut clipboard_selections = Vec::with_capacity(selections.len());
11622        {
11623            let max_point = buffer.max_point();
11624            let mut is_first = true;
11625            for selection in &mut selections {
11626                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11627                if is_entire_line {
11628                    selection.start = Point::new(selection.start.row, 0);
11629                    if !selection.is_empty() && selection.end.column == 0 {
11630                        selection.end = cmp::min(max_point, selection.end);
11631                    } else {
11632                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11633                    }
11634                    selection.goal = SelectionGoal::None;
11635                }
11636                if is_first {
11637                    is_first = false;
11638                } else {
11639                    text += "\n";
11640                }
11641                let mut len = 0;
11642                for chunk in buffer.text_for_range(selection.start..selection.end) {
11643                    text.push_str(chunk);
11644                    len += chunk.len();
11645                }
11646                clipboard_selections.push(ClipboardSelection {
11647                    len,
11648                    is_entire_line,
11649                    first_line_indent: buffer
11650                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11651                        .len,
11652                });
11653            }
11654        }
11655
11656        self.transact(window, cx, |this, window, cx| {
11657            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11658                s.select(selections);
11659            });
11660            this.insert("", window, cx);
11661        });
11662        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11663    }
11664
11665    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11666        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11667        let item = self.cut_common(window, cx);
11668        cx.write_to_clipboard(item);
11669    }
11670
11671    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11672        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11673        self.change_selections(None, window, cx, |s| {
11674            s.move_with(|snapshot, sel| {
11675                if sel.is_empty() {
11676                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11677                }
11678            });
11679        });
11680        let item = self.cut_common(window, cx);
11681        cx.set_global(KillRing(item))
11682    }
11683
11684    pub fn kill_ring_yank(
11685        &mut self,
11686        _: &KillRingYank,
11687        window: &mut Window,
11688        cx: &mut Context<Self>,
11689    ) {
11690        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11691        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11692            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11693                (kill_ring.text().to_string(), kill_ring.metadata_json())
11694            } else {
11695                return;
11696            }
11697        } else {
11698            return;
11699        };
11700        self.do_paste(&text, metadata, false, window, cx);
11701    }
11702
11703    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11704        self.do_copy(true, cx);
11705    }
11706
11707    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11708        self.do_copy(false, cx);
11709    }
11710
11711    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11712        let selections = self.selections.all::<Point>(cx);
11713        let buffer = self.buffer.read(cx).read(cx);
11714        let mut text = String::new();
11715
11716        let mut clipboard_selections = Vec::with_capacity(selections.len());
11717        {
11718            let max_point = buffer.max_point();
11719            let mut is_first = true;
11720            for selection in &selections {
11721                let mut start = selection.start;
11722                let mut end = selection.end;
11723                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11724                if is_entire_line {
11725                    start = Point::new(start.row, 0);
11726                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11727                }
11728
11729                let mut trimmed_selections = Vec::new();
11730                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11731                    let row = MultiBufferRow(start.row);
11732                    let first_indent = buffer.indent_size_for_line(row);
11733                    if first_indent.len == 0 || start.column > first_indent.len {
11734                        trimmed_selections.push(start..end);
11735                    } else {
11736                        trimmed_selections.push(
11737                            Point::new(row.0, first_indent.len)
11738                                ..Point::new(row.0, buffer.line_len(row)),
11739                        );
11740                        for row in start.row + 1..=end.row {
11741                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11742                            if row == end.row {
11743                                line_len = end.column;
11744                            }
11745                            if line_len == 0 {
11746                                trimmed_selections
11747                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11748                                continue;
11749                            }
11750                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11751                            if row_indent_size.len >= first_indent.len {
11752                                trimmed_selections.push(
11753                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11754                                );
11755                            } else {
11756                                trimmed_selections.clear();
11757                                trimmed_selections.push(start..end);
11758                                break;
11759                            }
11760                        }
11761                    }
11762                } else {
11763                    trimmed_selections.push(start..end);
11764                }
11765
11766                for trimmed_range in trimmed_selections {
11767                    if is_first {
11768                        is_first = false;
11769                    } else {
11770                        text += "\n";
11771                    }
11772                    let mut len = 0;
11773                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11774                        text.push_str(chunk);
11775                        len += chunk.len();
11776                    }
11777                    clipboard_selections.push(ClipboardSelection {
11778                        len,
11779                        is_entire_line,
11780                        first_line_indent: buffer
11781                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11782                            .len,
11783                    });
11784                }
11785            }
11786        }
11787
11788        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11789            text,
11790            clipboard_selections,
11791        ));
11792    }
11793
11794    pub fn do_paste(
11795        &mut self,
11796        text: &String,
11797        clipboard_selections: Option<Vec<ClipboardSelection>>,
11798        handle_entire_lines: bool,
11799        window: &mut Window,
11800        cx: &mut Context<Self>,
11801    ) {
11802        if self.read_only(cx) {
11803            return;
11804        }
11805
11806        let clipboard_text = Cow::Borrowed(text);
11807
11808        self.transact(window, cx, |this, window, cx| {
11809            if let Some(mut clipboard_selections) = clipboard_selections {
11810                let old_selections = this.selections.all::<usize>(cx);
11811                let all_selections_were_entire_line =
11812                    clipboard_selections.iter().all(|s| s.is_entire_line);
11813                let first_selection_indent_column =
11814                    clipboard_selections.first().map(|s| s.first_line_indent);
11815                if clipboard_selections.len() != old_selections.len() {
11816                    clipboard_selections.drain(..);
11817                }
11818                let cursor_offset = this.selections.last::<usize>(cx).head();
11819                let mut auto_indent_on_paste = true;
11820
11821                this.buffer.update(cx, |buffer, cx| {
11822                    let snapshot = buffer.read(cx);
11823                    auto_indent_on_paste = snapshot
11824                        .language_settings_at(cursor_offset, cx)
11825                        .auto_indent_on_paste;
11826
11827                    let mut start_offset = 0;
11828                    let mut edits = Vec::new();
11829                    let mut original_indent_columns = Vec::new();
11830                    for (ix, selection) in old_selections.iter().enumerate() {
11831                        let to_insert;
11832                        let entire_line;
11833                        let original_indent_column;
11834                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11835                            let end_offset = start_offset + clipboard_selection.len;
11836                            to_insert = &clipboard_text[start_offset..end_offset];
11837                            entire_line = clipboard_selection.is_entire_line;
11838                            start_offset = end_offset + 1;
11839                            original_indent_column = Some(clipboard_selection.first_line_indent);
11840                        } else {
11841                            to_insert = clipboard_text.as_str();
11842                            entire_line = all_selections_were_entire_line;
11843                            original_indent_column = first_selection_indent_column
11844                        }
11845
11846                        // If the corresponding selection was empty when this slice of the
11847                        // clipboard text was written, then the entire line containing the
11848                        // selection was copied. If this selection is also currently empty,
11849                        // then paste the line before the current line of the buffer.
11850                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11851                            let column = selection.start.to_point(&snapshot).column as usize;
11852                            let line_start = selection.start - column;
11853                            line_start..line_start
11854                        } else {
11855                            selection.range()
11856                        };
11857
11858                        edits.push((range, to_insert));
11859                        original_indent_columns.push(original_indent_column);
11860                    }
11861                    drop(snapshot);
11862
11863                    buffer.edit(
11864                        edits,
11865                        if auto_indent_on_paste {
11866                            Some(AutoindentMode::Block {
11867                                original_indent_columns,
11868                            })
11869                        } else {
11870                            None
11871                        },
11872                        cx,
11873                    );
11874                });
11875
11876                let selections = this.selections.all::<usize>(cx);
11877                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11878                    s.select(selections)
11879                });
11880            } else {
11881                this.insert(&clipboard_text, window, cx);
11882            }
11883        });
11884    }
11885
11886    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11887        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11888        if let Some(item) = cx.read_from_clipboard() {
11889            let entries = item.entries();
11890
11891            match entries.first() {
11892                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11893                // of all the pasted entries.
11894                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11895                    .do_paste(
11896                        clipboard_string.text(),
11897                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11898                        true,
11899                        window,
11900                        cx,
11901                    ),
11902                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11903            }
11904        }
11905    }
11906
11907    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11908        if self.read_only(cx) {
11909            return;
11910        }
11911
11912        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11913
11914        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11915            if let Some((selections, _)) =
11916                self.selection_history.transaction(transaction_id).cloned()
11917            {
11918                self.change_selections(None, window, cx, |s| {
11919                    s.select_anchors(selections.to_vec());
11920                });
11921            } else {
11922                log::error!(
11923                    "No entry in selection_history found for undo. \
11924                     This may correspond to a bug where undo does not update the selection. \
11925                     If this is occurring, please add details to \
11926                     https://github.com/zed-industries/zed/issues/22692"
11927                );
11928            }
11929            self.request_autoscroll(Autoscroll::fit(), cx);
11930            self.unmark_text(window, cx);
11931            self.refresh_inline_completion(true, false, window, cx);
11932            cx.emit(EditorEvent::Edited { transaction_id });
11933            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11934        }
11935    }
11936
11937    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11938        if self.read_only(cx) {
11939            return;
11940        }
11941
11942        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11943
11944        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11945            if let Some((_, Some(selections))) =
11946                self.selection_history.transaction(transaction_id).cloned()
11947            {
11948                self.change_selections(None, window, cx, |s| {
11949                    s.select_anchors(selections.to_vec());
11950                });
11951            } else {
11952                log::error!(
11953                    "No entry in selection_history found for redo. \
11954                     This may correspond to a bug where undo does not update the selection. \
11955                     If this is occurring, please add details to \
11956                     https://github.com/zed-industries/zed/issues/22692"
11957                );
11958            }
11959            self.request_autoscroll(Autoscroll::fit(), cx);
11960            self.unmark_text(window, cx);
11961            self.refresh_inline_completion(true, false, window, cx);
11962            cx.emit(EditorEvent::Edited { transaction_id });
11963        }
11964    }
11965
11966    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11967        self.buffer
11968            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11969    }
11970
11971    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11972        self.buffer
11973            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11974    }
11975
11976    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11977        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11978        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11979            s.move_with(|map, selection| {
11980                let cursor = if selection.is_empty() {
11981                    movement::left(map, selection.start)
11982                } else {
11983                    selection.start
11984                };
11985                selection.collapse_to(cursor, SelectionGoal::None);
11986            });
11987        })
11988    }
11989
11990    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11991        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11992        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11993            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11994        })
11995    }
11996
11997    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11998        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
11999        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12000            s.move_with(|map, selection| {
12001                let cursor = if selection.is_empty() {
12002                    movement::right(map, selection.end)
12003                } else {
12004                    selection.end
12005                };
12006                selection.collapse_to(cursor, SelectionGoal::None)
12007            });
12008        })
12009    }
12010
12011    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12012        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12013        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12014            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12015        })
12016    }
12017
12018    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12019        if self.take_rename(true, window, cx).is_some() {
12020            return;
12021        }
12022
12023        if self.mode.is_single_line() {
12024            cx.propagate();
12025            return;
12026        }
12027
12028        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12029
12030        let text_layout_details = &self.text_layout_details(window);
12031        let selection_count = self.selections.count();
12032        let first_selection = self.selections.first_anchor();
12033
12034        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12035            s.move_with(|map, selection| {
12036                if !selection.is_empty() {
12037                    selection.goal = SelectionGoal::None;
12038                }
12039                let (cursor, goal) = movement::up(
12040                    map,
12041                    selection.start,
12042                    selection.goal,
12043                    false,
12044                    text_layout_details,
12045                );
12046                selection.collapse_to(cursor, goal);
12047            });
12048        });
12049
12050        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12051        {
12052            cx.propagate();
12053        }
12054    }
12055
12056    pub fn move_up_by_lines(
12057        &mut self,
12058        action: &MoveUpByLines,
12059        window: &mut Window,
12060        cx: &mut Context<Self>,
12061    ) {
12062        if self.take_rename(true, window, cx).is_some() {
12063            return;
12064        }
12065
12066        if self.mode.is_single_line() {
12067            cx.propagate();
12068            return;
12069        }
12070
12071        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12072
12073        let text_layout_details = &self.text_layout_details(window);
12074
12075        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12076            s.move_with(|map, selection| {
12077                if !selection.is_empty() {
12078                    selection.goal = SelectionGoal::None;
12079                }
12080                let (cursor, goal) = movement::up_by_rows(
12081                    map,
12082                    selection.start,
12083                    action.lines,
12084                    selection.goal,
12085                    false,
12086                    text_layout_details,
12087                );
12088                selection.collapse_to(cursor, goal);
12089            });
12090        })
12091    }
12092
12093    pub fn move_down_by_lines(
12094        &mut self,
12095        action: &MoveDownByLines,
12096        window: &mut Window,
12097        cx: &mut Context<Self>,
12098    ) {
12099        if self.take_rename(true, window, cx).is_some() {
12100            return;
12101        }
12102
12103        if self.mode.is_single_line() {
12104            cx.propagate();
12105            return;
12106        }
12107
12108        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12109
12110        let text_layout_details = &self.text_layout_details(window);
12111
12112        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12113            s.move_with(|map, selection| {
12114                if !selection.is_empty() {
12115                    selection.goal = SelectionGoal::None;
12116                }
12117                let (cursor, goal) = movement::down_by_rows(
12118                    map,
12119                    selection.start,
12120                    action.lines,
12121                    selection.goal,
12122                    false,
12123                    text_layout_details,
12124                );
12125                selection.collapse_to(cursor, goal);
12126            });
12127        })
12128    }
12129
12130    pub fn select_down_by_lines(
12131        &mut self,
12132        action: &SelectDownByLines,
12133        window: &mut Window,
12134        cx: &mut Context<Self>,
12135    ) {
12136        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12137        let text_layout_details = &self.text_layout_details(window);
12138        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12139            s.move_heads_with(|map, head, goal| {
12140                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12141            })
12142        })
12143    }
12144
12145    pub fn select_up_by_lines(
12146        &mut self,
12147        action: &SelectUpByLines,
12148        window: &mut Window,
12149        cx: &mut Context<Self>,
12150    ) {
12151        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12152        let text_layout_details = &self.text_layout_details(window);
12153        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12154            s.move_heads_with(|map, head, goal| {
12155                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12156            })
12157        })
12158    }
12159
12160    pub fn select_page_up(
12161        &mut self,
12162        _: &SelectPageUp,
12163        window: &mut Window,
12164        cx: &mut Context<Self>,
12165    ) {
12166        let Some(row_count) = self.visible_row_count() else {
12167            return;
12168        };
12169
12170        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12171
12172        let text_layout_details = &self.text_layout_details(window);
12173
12174        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12175            s.move_heads_with(|map, head, goal| {
12176                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12177            })
12178        })
12179    }
12180
12181    pub fn move_page_up(
12182        &mut self,
12183        action: &MovePageUp,
12184        window: &mut Window,
12185        cx: &mut Context<Self>,
12186    ) {
12187        if self.take_rename(true, window, cx).is_some() {
12188            return;
12189        }
12190
12191        if self
12192            .context_menu
12193            .borrow_mut()
12194            .as_mut()
12195            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12196            .unwrap_or(false)
12197        {
12198            return;
12199        }
12200
12201        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12202            cx.propagate();
12203            return;
12204        }
12205
12206        let Some(row_count) = self.visible_row_count() else {
12207            return;
12208        };
12209
12210        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12211
12212        let autoscroll = if action.center_cursor {
12213            Autoscroll::center()
12214        } else {
12215            Autoscroll::fit()
12216        };
12217
12218        let text_layout_details = &self.text_layout_details(window);
12219
12220        self.change_selections(Some(autoscroll), window, cx, |s| {
12221            s.move_with(|map, selection| {
12222                if !selection.is_empty() {
12223                    selection.goal = SelectionGoal::None;
12224                }
12225                let (cursor, goal) = movement::up_by_rows(
12226                    map,
12227                    selection.end,
12228                    row_count,
12229                    selection.goal,
12230                    false,
12231                    text_layout_details,
12232                );
12233                selection.collapse_to(cursor, goal);
12234            });
12235        });
12236    }
12237
12238    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12239        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12240        let text_layout_details = &self.text_layout_details(window);
12241        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12242            s.move_heads_with(|map, head, goal| {
12243                movement::up(map, head, goal, false, text_layout_details)
12244            })
12245        })
12246    }
12247
12248    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12249        self.take_rename(true, window, cx);
12250
12251        if self.mode.is_single_line() {
12252            cx.propagate();
12253            return;
12254        }
12255
12256        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12257
12258        let text_layout_details = &self.text_layout_details(window);
12259        let selection_count = self.selections.count();
12260        let first_selection = self.selections.first_anchor();
12261
12262        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12263            s.move_with(|map, selection| {
12264                if !selection.is_empty() {
12265                    selection.goal = SelectionGoal::None;
12266                }
12267                let (cursor, goal) = movement::down(
12268                    map,
12269                    selection.end,
12270                    selection.goal,
12271                    false,
12272                    text_layout_details,
12273                );
12274                selection.collapse_to(cursor, goal);
12275            });
12276        });
12277
12278        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12279        {
12280            cx.propagate();
12281        }
12282    }
12283
12284    pub fn select_page_down(
12285        &mut self,
12286        _: &SelectPageDown,
12287        window: &mut Window,
12288        cx: &mut Context<Self>,
12289    ) {
12290        let Some(row_count) = self.visible_row_count() else {
12291            return;
12292        };
12293
12294        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12295
12296        let text_layout_details = &self.text_layout_details(window);
12297
12298        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12299            s.move_heads_with(|map, head, goal| {
12300                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12301            })
12302        })
12303    }
12304
12305    pub fn move_page_down(
12306        &mut self,
12307        action: &MovePageDown,
12308        window: &mut Window,
12309        cx: &mut Context<Self>,
12310    ) {
12311        if self.take_rename(true, window, cx).is_some() {
12312            return;
12313        }
12314
12315        if self
12316            .context_menu
12317            .borrow_mut()
12318            .as_mut()
12319            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12320            .unwrap_or(false)
12321        {
12322            return;
12323        }
12324
12325        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12326            cx.propagate();
12327            return;
12328        }
12329
12330        let Some(row_count) = self.visible_row_count() else {
12331            return;
12332        };
12333
12334        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12335
12336        let autoscroll = if action.center_cursor {
12337            Autoscroll::center()
12338        } else {
12339            Autoscroll::fit()
12340        };
12341
12342        let text_layout_details = &self.text_layout_details(window);
12343        self.change_selections(Some(autoscroll), window, cx, |s| {
12344            s.move_with(|map, selection| {
12345                if !selection.is_empty() {
12346                    selection.goal = SelectionGoal::None;
12347                }
12348                let (cursor, goal) = movement::down_by_rows(
12349                    map,
12350                    selection.end,
12351                    row_count,
12352                    selection.goal,
12353                    false,
12354                    text_layout_details,
12355                );
12356                selection.collapse_to(cursor, goal);
12357            });
12358        });
12359    }
12360
12361    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12362        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12363        let text_layout_details = &self.text_layout_details(window);
12364        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12365            s.move_heads_with(|map, head, goal| {
12366                movement::down(map, head, goal, false, text_layout_details)
12367            })
12368        });
12369    }
12370
12371    pub fn context_menu_first(
12372        &mut self,
12373        _: &ContextMenuFirst,
12374        window: &mut Window,
12375        cx: &mut Context<Self>,
12376    ) {
12377        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12378            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12379        }
12380    }
12381
12382    pub fn context_menu_prev(
12383        &mut self,
12384        _: &ContextMenuPrevious,
12385        window: &mut Window,
12386        cx: &mut Context<Self>,
12387    ) {
12388        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12389            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12390        }
12391    }
12392
12393    pub fn context_menu_next(
12394        &mut self,
12395        _: &ContextMenuNext,
12396        window: &mut Window,
12397        cx: &mut Context<Self>,
12398    ) {
12399        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12400            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12401        }
12402    }
12403
12404    pub fn context_menu_last(
12405        &mut self,
12406        _: &ContextMenuLast,
12407        window: &mut Window,
12408        cx: &mut Context<Self>,
12409    ) {
12410        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12411            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12412        }
12413    }
12414
12415    pub fn move_to_previous_word_start(
12416        &mut self,
12417        _: &MoveToPreviousWordStart,
12418        window: &mut Window,
12419        cx: &mut Context<Self>,
12420    ) {
12421        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12422        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12423            s.move_cursors_with(|map, head, _| {
12424                (
12425                    movement::previous_word_start(map, head),
12426                    SelectionGoal::None,
12427                )
12428            });
12429        })
12430    }
12431
12432    pub fn move_to_previous_subword_start(
12433        &mut self,
12434        _: &MoveToPreviousSubwordStart,
12435        window: &mut Window,
12436        cx: &mut Context<Self>,
12437    ) {
12438        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12439        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12440            s.move_cursors_with(|map, head, _| {
12441                (
12442                    movement::previous_subword_start(map, head),
12443                    SelectionGoal::None,
12444                )
12445            });
12446        })
12447    }
12448
12449    pub fn select_to_previous_word_start(
12450        &mut self,
12451        _: &SelectToPreviousWordStart,
12452        window: &mut Window,
12453        cx: &mut Context<Self>,
12454    ) {
12455        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12456        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12457            s.move_heads_with(|map, head, _| {
12458                (
12459                    movement::previous_word_start(map, head),
12460                    SelectionGoal::None,
12461                )
12462            });
12463        })
12464    }
12465
12466    pub fn select_to_previous_subword_start(
12467        &mut self,
12468        _: &SelectToPreviousSubwordStart,
12469        window: &mut Window,
12470        cx: &mut Context<Self>,
12471    ) {
12472        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12473        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12474            s.move_heads_with(|map, head, _| {
12475                (
12476                    movement::previous_subword_start(map, head),
12477                    SelectionGoal::None,
12478                )
12479            });
12480        })
12481    }
12482
12483    pub fn delete_to_previous_word_start(
12484        &mut self,
12485        action: &DeleteToPreviousWordStart,
12486        window: &mut Window,
12487        cx: &mut Context<Self>,
12488    ) {
12489        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12490        self.transact(window, cx, |this, window, cx| {
12491            this.select_autoclose_pair(window, cx);
12492            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12493                s.move_with(|map, selection| {
12494                    if selection.is_empty() {
12495                        let cursor = if action.ignore_newlines {
12496                            movement::previous_word_start(map, selection.head())
12497                        } else {
12498                            movement::previous_word_start_or_newline(map, selection.head())
12499                        };
12500                        selection.set_head(cursor, SelectionGoal::None);
12501                    }
12502                });
12503            });
12504            this.insert("", window, cx);
12505        });
12506    }
12507
12508    pub fn delete_to_previous_subword_start(
12509        &mut self,
12510        _: &DeleteToPreviousSubwordStart,
12511        window: &mut Window,
12512        cx: &mut Context<Self>,
12513    ) {
12514        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12515        self.transact(window, cx, |this, window, cx| {
12516            this.select_autoclose_pair(window, cx);
12517            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12518                s.move_with(|map, selection| {
12519                    if selection.is_empty() {
12520                        let cursor = movement::previous_subword_start(map, selection.head());
12521                        selection.set_head(cursor, SelectionGoal::None);
12522                    }
12523                });
12524            });
12525            this.insert("", window, cx);
12526        });
12527    }
12528
12529    pub fn move_to_next_word_end(
12530        &mut self,
12531        _: &MoveToNextWordEnd,
12532        window: &mut Window,
12533        cx: &mut Context<Self>,
12534    ) {
12535        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12536        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12537            s.move_cursors_with(|map, head, _| {
12538                (movement::next_word_end(map, head), SelectionGoal::None)
12539            });
12540        })
12541    }
12542
12543    pub fn move_to_next_subword_end(
12544        &mut self,
12545        _: &MoveToNextSubwordEnd,
12546        window: &mut Window,
12547        cx: &mut Context<Self>,
12548    ) {
12549        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12550        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12551            s.move_cursors_with(|map, head, _| {
12552                (movement::next_subword_end(map, head), SelectionGoal::None)
12553            });
12554        })
12555    }
12556
12557    pub fn select_to_next_word_end(
12558        &mut self,
12559        _: &SelectToNextWordEnd,
12560        window: &mut Window,
12561        cx: &mut Context<Self>,
12562    ) {
12563        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12564        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12565            s.move_heads_with(|map, head, _| {
12566                (movement::next_word_end(map, head), SelectionGoal::None)
12567            });
12568        })
12569    }
12570
12571    pub fn select_to_next_subword_end(
12572        &mut self,
12573        _: &SelectToNextSubwordEnd,
12574        window: &mut Window,
12575        cx: &mut Context<Self>,
12576    ) {
12577        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12578        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12579            s.move_heads_with(|map, head, _| {
12580                (movement::next_subword_end(map, head), SelectionGoal::None)
12581            });
12582        })
12583    }
12584
12585    pub fn delete_to_next_word_end(
12586        &mut self,
12587        action: &DeleteToNextWordEnd,
12588        window: &mut Window,
12589        cx: &mut Context<Self>,
12590    ) {
12591        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12592        self.transact(window, cx, |this, window, cx| {
12593            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12594                s.move_with(|map, selection| {
12595                    if selection.is_empty() {
12596                        let cursor = if action.ignore_newlines {
12597                            movement::next_word_end(map, selection.head())
12598                        } else {
12599                            movement::next_word_end_or_newline(map, selection.head())
12600                        };
12601                        selection.set_head(cursor, SelectionGoal::None);
12602                    }
12603                });
12604            });
12605            this.insert("", window, cx);
12606        });
12607    }
12608
12609    pub fn delete_to_next_subword_end(
12610        &mut self,
12611        _: &DeleteToNextSubwordEnd,
12612        window: &mut Window,
12613        cx: &mut Context<Self>,
12614    ) {
12615        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12616        self.transact(window, cx, |this, window, cx| {
12617            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12618                s.move_with(|map, selection| {
12619                    if selection.is_empty() {
12620                        let cursor = movement::next_subword_end(map, selection.head());
12621                        selection.set_head(cursor, SelectionGoal::None);
12622                    }
12623                });
12624            });
12625            this.insert("", window, cx);
12626        });
12627    }
12628
12629    pub fn move_to_beginning_of_line(
12630        &mut self,
12631        action: &MoveToBeginningOfLine,
12632        window: &mut Window,
12633        cx: &mut Context<Self>,
12634    ) {
12635        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12636        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12637            s.move_cursors_with(|map, head, _| {
12638                (
12639                    movement::indented_line_beginning(
12640                        map,
12641                        head,
12642                        action.stop_at_soft_wraps,
12643                        action.stop_at_indent,
12644                    ),
12645                    SelectionGoal::None,
12646                )
12647            });
12648        })
12649    }
12650
12651    pub fn select_to_beginning_of_line(
12652        &mut self,
12653        action: &SelectToBeginningOfLine,
12654        window: &mut Window,
12655        cx: &mut Context<Self>,
12656    ) {
12657        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12658        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12659            s.move_heads_with(|map, head, _| {
12660                (
12661                    movement::indented_line_beginning(
12662                        map,
12663                        head,
12664                        action.stop_at_soft_wraps,
12665                        action.stop_at_indent,
12666                    ),
12667                    SelectionGoal::None,
12668                )
12669            });
12670        });
12671    }
12672
12673    pub fn delete_to_beginning_of_line(
12674        &mut self,
12675        action: &DeleteToBeginningOfLine,
12676        window: &mut Window,
12677        cx: &mut Context<Self>,
12678    ) {
12679        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12680        self.transact(window, cx, |this, window, cx| {
12681            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12682                s.move_with(|_, selection| {
12683                    selection.reversed = true;
12684                });
12685            });
12686
12687            this.select_to_beginning_of_line(
12688                &SelectToBeginningOfLine {
12689                    stop_at_soft_wraps: false,
12690                    stop_at_indent: action.stop_at_indent,
12691                },
12692                window,
12693                cx,
12694            );
12695            this.backspace(&Backspace, window, cx);
12696        });
12697    }
12698
12699    pub fn move_to_end_of_line(
12700        &mut self,
12701        action: &MoveToEndOfLine,
12702        window: &mut Window,
12703        cx: &mut Context<Self>,
12704    ) {
12705        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12706        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12707            s.move_cursors_with(|map, head, _| {
12708                (
12709                    movement::line_end(map, head, action.stop_at_soft_wraps),
12710                    SelectionGoal::None,
12711                )
12712            });
12713        })
12714    }
12715
12716    pub fn select_to_end_of_line(
12717        &mut self,
12718        action: &SelectToEndOfLine,
12719        window: &mut Window,
12720        cx: &mut Context<Self>,
12721    ) {
12722        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12723        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12724            s.move_heads_with(|map, head, _| {
12725                (
12726                    movement::line_end(map, head, action.stop_at_soft_wraps),
12727                    SelectionGoal::None,
12728                )
12729            });
12730        })
12731    }
12732
12733    pub fn delete_to_end_of_line(
12734        &mut self,
12735        _: &DeleteToEndOfLine,
12736        window: &mut Window,
12737        cx: &mut Context<Self>,
12738    ) {
12739        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12740        self.transact(window, cx, |this, window, cx| {
12741            this.select_to_end_of_line(
12742                &SelectToEndOfLine {
12743                    stop_at_soft_wraps: false,
12744                },
12745                window,
12746                cx,
12747            );
12748            this.delete(&Delete, window, cx);
12749        });
12750    }
12751
12752    pub fn cut_to_end_of_line(
12753        &mut self,
12754        _: &CutToEndOfLine,
12755        window: &mut Window,
12756        cx: &mut Context<Self>,
12757    ) {
12758        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12759        self.transact(window, cx, |this, window, cx| {
12760            this.select_to_end_of_line(
12761                &SelectToEndOfLine {
12762                    stop_at_soft_wraps: false,
12763                },
12764                window,
12765                cx,
12766            );
12767            this.cut(&Cut, window, cx);
12768        });
12769    }
12770
12771    pub fn move_to_start_of_paragraph(
12772        &mut self,
12773        _: &MoveToStartOfParagraph,
12774        window: &mut Window,
12775        cx: &mut Context<Self>,
12776    ) {
12777        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12778            cx.propagate();
12779            return;
12780        }
12781        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12782        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12783            s.move_with(|map, selection| {
12784                selection.collapse_to(
12785                    movement::start_of_paragraph(map, selection.head(), 1),
12786                    SelectionGoal::None,
12787                )
12788            });
12789        })
12790    }
12791
12792    pub fn move_to_end_of_paragraph(
12793        &mut self,
12794        _: &MoveToEndOfParagraph,
12795        window: &mut Window,
12796        cx: &mut Context<Self>,
12797    ) {
12798        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12799            cx.propagate();
12800            return;
12801        }
12802        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12803        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12804            s.move_with(|map, selection| {
12805                selection.collapse_to(
12806                    movement::end_of_paragraph(map, selection.head(), 1),
12807                    SelectionGoal::None,
12808                )
12809            });
12810        })
12811    }
12812
12813    pub fn select_to_start_of_paragraph(
12814        &mut self,
12815        _: &SelectToStartOfParagraph,
12816        window: &mut Window,
12817        cx: &mut Context<Self>,
12818    ) {
12819        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12820            cx.propagate();
12821            return;
12822        }
12823        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12824        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12825            s.move_heads_with(|map, head, _| {
12826                (
12827                    movement::start_of_paragraph(map, head, 1),
12828                    SelectionGoal::None,
12829                )
12830            });
12831        })
12832    }
12833
12834    pub fn select_to_end_of_paragraph(
12835        &mut self,
12836        _: &SelectToEndOfParagraph,
12837        window: &mut Window,
12838        cx: &mut Context<Self>,
12839    ) {
12840        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12841            cx.propagate();
12842            return;
12843        }
12844        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12845        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12846            s.move_heads_with(|map, head, _| {
12847                (
12848                    movement::end_of_paragraph(map, head, 1),
12849                    SelectionGoal::None,
12850                )
12851            });
12852        })
12853    }
12854
12855    pub fn move_to_start_of_excerpt(
12856        &mut self,
12857        _: &MoveToStartOfExcerpt,
12858        window: &mut Window,
12859        cx: &mut Context<Self>,
12860    ) {
12861        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12862            cx.propagate();
12863            return;
12864        }
12865        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12866        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12867            s.move_with(|map, selection| {
12868                selection.collapse_to(
12869                    movement::start_of_excerpt(
12870                        map,
12871                        selection.head(),
12872                        workspace::searchable::Direction::Prev,
12873                    ),
12874                    SelectionGoal::None,
12875                )
12876            });
12877        })
12878    }
12879
12880    pub fn move_to_start_of_next_excerpt(
12881        &mut self,
12882        _: &MoveToStartOfNextExcerpt,
12883        window: &mut Window,
12884        cx: &mut Context<Self>,
12885    ) {
12886        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12887            cx.propagate();
12888            return;
12889        }
12890
12891        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12892            s.move_with(|map, selection| {
12893                selection.collapse_to(
12894                    movement::start_of_excerpt(
12895                        map,
12896                        selection.head(),
12897                        workspace::searchable::Direction::Next,
12898                    ),
12899                    SelectionGoal::None,
12900                )
12901            });
12902        })
12903    }
12904
12905    pub fn move_to_end_of_excerpt(
12906        &mut self,
12907        _: &MoveToEndOfExcerpt,
12908        window: &mut Window,
12909        cx: &mut Context<Self>,
12910    ) {
12911        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12912            cx.propagate();
12913            return;
12914        }
12915        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12916        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12917            s.move_with(|map, selection| {
12918                selection.collapse_to(
12919                    movement::end_of_excerpt(
12920                        map,
12921                        selection.head(),
12922                        workspace::searchable::Direction::Next,
12923                    ),
12924                    SelectionGoal::None,
12925                )
12926            });
12927        })
12928    }
12929
12930    pub fn move_to_end_of_previous_excerpt(
12931        &mut self,
12932        _: &MoveToEndOfPreviousExcerpt,
12933        window: &mut Window,
12934        cx: &mut Context<Self>,
12935    ) {
12936        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12937            cx.propagate();
12938            return;
12939        }
12940        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12941        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12942            s.move_with(|map, selection| {
12943                selection.collapse_to(
12944                    movement::end_of_excerpt(
12945                        map,
12946                        selection.head(),
12947                        workspace::searchable::Direction::Prev,
12948                    ),
12949                    SelectionGoal::None,
12950                )
12951            });
12952        })
12953    }
12954
12955    pub fn select_to_start_of_excerpt(
12956        &mut self,
12957        _: &SelectToStartOfExcerpt,
12958        window: &mut Window,
12959        cx: &mut Context<Self>,
12960    ) {
12961        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12962            cx.propagate();
12963            return;
12964        }
12965        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12966        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12967            s.move_heads_with(|map, head, _| {
12968                (
12969                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12970                    SelectionGoal::None,
12971                )
12972            });
12973        })
12974    }
12975
12976    pub fn select_to_start_of_next_excerpt(
12977        &mut self,
12978        _: &SelectToStartOfNextExcerpt,
12979        window: &mut Window,
12980        cx: &mut Context<Self>,
12981    ) {
12982        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12983            cx.propagate();
12984            return;
12985        }
12986        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12987        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12988            s.move_heads_with(|map, head, _| {
12989                (
12990                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12991                    SelectionGoal::None,
12992                )
12993            });
12994        })
12995    }
12996
12997    pub fn select_to_end_of_excerpt(
12998        &mut self,
12999        _: &SelectToEndOfExcerpt,
13000        window: &mut Window,
13001        cx: &mut Context<Self>,
13002    ) {
13003        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13004            cx.propagate();
13005            return;
13006        }
13007        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13008        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13009            s.move_heads_with(|map, head, _| {
13010                (
13011                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13012                    SelectionGoal::None,
13013                )
13014            });
13015        })
13016    }
13017
13018    pub fn select_to_end_of_previous_excerpt(
13019        &mut self,
13020        _: &SelectToEndOfPreviousExcerpt,
13021        window: &mut Window,
13022        cx: &mut Context<Self>,
13023    ) {
13024        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13025            cx.propagate();
13026            return;
13027        }
13028        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13029        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13030            s.move_heads_with(|map, head, _| {
13031                (
13032                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13033                    SelectionGoal::None,
13034                )
13035            });
13036        })
13037    }
13038
13039    pub fn move_to_beginning(
13040        &mut self,
13041        _: &MoveToBeginning,
13042        window: &mut Window,
13043        cx: &mut Context<Self>,
13044    ) {
13045        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13046            cx.propagate();
13047            return;
13048        }
13049        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13050        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13051            s.select_ranges(vec![0..0]);
13052        });
13053    }
13054
13055    pub fn select_to_beginning(
13056        &mut self,
13057        _: &SelectToBeginning,
13058        window: &mut Window,
13059        cx: &mut Context<Self>,
13060    ) {
13061        let mut selection = self.selections.last::<Point>(cx);
13062        selection.set_head(Point::zero(), SelectionGoal::None);
13063        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13064        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13065            s.select(vec![selection]);
13066        });
13067    }
13068
13069    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13070        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13071            cx.propagate();
13072            return;
13073        }
13074        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13075        let cursor = self.buffer.read(cx).read(cx).len();
13076        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13077            s.select_ranges(vec![cursor..cursor])
13078        });
13079    }
13080
13081    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13082        self.nav_history = nav_history;
13083    }
13084
13085    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13086        self.nav_history.as_ref()
13087    }
13088
13089    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13090        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
13091    }
13092
13093    fn push_to_nav_history(
13094        &mut self,
13095        cursor_anchor: Anchor,
13096        new_position: Option<Point>,
13097        is_deactivate: bool,
13098        cx: &mut Context<Self>,
13099    ) {
13100        if let Some(nav_history) = self.nav_history.as_mut() {
13101            let buffer = self.buffer.read(cx).read(cx);
13102            let cursor_position = cursor_anchor.to_point(&buffer);
13103            let scroll_state = self.scroll_manager.anchor();
13104            let scroll_top_row = scroll_state.top_row(&buffer);
13105            drop(buffer);
13106
13107            if let Some(new_position) = new_position {
13108                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13109                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
13110                    return;
13111                }
13112            }
13113
13114            nav_history.push(
13115                Some(NavigationData {
13116                    cursor_anchor,
13117                    cursor_position,
13118                    scroll_anchor: scroll_state,
13119                    scroll_top_row,
13120                }),
13121                cx,
13122            );
13123            cx.emit(EditorEvent::PushedToNavHistory {
13124                anchor: cursor_anchor,
13125                is_deactivate,
13126            })
13127        }
13128    }
13129
13130    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13131        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13132        let buffer = self.buffer.read(cx).snapshot(cx);
13133        let mut selection = self.selections.first::<usize>(cx);
13134        selection.set_head(buffer.len(), SelectionGoal::None);
13135        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13136            s.select(vec![selection]);
13137        });
13138    }
13139
13140    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13141        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13142        let end = self.buffer.read(cx).read(cx).len();
13143        self.change_selections(None, window, cx, |s| {
13144            s.select_ranges(vec![0..end]);
13145        });
13146    }
13147
13148    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13149        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13150        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13151        let mut selections = self.selections.all::<Point>(cx);
13152        let max_point = display_map.buffer_snapshot.max_point();
13153        for selection in &mut selections {
13154            let rows = selection.spanned_rows(true, &display_map);
13155            selection.start = Point::new(rows.start.0, 0);
13156            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13157            selection.reversed = false;
13158        }
13159        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13160            s.select(selections);
13161        });
13162    }
13163
13164    pub fn split_selection_into_lines(
13165        &mut self,
13166        _: &SplitSelectionIntoLines,
13167        window: &mut Window,
13168        cx: &mut Context<Self>,
13169    ) {
13170        let selections = self
13171            .selections
13172            .all::<Point>(cx)
13173            .into_iter()
13174            .map(|selection| selection.start..selection.end)
13175            .collect::<Vec<_>>();
13176        self.unfold_ranges(&selections, true, true, cx);
13177
13178        let mut new_selection_ranges = Vec::new();
13179        {
13180            let buffer = self.buffer.read(cx).read(cx);
13181            for selection in selections {
13182                for row in selection.start.row..selection.end.row {
13183                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13184                    new_selection_ranges.push(cursor..cursor);
13185                }
13186
13187                let is_multiline_selection = selection.start.row != selection.end.row;
13188                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13189                // so this action feels more ergonomic when paired with other selection operations
13190                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13191                if !should_skip_last {
13192                    new_selection_ranges.push(selection.end..selection.end);
13193                }
13194            }
13195        }
13196        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13197            s.select_ranges(new_selection_ranges);
13198        });
13199    }
13200
13201    pub fn add_selection_above(
13202        &mut self,
13203        _: &AddSelectionAbove,
13204        window: &mut Window,
13205        cx: &mut Context<Self>,
13206    ) {
13207        self.add_selection(true, window, cx);
13208    }
13209
13210    pub fn add_selection_below(
13211        &mut self,
13212        _: &AddSelectionBelow,
13213        window: &mut Window,
13214        cx: &mut Context<Self>,
13215    ) {
13216        self.add_selection(false, window, cx);
13217    }
13218
13219    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13220        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13221
13222        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13223        let all_selections = self.selections.all::<Point>(cx);
13224        let text_layout_details = self.text_layout_details(window);
13225
13226        let (mut columnar_selections, new_selections_to_columnarize) = {
13227            if let Some(state) = self.add_selections_state.as_ref() {
13228                let columnar_selection_ids: HashSet<_> = state
13229                    .groups
13230                    .iter()
13231                    .flat_map(|group| group.stack.iter())
13232                    .copied()
13233                    .collect();
13234
13235                all_selections
13236                    .into_iter()
13237                    .partition(|s| columnar_selection_ids.contains(&s.id))
13238            } else {
13239                (Vec::new(), all_selections)
13240            }
13241        };
13242
13243        let mut state = self
13244            .add_selections_state
13245            .take()
13246            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13247
13248        for selection in new_selections_to_columnarize {
13249            let range = selection.display_range(&display_map).sorted();
13250            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13251            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13252            let positions = start_x.min(end_x)..start_x.max(end_x);
13253            let mut stack = Vec::new();
13254            for row in range.start.row().0..=range.end.row().0 {
13255                if let Some(selection) = self.selections.build_columnar_selection(
13256                    &display_map,
13257                    DisplayRow(row),
13258                    &positions,
13259                    selection.reversed,
13260                    &text_layout_details,
13261                ) {
13262                    stack.push(selection.id);
13263                    columnar_selections.push(selection);
13264                }
13265            }
13266            if !stack.is_empty() {
13267                if above {
13268                    stack.reverse();
13269                }
13270                state.groups.push(AddSelectionsGroup { above, stack });
13271            }
13272        }
13273
13274        let mut final_selections = Vec::new();
13275        let end_row = if above {
13276            DisplayRow(0)
13277        } else {
13278            display_map.max_point().row()
13279        };
13280
13281        let mut last_added_item_per_group = HashMap::default();
13282        for group in state.groups.iter_mut() {
13283            if let Some(last_id) = group.stack.last() {
13284                last_added_item_per_group.insert(*last_id, group);
13285            }
13286        }
13287
13288        for selection in columnar_selections {
13289            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13290                if above == group.above {
13291                    let range = selection.display_range(&display_map).sorted();
13292                    debug_assert_eq!(range.start.row(), range.end.row());
13293                    let mut row = range.start.row();
13294                    let positions =
13295                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13296                            px(start)..px(end)
13297                        } else {
13298                            let start_x =
13299                                display_map.x_for_display_point(range.start, &text_layout_details);
13300                            let end_x =
13301                                display_map.x_for_display_point(range.end, &text_layout_details);
13302                            start_x.min(end_x)..start_x.max(end_x)
13303                        };
13304
13305                    let mut maybe_new_selection = None;
13306                    while row != end_row {
13307                        if above {
13308                            row.0 -= 1;
13309                        } else {
13310                            row.0 += 1;
13311                        }
13312                        if let Some(new_selection) = self.selections.build_columnar_selection(
13313                            &display_map,
13314                            row,
13315                            &positions,
13316                            selection.reversed,
13317                            &text_layout_details,
13318                        ) {
13319                            maybe_new_selection = Some(new_selection);
13320                            break;
13321                        }
13322                    }
13323
13324                    if let Some(new_selection) = maybe_new_selection {
13325                        group.stack.push(new_selection.id);
13326                        if above {
13327                            final_selections.push(new_selection);
13328                            final_selections.push(selection);
13329                        } else {
13330                            final_selections.push(selection);
13331                            final_selections.push(new_selection);
13332                        }
13333                    } else {
13334                        final_selections.push(selection);
13335                    }
13336                } else {
13337                    group.stack.pop();
13338                }
13339            } else {
13340                final_selections.push(selection);
13341            }
13342        }
13343
13344        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13345            s.select(final_selections);
13346        });
13347
13348        let final_selection_ids: HashSet<_> = self
13349            .selections
13350            .all::<Point>(cx)
13351            .iter()
13352            .map(|s| s.id)
13353            .collect();
13354        state.groups.retain_mut(|group| {
13355            // selections might get merged above so we remove invalid items from stacks
13356            group.stack.retain(|id| final_selection_ids.contains(id));
13357
13358            // single selection in stack can be treated as initial state
13359            group.stack.len() > 1
13360        });
13361
13362        if !state.groups.is_empty() {
13363            self.add_selections_state = Some(state);
13364        }
13365    }
13366
13367    fn select_match_ranges(
13368        &mut self,
13369        range: Range<usize>,
13370        reversed: bool,
13371        replace_newest: bool,
13372        auto_scroll: Option<Autoscroll>,
13373        window: &mut Window,
13374        cx: &mut Context<Editor>,
13375    ) {
13376        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
13377        self.change_selections(auto_scroll, window, cx, |s| {
13378            if replace_newest {
13379                s.delete(s.newest_anchor().id);
13380            }
13381            if reversed {
13382                s.insert_range(range.end..range.start);
13383            } else {
13384                s.insert_range(range);
13385            }
13386        });
13387    }
13388
13389    pub fn select_next_match_internal(
13390        &mut self,
13391        display_map: &DisplaySnapshot,
13392        replace_newest: bool,
13393        autoscroll: Option<Autoscroll>,
13394        window: &mut Window,
13395        cx: &mut Context<Self>,
13396    ) -> Result<()> {
13397        let buffer = &display_map.buffer_snapshot;
13398        let mut selections = self.selections.all::<usize>(cx);
13399        if let Some(mut select_next_state) = self.select_next_state.take() {
13400            let query = &select_next_state.query;
13401            if !select_next_state.done {
13402                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13403                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13404                let mut next_selected_range = None;
13405
13406                let bytes_after_last_selection =
13407                    buffer.bytes_in_range(last_selection.end..buffer.len());
13408                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13409                let query_matches = query
13410                    .stream_find_iter(bytes_after_last_selection)
13411                    .map(|result| (last_selection.end, result))
13412                    .chain(
13413                        query
13414                            .stream_find_iter(bytes_before_first_selection)
13415                            .map(|result| (0, result)),
13416                    );
13417
13418                for (start_offset, query_match) in query_matches {
13419                    let query_match = query_match.unwrap(); // can only fail due to I/O
13420                    let offset_range =
13421                        start_offset + query_match.start()..start_offset + query_match.end();
13422
13423                    if !select_next_state.wordwise
13424                        || (!buffer.is_inside_word(offset_range.start, false)
13425                            && !buffer.is_inside_word(offset_range.end, false))
13426                    {
13427                        // TODO: This is n^2, because we might check all the selections
13428                        if !selections
13429                            .iter()
13430                            .any(|selection| selection.range().overlaps(&offset_range))
13431                        {
13432                            next_selected_range = Some(offset_range);
13433                            break;
13434                        }
13435                    }
13436                }
13437
13438                if let Some(next_selected_range) = next_selected_range {
13439                    self.select_match_ranges(
13440                        next_selected_range,
13441                        last_selection.reversed,
13442                        replace_newest,
13443                        autoscroll,
13444                        window,
13445                        cx,
13446                    );
13447                } else {
13448                    select_next_state.done = true;
13449                }
13450            }
13451
13452            self.select_next_state = Some(select_next_state);
13453        } else {
13454            let mut only_carets = true;
13455            let mut same_text_selected = true;
13456            let mut selected_text = None;
13457
13458            let mut selections_iter = selections.iter().peekable();
13459            while let Some(selection) = selections_iter.next() {
13460                if selection.start != selection.end {
13461                    only_carets = false;
13462                }
13463
13464                if same_text_selected {
13465                    if selected_text.is_none() {
13466                        selected_text =
13467                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13468                    }
13469
13470                    if let Some(next_selection) = selections_iter.peek() {
13471                        if next_selection.range().len() == selection.range().len() {
13472                            let next_selected_text = buffer
13473                                .text_for_range(next_selection.range())
13474                                .collect::<String>();
13475                            if Some(next_selected_text) != selected_text {
13476                                same_text_selected = false;
13477                                selected_text = None;
13478                            }
13479                        } else {
13480                            same_text_selected = false;
13481                            selected_text = None;
13482                        }
13483                    }
13484                }
13485            }
13486
13487            if only_carets {
13488                for selection in &mut selections {
13489                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13490                    selection.start = word_range.start;
13491                    selection.end = word_range.end;
13492                    selection.goal = SelectionGoal::None;
13493                    selection.reversed = false;
13494                    self.select_match_ranges(
13495                        selection.start..selection.end,
13496                        selection.reversed,
13497                        replace_newest,
13498                        autoscroll,
13499                        window,
13500                        cx,
13501                    );
13502                }
13503
13504                if selections.len() == 1 {
13505                    let selection = selections
13506                        .last()
13507                        .expect("ensured that there's only one selection");
13508                    let query = buffer
13509                        .text_for_range(selection.start..selection.end)
13510                        .collect::<String>();
13511                    let is_empty = query.is_empty();
13512                    let select_state = SelectNextState {
13513                        query: AhoCorasick::new(&[query])?,
13514                        wordwise: true,
13515                        done: is_empty,
13516                    };
13517                    self.select_next_state = Some(select_state);
13518                } else {
13519                    self.select_next_state = None;
13520                }
13521            } else if let Some(selected_text) = selected_text {
13522                self.select_next_state = Some(SelectNextState {
13523                    query: AhoCorasick::new(&[selected_text])?,
13524                    wordwise: false,
13525                    done: false,
13526                });
13527                self.select_next_match_internal(
13528                    display_map,
13529                    replace_newest,
13530                    autoscroll,
13531                    window,
13532                    cx,
13533                )?;
13534            }
13535        }
13536        Ok(())
13537    }
13538
13539    pub fn select_all_matches(
13540        &mut self,
13541        _action: &SelectAllMatches,
13542        window: &mut Window,
13543        cx: &mut Context<Self>,
13544    ) -> Result<()> {
13545        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13546
13547        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13548
13549        self.select_next_match_internal(&display_map, false, None, window, cx)?;
13550        let Some(select_next_state) = self.select_next_state.as_mut() else {
13551            return Ok(());
13552        };
13553        if select_next_state.done {
13554            return Ok(());
13555        }
13556
13557        let mut new_selections = Vec::new();
13558
13559        let reversed = self.selections.oldest::<usize>(cx).reversed;
13560        let buffer = &display_map.buffer_snapshot;
13561        let query_matches = select_next_state
13562            .query
13563            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
13564
13565        for query_match in query_matches.into_iter() {
13566            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
13567            let offset_range = if reversed {
13568                query_match.end()..query_match.start()
13569            } else {
13570                query_match.start()..query_match.end()
13571            };
13572
13573            if !select_next_state.wordwise
13574                || (!buffer.is_inside_word(offset_range.start, false)
13575                    && !buffer.is_inside_word(offset_range.end, false))
13576            {
13577                new_selections.push(offset_range.start..offset_range.end);
13578            }
13579        }
13580
13581        select_next_state.done = true;
13582
13583        if new_selections.is_empty() {
13584            log::error!("bug: new_selections is empty in select_all_matches");
13585            return Ok(());
13586        }
13587
13588        self.unfold_ranges(&new_selections.clone(), false, false, cx);
13589        self.change_selections(None, window, cx, |selections| {
13590            selections.select_ranges(new_selections)
13591        });
13592
13593        Ok(())
13594    }
13595
13596    pub fn select_next(
13597        &mut self,
13598        action: &SelectNext,
13599        window: &mut Window,
13600        cx: &mut Context<Self>,
13601    ) -> Result<()> {
13602        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13603        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13604        self.select_next_match_internal(
13605            &display_map,
13606            action.replace_newest,
13607            Some(Autoscroll::newest()),
13608            window,
13609            cx,
13610        )?;
13611        Ok(())
13612    }
13613
13614    pub fn select_previous(
13615        &mut self,
13616        action: &SelectPrevious,
13617        window: &mut Window,
13618        cx: &mut Context<Self>,
13619    ) -> Result<()> {
13620        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13621        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13622        let buffer = &display_map.buffer_snapshot;
13623        let mut selections = self.selections.all::<usize>(cx);
13624        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13625            let query = &select_prev_state.query;
13626            if !select_prev_state.done {
13627                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13628                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13629                let mut next_selected_range = None;
13630                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13631                let bytes_before_last_selection =
13632                    buffer.reversed_bytes_in_range(0..last_selection.start);
13633                let bytes_after_first_selection =
13634                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13635                let query_matches = query
13636                    .stream_find_iter(bytes_before_last_selection)
13637                    .map(|result| (last_selection.start, result))
13638                    .chain(
13639                        query
13640                            .stream_find_iter(bytes_after_first_selection)
13641                            .map(|result| (buffer.len(), result)),
13642                    );
13643                for (end_offset, query_match) in query_matches {
13644                    let query_match = query_match.unwrap(); // can only fail due to I/O
13645                    let offset_range =
13646                        end_offset - query_match.end()..end_offset - query_match.start();
13647
13648                    if !select_prev_state.wordwise
13649                        || (!buffer.is_inside_word(offset_range.start, false)
13650                            && !buffer.is_inside_word(offset_range.end, false))
13651                    {
13652                        next_selected_range = Some(offset_range);
13653                        break;
13654                    }
13655                }
13656
13657                if let Some(next_selected_range) = next_selected_range {
13658                    self.select_match_ranges(
13659                        next_selected_range,
13660                        last_selection.reversed,
13661                        action.replace_newest,
13662                        Some(Autoscroll::newest()),
13663                        window,
13664                        cx,
13665                    );
13666                } else {
13667                    select_prev_state.done = true;
13668                }
13669            }
13670
13671            self.select_prev_state = Some(select_prev_state);
13672        } else {
13673            let mut only_carets = true;
13674            let mut same_text_selected = true;
13675            let mut selected_text = None;
13676
13677            let mut selections_iter = selections.iter().peekable();
13678            while let Some(selection) = selections_iter.next() {
13679                if selection.start != selection.end {
13680                    only_carets = false;
13681                }
13682
13683                if same_text_selected {
13684                    if selected_text.is_none() {
13685                        selected_text =
13686                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13687                    }
13688
13689                    if let Some(next_selection) = selections_iter.peek() {
13690                        if next_selection.range().len() == selection.range().len() {
13691                            let next_selected_text = buffer
13692                                .text_for_range(next_selection.range())
13693                                .collect::<String>();
13694                            if Some(next_selected_text) != selected_text {
13695                                same_text_selected = false;
13696                                selected_text = None;
13697                            }
13698                        } else {
13699                            same_text_selected = false;
13700                            selected_text = None;
13701                        }
13702                    }
13703                }
13704            }
13705
13706            if only_carets {
13707                for selection in &mut selections {
13708                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13709                    selection.start = word_range.start;
13710                    selection.end = word_range.end;
13711                    selection.goal = SelectionGoal::None;
13712                    selection.reversed = false;
13713                    self.select_match_ranges(
13714                        selection.start..selection.end,
13715                        selection.reversed,
13716                        action.replace_newest,
13717                        Some(Autoscroll::newest()),
13718                        window,
13719                        cx,
13720                    );
13721                }
13722                if selections.len() == 1 {
13723                    let selection = selections
13724                        .last()
13725                        .expect("ensured that there's only one selection");
13726                    let query = buffer
13727                        .text_for_range(selection.start..selection.end)
13728                        .collect::<String>();
13729                    let is_empty = query.is_empty();
13730                    let select_state = SelectNextState {
13731                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13732                        wordwise: true,
13733                        done: is_empty,
13734                    };
13735                    self.select_prev_state = Some(select_state);
13736                } else {
13737                    self.select_prev_state = None;
13738                }
13739            } else if let Some(selected_text) = selected_text {
13740                self.select_prev_state = Some(SelectNextState {
13741                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13742                    wordwise: false,
13743                    done: false,
13744                });
13745                self.select_previous(action, window, cx)?;
13746            }
13747        }
13748        Ok(())
13749    }
13750
13751    pub fn find_next_match(
13752        &mut self,
13753        _: &FindNextMatch,
13754        window: &mut Window,
13755        cx: &mut Context<Self>,
13756    ) -> Result<()> {
13757        let selections = self.selections.disjoint_anchors();
13758        match selections.first() {
13759            Some(first) if selections.len() >= 2 => {
13760                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13761                    s.select_ranges([first.range()]);
13762                });
13763            }
13764            _ => self.select_next(
13765                &SelectNext {
13766                    replace_newest: true,
13767                },
13768                window,
13769                cx,
13770            )?,
13771        }
13772        Ok(())
13773    }
13774
13775    pub fn find_previous_match(
13776        &mut self,
13777        _: &FindPreviousMatch,
13778        window: &mut Window,
13779        cx: &mut Context<Self>,
13780    ) -> Result<()> {
13781        let selections = self.selections.disjoint_anchors();
13782        match selections.last() {
13783            Some(last) if selections.len() >= 2 => {
13784                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13785                    s.select_ranges([last.range()]);
13786                });
13787            }
13788            _ => self.select_previous(
13789                &SelectPrevious {
13790                    replace_newest: true,
13791                },
13792                window,
13793                cx,
13794            )?,
13795        }
13796        Ok(())
13797    }
13798
13799    pub fn toggle_comments(
13800        &mut self,
13801        action: &ToggleComments,
13802        window: &mut Window,
13803        cx: &mut Context<Self>,
13804    ) {
13805        if self.read_only(cx) {
13806            return;
13807        }
13808        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13809        let text_layout_details = &self.text_layout_details(window);
13810        self.transact(window, cx, |this, window, cx| {
13811            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13812            let mut edits = Vec::new();
13813            let mut selection_edit_ranges = Vec::new();
13814            let mut last_toggled_row = None;
13815            let snapshot = this.buffer.read(cx).read(cx);
13816            let empty_str: Arc<str> = Arc::default();
13817            let mut suffixes_inserted = Vec::new();
13818            let ignore_indent = action.ignore_indent;
13819
13820            fn comment_prefix_range(
13821                snapshot: &MultiBufferSnapshot,
13822                row: MultiBufferRow,
13823                comment_prefix: &str,
13824                comment_prefix_whitespace: &str,
13825                ignore_indent: bool,
13826            ) -> Range<Point> {
13827                let indent_size = if ignore_indent {
13828                    0
13829                } else {
13830                    snapshot.indent_size_for_line(row).len
13831                };
13832
13833                let start = Point::new(row.0, indent_size);
13834
13835                let mut line_bytes = snapshot
13836                    .bytes_in_range(start..snapshot.max_point())
13837                    .flatten()
13838                    .copied();
13839
13840                // If this line currently begins with the line comment prefix, then record
13841                // the range containing the prefix.
13842                if line_bytes
13843                    .by_ref()
13844                    .take(comment_prefix.len())
13845                    .eq(comment_prefix.bytes())
13846                {
13847                    // Include any whitespace that matches the comment prefix.
13848                    let matching_whitespace_len = line_bytes
13849                        .zip(comment_prefix_whitespace.bytes())
13850                        .take_while(|(a, b)| a == b)
13851                        .count() as u32;
13852                    let end = Point::new(
13853                        start.row,
13854                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13855                    );
13856                    start..end
13857                } else {
13858                    start..start
13859                }
13860            }
13861
13862            fn comment_suffix_range(
13863                snapshot: &MultiBufferSnapshot,
13864                row: MultiBufferRow,
13865                comment_suffix: &str,
13866                comment_suffix_has_leading_space: bool,
13867            ) -> Range<Point> {
13868                let end = Point::new(row.0, snapshot.line_len(row));
13869                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13870
13871                let mut line_end_bytes = snapshot
13872                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13873                    .flatten()
13874                    .copied();
13875
13876                let leading_space_len = if suffix_start_column > 0
13877                    && line_end_bytes.next() == Some(b' ')
13878                    && comment_suffix_has_leading_space
13879                {
13880                    1
13881                } else {
13882                    0
13883                };
13884
13885                // If this line currently begins with the line comment prefix, then record
13886                // the range containing the prefix.
13887                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13888                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13889                    start..end
13890                } else {
13891                    end..end
13892                }
13893            }
13894
13895            // TODO: Handle selections that cross excerpts
13896            for selection in &mut selections {
13897                let start_column = snapshot
13898                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13899                    .len;
13900                let language = if let Some(language) =
13901                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13902                {
13903                    language
13904                } else {
13905                    continue;
13906                };
13907
13908                selection_edit_ranges.clear();
13909
13910                // If multiple selections contain a given row, avoid processing that
13911                // row more than once.
13912                let mut start_row = MultiBufferRow(selection.start.row);
13913                if last_toggled_row == Some(start_row) {
13914                    start_row = start_row.next_row();
13915                }
13916                let end_row =
13917                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13918                        MultiBufferRow(selection.end.row - 1)
13919                    } else {
13920                        MultiBufferRow(selection.end.row)
13921                    };
13922                last_toggled_row = Some(end_row);
13923
13924                if start_row > end_row {
13925                    continue;
13926                }
13927
13928                // If the language has line comments, toggle those.
13929                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13930
13931                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13932                if ignore_indent {
13933                    full_comment_prefixes = full_comment_prefixes
13934                        .into_iter()
13935                        .map(|s| Arc::from(s.trim_end()))
13936                        .collect();
13937                }
13938
13939                if !full_comment_prefixes.is_empty() {
13940                    let first_prefix = full_comment_prefixes
13941                        .first()
13942                        .expect("prefixes is non-empty");
13943                    let prefix_trimmed_lengths = full_comment_prefixes
13944                        .iter()
13945                        .map(|p| p.trim_end_matches(' ').len())
13946                        .collect::<SmallVec<[usize; 4]>>();
13947
13948                    let mut all_selection_lines_are_comments = true;
13949
13950                    for row in start_row.0..=end_row.0 {
13951                        let row = MultiBufferRow(row);
13952                        if start_row < end_row && snapshot.is_line_blank(row) {
13953                            continue;
13954                        }
13955
13956                        let prefix_range = full_comment_prefixes
13957                            .iter()
13958                            .zip(prefix_trimmed_lengths.iter().copied())
13959                            .map(|(prefix, trimmed_prefix_len)| {
13960                                comment_prefix_range(
13961                                    snapshot.deref(),
13962                                    row,
13963                                    &prefix[..trimmed_prefix_len],
13964                                    &prefix[trimmed_prefix_len..],
13965                                    ignore_indent,
13966                                )
13967                            })
13968                            .max_by_key(|range| range.end.column - range.start.column)
13969                            .expect("prefixes is non-empty");
13970
13971                        if prefix_range.is_empty() {
13972                            all_selection_lines_are_comments = false;
13973                        }
13974
13975                        selection_edit_ranges.push(prefix_range);
13976                    }
13977
13978                    if all_selection_lines_are_comments {
13979                        edits.extend(
13980                            selection_edit_ranges
13981                                .iter()
13982                                .cloned()
13983                                .map(|range| (range, empty_str.clone())),
13984                        );
13985                    } else {
13986                        let min_column = selection_edit_ranges
13987                            .iter()
13988                            .map(|range| range.start.column)
13989                            .min()
13990                            .unwrap_or(0);
13991                        edits.extend(selection_edit_ranges.iter().map(|range| {
13992                            let position = Point::new(range.start.row, min_column);
13993                            (position..position, first_prefix.clone())
13994                        }));
13995                    }
13996                } else if let Some((full_comment_prefix, comment_suffix)) =
13997                    language.block_comment_delimiters()
13998                {
13999                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14000                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14001                    let prefix_range = comment_prefix_range(
14002                        snapshot.deref(),
14003                        start_row,
14004                        comment_prefix,
14005                        comment_prefix_whitespace,
14006                        ignore_indent,
14007                    );
14008                    let suffix_range = comment_suffix_range(
14009                        snapshot.deref(),
14010                        end_row,
14011                        comment_suffix.trim_start_matches(' '),
14012                        comment_suffix.starts_with(' '),
14013                    );
14014
14015                    if prefix_range.is_empty() || suffix_range.is_empty() {
14016                        edits.push((
14017                            prefix_range.start..prefix_range.start,
14018                            full_comment_prefix.clone(),
14019                        ));
14020                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14021                        suffixes_inserted.push((end_row, comment_suffix.len()));
14022                    } else {
14023                        edits.push((prefix_range, empty_str.clone()));
14024                        edits.push((suffix_range, empty_str.clone()));
14025                    }
14026                } else {
14027                    continue;
14028                }
14029            }
14030
14031            drop(snapshot);
14032            this.buffer.update(cx, |buffer, cx| {
14033                buffer.edit(edits, None, cx);
14034            });
14035
14036            // Adjust selections so that they end before any comment suffixes that
14037            // were inserted.
14038            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14039            let mut selections = this.selections.all::<Point>(cx);
14040            let snapshot = this.buffer.read(cx).read(cx);
14041            for selection in &mut selections {
14042                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14043                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14044                        Ordering::Less => {
14045                            suffixes_inserted.next();
14046                            continue;
14047                        }
14048                        Ordering::Greater => break,
14049                        Ordering::Equal => {
14050                            if selection.end.column == snapshot.line_len(row) {
14051                                if selection.is_empty() {
14052                                    selection.start.column -= suffix_len as u32;
14053                                }
14054                                selection.end.column -= suffix_len as u32;
14055                            }
14056                            break;
14057                        }
14058                    }
14059                }
14060            }
14061
14062            drop(snapshot);
14063            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14064                s.select(selections)
14065            });
14066
14067            let selections = this.selections.all::<Point>(cx);
14068            let selections_on_single_row = selections.windows(2).all(|selections| {
14069                selections[0].start.row == selections[1].start.row
14070                    && selections[0].end.row == selections[1].end.row
14071                    && selections[0].start.row == selections[0].end.row
14072            });
14073            let selections_selecting = selections
14074                .iter()
14075                .any(|selection| selection.start != selection.end);
14076            let advance_downwards = action.advance_downwards
14077                && selections_on_single_row
14078                && !selections_selecting
14079                && !matches!(this.mode, EditorMode::SingleLine { .. });
14080
14081            if advance_downwards {
14082                let snapshot = this.buffer.read(cx).snapshot(cx);
14083
14084                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14085                    s.move_cursors_with(|display_snapshot, display_point, _| {
14086                        let mut point = display_point.to_point(display_snapshot);
14087                        point.row += 1;
14088                        point = snapshot.clip_point(point, Bias::Left);
14089                        let display_point = point.to_display_point(display_snapshot);
14090                        let goal = SelectionGoal::HorizontalPosition(
14091                            display_snapshot
14092                                .x_for_display_point(display_point, text_layout_details)
14093                                .into(),
14094                        );
14095                        (display_point, goal)
14096                    })
14097                });
14098            }
14099        });
14100    }
14101
14102    pub fn select_enclosing_symbol(
14103        &mut self,
14104        _: &SelectEnclosingSymbol,
14105        window: &mut Window,
14106        cx: &mut Context<Self>,
14107    ) {
14108        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14109
14110        let buffer = self.buffer.read(cx).snapshot(cx);
14111        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14112
14113        fn update_selection(
14114            selection: &Selection<usize>,
14115            buffer_snap: &MultiBufferSnapshot,
14116        ) -> Option<Selection<usize>> {
14117            let cursor = selection.head();
14118            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14119            for symbol in symbols.iter().rev() {
14120                let start = symbol.range.start.to_offset(buffer_snap);
14121                let end = symbol.range.end.to_offset(buffer_snap);
14122                let new_range = start..end;
14123                if start < selection.start || end > selection.end {
14124                    return Some(Selection {
14125                        id: selection.id,
14126                        start: new_range.start,
14127                        end: new_range.end,
14128                        goal: SelectionGoal::None,
14129                        reversed: selection.reversed,
14130                    });
14131                }
14132            }
14133            None
14134        }
14135
14136        let mut selected_larger_symbol = false;
14137        let new_selections = old_selections
14138            .iter()
14139            .map(|selection| match update_selection(selection, &buffer) {
14140                Some(new_selection) => {
14141                    if new_selection.range() != selection.range() {
14142                        selected_larger_symbol = true;
14143                    }
14144                    new_selection
14145                }
14146                None => selection.clone(),
14147            })
14148            .collect::<Vec<_>>();
14149
14150        if selected_larger_symbol {
14151            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14152                s.select(new_selections);
14153            });
14154        }
14155    }
14156
14157    pub fn select_larger_syntax_node(
14158        &mut self,
14159        _: &SelectLargerSyntaxNode,
14160        window: &mut Window,
14161        cx: &mut Context<Self>,
14162    ) {
14163        let Some(visible_row_count) = self.visible_row_count() else {
14164            return;
14165        };
14166        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14167        if old_selections.is_empty() {
14168            return;
14169        }
14170
14171        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14172
14173        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14174        let buffer = self.buffer.read(cx).snapshot(cx);
14175
14176        let mut selected_larger_node = false;
14177        let mut new_selections = old_selections
14178            .iter()
14179            .map(|selection| {
14180                let old_range = selection.start..selection.end;
14181
14182                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14183                    // manually select word at selection
14184                    if ["string_content", "inline"].contains(&node.kind()) {
14185                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14186                        // ignore if word is already selected
14187                        if !word_range.is_empty() && old_range != word_range {
14188                            let (last_word_range, _) =
14189                                buffer.surrounding_word(old_range.end, false);
14190                            // only select word if start and end point belongs to same word
14191                            if word_range == last_word_range {
14192                                selected_larger_node = true;
14193                                return Selection {
14194                                    id: selection.id,
14195                                    start: word_range.start,
14196                                    end: word_range.end,
14197                                    goal: SelectionGoal::None,
14198                                    reversed: selection.reversed,
14199                                };
14200                            }
14201                        }
14202                    }
14203                }
14204
14205                let mut new_range = old_range.clone();
14206                while let Some((_node, containing_range)) =
14207                    buffer.syntax_ancestor(new_range.clone())
14208                {
14209                    new_range = match containing_range {
14210                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14211                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14212                    };
14213                    if !display_map.intersects_fold(new_range.start)
14214                        && !display_map.intersects_fold(new_range.end)
14215                    {
14216                        break;
14217                    }
14218                }
14219
14220                selected_larger_node |= new_range != old_range;
14221                Selection {
14222                    id: selection.id,
14223                    start: new_range.start,
14224                    end: new_range.end,
14225                    goal: SelectionGoal::None,
14226                    reversed: selection.reversed,
14227                }
14228            })
14229            .collect::<Vec<_>>();
14230
14231        if !selected_larger_node {
14232            return; // don't put this call in the history
14233        }
14234
14235        // scroll based on transformation done to the last selection created by the user
14236        let (last_old, last_new) = old_selections
14237            .last()
14238            .zip(new_selections.last().cloned())
14239            .expect("old_selections isn't empty");
14240
14241        // revert selection
14242        let is_selection_reversed = {
14243            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14244            new_selections.last_mut().expect("checked above").reversed =
14245                should_newest_selection_be_reversed;
14246            should_newest_selection_be_reversed
14247        };
14248
14249        if selected_larger_node {
14250            self.select_syntax_node_history.disable_clearing = true;
14251            self.change_selections(None, window, cx, |s| {
14252                s.select(new_selections.clone());
14253            });
14254            self.select_syntax_node_history.disable_clearing = false;
14255        }
14256
14257        let start_row = last_new.start.to_display_point(&display_map).row().0;
14258        let end_row = last_new.end.to_display_point(&display_map).row().0;
14259        let selection_height = end_row - start_row + 1;
14260        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14261
14262        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14263        let scroll_behavior = if fits_on_the_screen {
14264            self.request_autoscroll(Autoscroll::fit(), cx);
14265            SelectSyntaxNodeScrollBehavior::FitSelection
14266        } else if is_selection_reversed {
14267            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14268            SelectSyntaxNodeScrollBehavior::CursorTop
14269        } else {
14270            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14271            SelectSyntaxNodeScrollBehavior::CursorBottom
14272        };
14273
14274        self.select_syntax_node_history.push((
14275            old_selections,
14276            scroll_behavior,
14277            is_selection_reversed,
14278        ));
14279    }
14280
14281    pub fn select_smaller_syntax_node(
14282        &mut self,
14283        _: &SelectSmallerSyntaxNode,
14284        window: &mut Window,
14285        cx: &mut Context<Self>,
14286    ) {
14287        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14288
14289        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14290            self.select_syntax_node_history.pop()
14291        {
14292            if let Some(selection) = selections.last_mut() {
14293                selection.reversed = is_selection_reversed;
14294            }
14295
14296            self.select_syntax_node_history.disable_clearing = true;
14297            self.change_selections(None, window, cx, |s| {
14298                s.select(selections.to_vec());
14299            });
14300            self.select_syntax_node_history.disable_clearing = false;
14301
14302            match scroll_behavior {
14303                SelectSyntaxNodeScrollBehavior::CursorTop => {
14304                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14305                }
14306                SelectSyntaxNodeScrollBehavior::FitSelection => {
14307                    self.request_autoscroll(Autoscroll::fit(), cx);
14308                }
14309                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14310                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14311                }
14312            }
14313        }
14314    }
14315
14316    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14317        if !EditorSettings::get_global(cx).gutter.runnables {
14318            self.clear_tasks();
14319            return Task::ready(());
14320        }
14321        let project = self.project.as_ref().map(Entity::downgrade);
14322        let task_sources = self.lsp_task_sources(cx);
14323        let multi_buffer = self.buffer.downgrade();
14324        cx.spawn_in(window, async move |editor, cx| {
14325            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14326            let Some(project) = project.and_then(|p| p.upgrade()) else {
14327                return;
14328            };
14329            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14330                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14331            }) else {
14332                return;
14333            };
14334
14335            let hide_runnables = project
14336                .update(cx, |project, cx| {
14337                    // Do not display any test indicators in non-dev server remote projects.
14338                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14339                })
14340                .unwrap_or(true);
14341            if hide_runnables {
14342                return;
14343            }
14344            let new_rows =
14345                cx.background_spawn({
14346                    let snapshot = display_snapshot.clone();
14347                    async move {
14348                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14349                    }
14350                })
14351                    .await;
14352            let Ok(lsp_tasks) =
14353                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14354            else {
14355                return;
14356            };
14357            let lsp_tasks = lsp_tasks.await;
14358
14359            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14360                lsp_tasks
14361                    .into_iter()
14362                    .flat_map(|(kind, tasks)| {
14363                        tasks.into_iter().filter_map(move |(location, task)| {
14364                            Some((kind.clone(), location?, task))
14365                        })
14366                    })
14367                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14368                        let buffer = location.target.buffer;
14369                        let buffer_snapshot = buffer.read(cx).snapshot();
14370                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14371                            |(excerpt_id, snapshot, _)| {
14372                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14373                                    display_snapshot
14374                                        .buffer_snapshot
14375                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14376                                } else {
14377                                    None
14378                                }
14379                            },
14380                        );
14381                        if let Some(offset) = offset {
14382                            let task_buffer_range =
14383                                location.target.range.to_point(&buffer_snapshot);
14384                            let context_buffer_range =
14385                                task_buffer_range.to_offset(&buffer_snapshot);
14386                            let context_range = BufferOffset(context_buffer_range.start)
14387                                ..BufferOffset(context_buffer_range.end);
14388
14389                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14390                                .or_insert_with(|| RunnableTasks {
14391                                    templates: Vec::new(),
14392                                    offset,
14393                                    column: task_buffer_range.start.column,
14394                                    extra_variables: HashMap::default(),
14395                                    context_range,
14396                                })
14397                                .templates
14398                                .push((kind, task.original_task().clone()));
14399                        }
14400
14401                        acc
14402                    })
14403            }) else {
14404                return;
14405            };
14406
14407            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14408                buffer.language_settings(cx).tasks.prefer_lsp
14409            }) else {
14410                return;
14411            };
14412
14413            let rows = Self::runnable_rows(
14414                project,
14415                display_snapshot,
14416                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14417                new_rows,
14418                cx.clone(),
14419            )
14420            .await;
14421            editor
14422                .update(cx, |editor, _| {
14423                    editor.clear_tasks();
14424                    for (key, mut value) in rows {
14425                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14426                            value.templates.extend(lsp_tasks.templates);
14427                        }
14428
14429                        editor.insert_tasks(key, value);
14430                    }
14431                    for (key, value) in lsp_tasks_by_rows {
14432                        editor.insert_tasks(key, value);
14433                    }
14434                })
14435                .ok();
14436        })
14437    }
14438    fn fetch_runnable_ranges(
14439        snapshot: &DisplaySnapshot,
14440        range: Range<Anchor>,
14441    ) -> Vec<language::RunnableRange> {
14442        snapshot.buffer_snapshot.runnable_ranges(range).collect()
14443    }
14444
14445    fn runnable_rows(
14446        project: Entity<Project>,
14447        snapshot: DisplaySnapshot,
14448        prefer_lsp: bool,
14449        runnable_ranges: Vec<RunnableRange>,
14450        cx: AsyncWindowContext,
14451    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
14452        cx.spawn(async move |cx| {
14453            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
14454            for mut runnable in runnable_ranges {
14455                let Some(tasks) = cx
14456                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
14457                    .ok()
14458                else {
14459                    continue;
14460                };
14461                let mut tasks = tasks.await;
14462
14463                if prefer_lsp {
14464                    tasks.retain(|(task_kind, _)| {
14465                        !matches!(task_kind, TaskSourceKind::Language { .. })
14466                    });
14467                }
14468                if tasks.is_empty() {
14469                    continue;
14470                }
14471
14472                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
14473                let Some(row) = snapshot
14474                    .buffer_snapshot
14475                    .buffer_line_for_row(MultiBufferRow(point.row))
14476                    .map(|(_, range)| range.start.row)
14477                else {
14478                    continue;
14479                };
14480
14481                let context_range =
14482                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
14483                runnable_rows.push((
14484                    (runnable.buffer_id, row),
14485                    RunnableTasks {
14486                        templates: tasks,
14487                        offset: snapshot
14488                            .buffer_snapshot
14489                            .anchor_before(runnable.run_range.start),
14490                        context_range,
14491                        column: point.column,
14492                        extra_variables: runnable.extra_captures,
14493                    },
14494                ));
14495            }
14496            runnable_rows
14497        })
14498    }
14499
14500    fn templates_with_tags(
14501        project: &Entity<Project>,
14502        runnable: &mut Runnable,
14503        cx: &mut App,
14504    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
14505        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
14506            let (worktree_id, file) = project
14507                .buffer_for_id(runnable.buffer, cx)
14508                .and_then(|buffer| buffer.read(cx).file())
14509                .map(|file| (file.worktree_id(cx), file.clone()))
14510                .unzip();
14511
14512            (
14513                project.task_store().read(cx).task_inventory().cloned(),
14514                worktree_id,
14515                file,
14516            )
14517        });
14518
14519        let tags = mem::take(&mut runnable.tags);
14520        let language = runnable.language.clone();
14521        cx.spawn(async move |cx| {
14522            let mut templates_with_tags = Vec::new();
14523            if let Some(inventory) = inventory {
14524                for RunnableTag(tag) in tags {
14525                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
14526                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
14527                    }) else {
14528                        return templates_with_tags;
14529                    };
14530                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
14531                        move |(_, template)| {
14532                            template.tags.iter().any(|source_tag| source_tag == &tag)
14533                        },
14534                    ));
14535                }
14536            }
14537            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
14538
14539            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
14540                // Strongest source wins; if we have worktree tag binding, prefer that to
14541                // global and language bindings;
14542                // if we have a global binding, prefer that to language binding.
14543                let first_mismatch = templates_with_tags
14544                    .iter()
14545                    .position(|(tag_source, _)| tag_source != leading_tag_source);
14546                if let Some(index) = first_mismatch {
14547                    templates_with_tags.truncate(index);
14548                }
14549            }
14550
14551            templates_with_tags
14552        })
14553    }
14554
14555    pub fn move_to_enclosing_bracket(
14556        &mut self,
14557        _: &MoveToEnclosingBracket,
14558        window: &mut Window,
14559        cx: &mut Context<Self>,
14560    ) {
14561        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14562        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14563            s.move_offsets_with(|snapshot, selection| {
14564                let Some(enclosing_bracket_ranges) =
14565                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
14566                else {
14567                    return;
14568                };
14569
14570                let mut best_length = usize::MAX;
14571                let mut best_inside = false;
14572                let mut best_in_bracket_range = false;
14573                let mut best_destination = None;
14574                for (open, close) in enclosing_bracket_ranges {
14575                    let close = close.to_inclusive();
14576                    let length = close.end() - open.start;
14577                    let inside = selection.start >= open.end && selection.end <= *close.start();
14578                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
14579                        || close.contains(&selection.head());
14580
14581                    // If best is next to a bracket and current isn't, skip
14582                    if !in_bracket_range && best_in_bracket_range {
14583                        continue;
14584                    }
14585
14586                    // Prefer smaller lengths unless best is inside and current isn't
14587                    if length > best_length && (best_inside || !inside) {
14588                        continue;
14589                    }
14590
14591                    best_length = length;
14592                    best_inside = inside;
14593                    best_in_bracket_range = in_bracket_range;
14594                    best_destination = Some(
14595                        if close.contains(&selection.start) && close.contains(&selection.end) {
14596                            if inside { open.end } else { open.start }
14597                        } else if inside {
14598                            *close.start()
14599                        } else {
14600                            *close.end()
14601                        },
14602                    );
14603                }
14604
14605                if let Some(destination) = best_destination {
14606                    selection.collapse_to(destination, SelectionGoal::None);
14607                }
14608            })
14609        });
14610    }
14611
14612    pub fn undo_selection(
14613        &mut self,
14614        _: &UndoSelection,
14615        window: &mut Window,
14616        cx: &mut Context<Self>,
14617    ) {
14618        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14619        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14620            self.selection_history.mode = SelectionHistoryMode::Undoing;
14621            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14622                this.end_selection(window, cx);
14623                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14624                    s.select_anchors(entry.selections.to_vec())
14625                });
14626            });
14627            self.selection_history.mode = SelectionHistoryMode::Normal;
14628
14629            self.select_next_state = entry.select_next_state;
14630            self.select_prev_state = entry.select_prev_state;
14631            self.add_selections_state = entry.add_selections_state;
14632        }
14633    }
14634
14635    pub fn redo_selection(
14636        &mut self,
14637        _: &RedoSelection,
14638        window: &mut Window,
14639        cx: &mut Context<Self>,
14640    ) {
14641        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14642        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14643            self.selection_history.mode = SelectionHistoryMode::Redoing;
14644            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
14645                this.end_selection(window, cx);
14646                this.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
14647                    s.select_anchors(entry.selections.to_vec())
14648                });
14649            });
14650            self.selection_history.mode = SelectionHistoryMode::Normal;
14651
14652            self.select_next_state = entry.select_next_state;
14653            self.select_prev_state = entry.select_prev_state;
14654            self.add_selections_state = entry.add_selections_state;
14655        }
14656    }
14657
14658    pub fn expand_excerpts(
14659        &mut self,
14660        action: &ExpandExcerpts,
14661        _: &mut Window,
14662        cx: &mut Context<Self>,
14663    ) {
14664        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14665    }
14666
14667    pub fn expand_excerpts_down(
14668        &mut self,
14669        action: &ExpandExcerptsDown,
14670        _: &mut Window,
14671        cx: &mut Context<Self>,
14672    ) {
14673        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14674    }
14675
14676    pub fn expand_excerpts_up(
14677        &mut self,
14678        action: &ExpandExcerptsUp,
14679        _: &mut Window,
14680        cx: &mut Context<Self>,
14681    ) {
14682        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14683    }
14684
14685    pub fn expand_excerpts_for_direction(
14686        &mut self,
14687        lines: u32,
14688        direction: ExpandExcerptDirection,
14689
14690        cx: &mut Context<Self>,
14691    ) {
14692        let selections = self.selections.disjoint_anchors();
14693
14694        let lines = if lines == 0 {
14695            EditorSettings::get_global(cx).expand_excerpt_lines
14696        } else {
14697            lines
14698        };
14699
14700        self.buffer.update(cx, |buffer, cx| {
14701            let snapshot = buffer.snapshot(cx);
14702            let mut excerpt_ids = selections
14703                .iter()
14704                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14705                .collect::<Vec<_>>();
14706            excerpt_ids.sort();
14707            excerpt_ids.dedup();
14708            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14709        })
14710    }
14711
14712    pub fn expand_excerpt(
14713        &mut self,
14714        excerpt: ExcerptId,
14715        direction: ExpandExcerptDirection,
14716        window: &mut Window,
14717        cx: &mut Context<Self>,
14718    ) {
14719        let current_scroll_position = self.scroll_position(cx);
14720        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14721        let mut should_scroll_up = false;
14722
14723        if direction == ExpandExcerptDirection::Down {
14724            let multi_buffer = self.buffer.read(cx);
14725            let snapshot = multi_buffer.snapshot(cx);
14726            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14727                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14728                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14729                        let buffer_snapshot = buffer.read(cx).snapshot();
14730                        let excerpt_end_row =
14731                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14732                        let last_row = buffer_snapshot.max_point().row;
14733                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14734                        should_scroll_up = lines_below >= lines_to_expand;
14735                    }
14736                }
14737            }
14738        }
14739
14740        self.buffer.update(cx, |buffer, cx| {
14741            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14742        });
14743
14744        if should_scroll_up {
14745            let new_scroll_position =
14746                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14747            self.set_scroll_position(new_scroll_position, window, cx);
14748        }
14749    }
14750
14751    pub fn go_to_singleton_buffer_point(
14752        &mut self,
14753        point: Point,
14754        window: &mut Window,
14755        cx: &mut Context<Self>,
14756    ) {
14757        self.go_to_singleton_buffer_range(point..point, window, cx);
14758    }
14759
14760    pub fn go_to_singleton_buffer_range(
14761        &mut self,
14762        range: Range<Point>,
14763        window: &mut Window,
14764        cx: &mut Context<Self>,
14765    ) {
14766        let multibuffer = self.buffer().read(cx);
14767        let Some(buffer) = multibuffer.as_singleton() else {
14768            return;
14769        };
14770        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14771            return;
14772        };
14773        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14774            return;
14775        };
14776        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14777            s.select_anchor_ranges([start..end])
14778        });
14779    }
14780
14781    pub fn go_to_diagnostic(
14782        &mut self,
14783        _: &GoToDiagnostic,
14784        window: &mut Window,
14785        cx: &mut Context<Self>,
14786    ) {
14787        if !self.diagnostics_enabled() {
14788            return;
14789        }
14790        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14791        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14792    }
14793
14794    pub fn go_to_prev_diagnostic(
14795        &mut self,
14796        _: &GoToPreviousDiagnostic,
14797        window: &mut Window,
14798        cx: &mut Context<Self>,
14799    ) {
14800        if !self.diagnostics_enabled() {
14801            return;
14802        }
14803        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14804        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14805    }
14806
14807    pub fn go_to_diagnostic_impl(
14808        &mut self,
14809        direction: Direction,
14810        window: &mut Window,
14811        cx: &mut Context<Self>,
14812    ) {
14813        let buffer = self.buffer.read(cx).snapshot(cx);
14814        let selection = self.selections.newest::<usize>(cx);
14815
14816        let mut active_group_id = None;
14817        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14818            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14819                active_group_id = Some(active_group.group_id);
14820            }
14821        }
14822
14823        fn filtered(
14824            snapshot: EditorSnapshot,
14825            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14826        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14827            diagnostics
14828                .filter(|entry| entry.range.start != entry.range.end)
14829                .filter(|entry| !entry.diagnostic.is_unnecessary)
14830                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14831        }
14832
14833        let snapshot = self.snapshot(window, cx);
14834        let before = filtered(
14835            snapshot.clone(),
14836            buffer
14837                .diagnostics_in_range(0..selection.start)
14838                .filter(|entry| entry.range.start <= selection.start),
14839        );
14840        let after = filtered(
14841            snapshot,
14842            buffer
14843                .diagnostics_in_range(selection.start..buffer.len())
14844                .filter(|entry| entry.range.start >= selection.start),
14845        );
14846
14847        let mut found: Option<DiagnosticEntry<usize>> = None;
14848        if direction == Direction::Prev {
14849            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14850            {
14851                for diagnostic in prev_diagnostics.into_iter().rev() {
14852                    if diagnostic.range.start != selection.start
14853                        || active_group_id
14854                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14855                    {
14856                        found = Some(diagnostic);
14857                        break 'outer;
14858                    }
14859                }
14860            }
14861        } else {
14862            for diagnostic in after.chain(before) {
14863                if diagnostic.range.start != selection.start
14864                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14865                {
14866                    found = Some(diagnostic);
14867                    break;
14868                }
14869            }
14870        }
14871        let Some(next_diagnostic) = found else {
14872            return;
14873        };
14874
14875        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14876            return;
14877        };
14878        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14879            s.select_ranges(vec![
14880                next_diagnostic.range.start..next_diagnostic.range.start,
14881            ])
14882        });
14883        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14884        self.refresh_inline_completion(false, true, window, cx);
14885    }
14886
14887    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14888        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14889        let snapshot = self.snapshot(window, cx);
14890        let selection = self.selections.newest::<Point>(cx);
14891        self.go_to_hunk_before_or_after_position(
14892            &snapshot,
14893            selection.head(),
14894            Direction::Next,
14895            window,
14896            cx,
14897        );
14898    }
14899
14900    pub fn go_to_hunk_before_or_after_position(
14901        &mut self,
14902        snapshot: &EditorSnapshot,
14903        position: Point,
14904        direction: Direction,
14905        window: &mut Window,
14906        cx: &mut Context<Editor>,
14907    ) {
14908        let row = if direction == Direction::Next {
14909            self.hunk_after_position(snapshot, position)
14910                .map(|hunk| hunk.row_range.start)
14911        } else {
14912            self.hunk_before_position(snapshot, position)
14913        };
14914
14915        if let Some(row) = row {
14916            let destination = Point::new(row.0, 0);
14917            let autoscroll = Autoscroll::center();
14918
14919            self.unfold_ranges(&[destination..destination], false, false, cx);
14920            self.change_selections(Some(autoscroll), window, cx, |s| {
14921                s.select_ranges([destination..destination]);
14922            });
14923        }
14924    }
14925
14926    fn hunk_after_position(
14927        &mut self,
14928        snapshot: &EditorSnapshot,
14929        position: Point,
14930    ) -> Option<MultiBufferDiffHunk> {
14931        snapshot
14932            .buffer_snapshot
14933            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14934            .find(|hunk| hunk.row_range.start.0 > position.row)
14935            .or_else(|| {
14936                snapshot
14937                    .buffer_snapshot
14938                    .diff_hunks_in_range(Point::zero()..position)
14939                    .find(|hunk| hunk.row_range.end.0 < position.row)
14940            })
14941    }
14942
14943    fn go_to_prev_hunk(
14944        &mut self,
14945        _: &GoToPreviousHunk,
14946        window: &mut Window,
14947        cx: &mut Context<Self>,
14948    ) {
14949        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14950        let snapshot = self.snapshot(window, cx);
14951        let selection = self.selections.newest::<Point>(cx);
14952        self.go_to_hunk_before_or_after_position(
14953            &snapshot,
14954            selection.head(),
14955            Direction::Prev,
14956            window,
14957            cx,
14958        );
14959    }
14960
14961    fn hunk_before_position(
14962        &mut self,
14963        snapshot: &EditorSnapshot,
14964        position: Point,
14965    ) -> Option<MultiBufferRow> {
14966        snapshot
14967            .buffer_snapshot
14968            .diff_hunk_before(position)
14969            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14970    }
14971
14972    fn go_to_next_change(
14973        &mut self,
14974        _: &GoToNextChange,
14975        window: &mut Window,
14976        cx: &mut Context<Self>,
14977    ) {
14978        if let Some(selections) = self
14979            .change_list
14980            .next_change(1, Direction::Next)
14981            .map(|s| s.to_vec())
14982        {
14983            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14984                let map = s.display_map();
14985                s.select_display_ranges(selections.iter().map(|a| {
14986                    let point = a.to_display_point(&map);
14987                    point..point
14988                }))
14989            })
14990        }
14991    }
14992
14993    fn go_to_previous_change(
14994        &mut self,
14995        _: &GoToPreviousChange,
14996        window: &mut Window,
14997        cx: &mut Context<Self>,
14998    ) {
14999        if let Some(selections) = self
15000            .change_list
15001            .next_change(1, Direction::Prev)
15002            .map(|s| s.to_vec())
15003        {
15004            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15005                let map = s.display_map();
15006                s.select_display_ranges(selections.iter().map(|a| {
15007                    let point = a.to_display_point(&map);
15008                    point..point
15009                }))
15010            })
15011        }
15012    }
15013
15014    fn go_to_line<T: 'static>(
15015        &mut self,
15016        position: Anchor,
15017        highlight_color: Option<Hsla>,
15018        window: &mut Window,
15019        cx: &mut Context<Self>,
15020    ) {
15021        let snapshot = self.snapshot(window, cx).display_snapshot;
15022        let position = position.to_point(&snapshot.buffer_snapshot);
15023        let start = snapshot
15024            .buffer_snapshot
15025            .clip_point(Point::new(position.row, 0), Bias::Left);
15026        let end = start + Point::new(1, 0);
15027        let start = snapshot.buffer_snapshot.anchor_before(start);
15028        let end = snapshot.buffer_snapshot.anchor_before(end);
15029
15030        self.highlight_rows::<T>(
15031            start..end,
15032            highlight_color
15033                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15034            Default::default(),
15035            cx,
15036        );
15037
15038        if self.buffer.read(cx).is_singleton() {
15039            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15040        }
15041    }
15042
15043    pub fn go_to_definition(
15044        &mut self,
15045        _: &GoToDefinition,
15046        window: &mut Window,
15047        cx: &mut Context<Self>,
15048    ) -> Task<Result<Navigated>> {
15049        let definition =
15050            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15051        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15052        cx.spawn_in(window, async move |editor, cx| {
15053            if definition.await? == Navigated::Yes {
15054                return Ok(Navigated::Yes);
15055            }
15056            match fallback_strategy {
15057                GoToDefinitionFallback::None => Ok(Navigated::No),
15058                GoToDefinitionFallback::FindAllReferences => {
15059                    match editor.update_in(cx, |editor, window, cx| {
15060                        editor.find_all_references(&FindAllReferences, window, cx)
15061                    })? {
15062                        Some(references) => references.await,
15063                        None => Ok(Navigated::No),
15064                    }
15065                }
15066            }
15067        })
15068    }
15069
15070    pub fn go_to_declaration(
15071        &mut self,
15072        _: &GoToDeclaration,
15073        window: &mut Window,
15074        cx: &mut Context<Self>,
15075    ) -> Task<Result<Navigated>> {
15076        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15077    }
15078
15079    pub fn go_to_declaration_split(
15080        &mut self,
15081        _: &GoToDeclaration,
15082        window: &mut Window,
15083        cx: &mut Context<Self>,
15084    ) -> Task<Result<Navigated>> {
15085        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15086    }
15087
15088    pub fn go_to_implementation(
15089        &mut self,
15090        _: &GoToImplementation,
15091        window: &mut Window,
15092        cx: &mut Context<Self>,
15093    ) -> Task<Result<Navigated>> {
15094        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15095    }
15096
15097    pub fn go_to_implementation_split(
15098        &mut self,
15099        _: &GoToImplementationSplit,
15100        window: &mut Window,
15101        cx: &mut Context<Self>,
15102    ) -> Task<Result<Navigated>> {
15103        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15104    }
15105
15106    pub fn go_to_type_definition(
15107        &mut self,
15108        _: &GoToTypeDefinition,
15109        window: &mut Window,
15110        cx: &mut Context<Self>,
15111    ) -> Task<Result<Navigated>> {
15112        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15113    }
15114
15115    pub fn go_to_definition_split(
15116        &mut self,
15117        _: &GoToDefinitionSplit,
15118        window: &mut Window,
15119        cx: &mut Context<Self>,
15120    ) -> Task<Result<Navigated>> {
15121        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15122    }
15123
15124    pub fn go_to_type_definition_split(
15125        &mut self,
15126        _: &GoToTypeDefinitionSplit,
15127        window: &mut Window,
15128        cx: &mut Context<Self>,
15129    ) -> Task<Result<Navigated>> {
15130        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15131    }
15132
15133    fn go_to_definition_of_kind(
15134        &mut self,
15135        kind: GotoDefinitionKind,
15136        split: bool,
15137        window: &mut Window,
15138        cx: &mut Context<Self>,
15139    ) -> Task<Result<Navigated>> {
15140        let Some(provider) = self.semantics_provider.clone() else {
15141            return Task::ready(Ok(Navigated::No));
15142        };
15143        let head = self.selections.newest::<usize>(cx).head();
15144        let buffer = self.buffer.read(cx);
15145        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
15146            text_anchor
15147        } else {
15148            return Task::ready(Ok(Navigated::No));
15149        };
15150
15151        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15152            return Task::ready(Ok(Navigated::No));
15153        };
15154
15155        cx.spawn_in(window, async move |editor, cx| {
15156            let definitions = definitions.await?;
15157            let navigated = editor
15158                .update_in(cx, |editor, window, cx| {
15159                    editor.navigate_to_hover_links(
15160                        Some(kind),
15161                        definitions
15162                            .into_iter()
15163                            .filter(|location| {
15164                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15165                            })
15166                            .map(HoverLink::Text)
15167                            .collect::<Vec<_>>(),
15168                        split,
15169                        window,
15170                        cx,
15171                    )
15172                })?
15173                .await?;
15174            anyhow::Ok(navigated)
15175        })
15176    }
15177
15178    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15179        let selection = self.selections.newest_anchor();
15180        let head = selection.head();
15181        let tail = selection.tail();
15182
15183        let Some((buffer, start_position)) =
15184            self.buffer.read(cx).text_anchor_for_position(head, cx)
15185        else {
15186            return;
15187        };
15188
15189        let end_position = if head != tail {
15190            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15191                return;
15192            };
15193            Some(pos)
15194        } else {
15195            None
15196        };
15197
15198        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15199            let url = if let Some(end_pos) = end_position {
15200                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15201            } else {
15202                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15203            };
15204
15205            if let Some(url) = url {
15206                editor.update(cx, |_, cx| {
15207                    cx.open_url(&url);
15208                })
15209            } else {
15210                Ok(())
15211            }
15212        });
15213
15214        url_finder.detach();
15215    }
15216
15217    pub fn open_selected_filename(
15218        &mut self,
15219        _: &OpenSelectedFilename,
15220        window: &mut Window,
15221        cx: &mut Context<Self>,
15222    ) {
15223        let Some(workspace) = self.workspace() else {
15224            return;
15225        };
15226
15227        let position = self.selections.newest_anchor().head();
15228
15229        let Some((buffer, buffer_position)) =
15230            self.buffer.read(cx).text_anchor_for_position(position, cx)
15231        else {
15232            return;
15233        };
15234
15235        let project = self.project.clone();
15236
15237        cx.spawn_in(window, async move |_, cx| {
15238            let result = find_file(&buffer, project, buffer_position, cx).await;
15239
15240            if let Some((_, path)) = result {
15241                workspace
15242                    .update_in(cx, |workspace, window, cx| {
15243                        workspace.open_resolved_path(path, window, cx)
15244                    })?
15245                    .await?;
15246            }
15247            anyhow::Ok(())
15248        })
15249        .detach();
15250    }
15251
15252    pub(crate) fn navigate_to_hover_links(
15253        &mut self,
15254        kind: Option<GotoDefinitionKind>,
15255        mut definitions: Vec<HoverLink>,
15256        split: bool,
15257        window: &mut Window,
15258        cx: &mut Context<Editor>,
15259    ) -> Task<Result<Navigated>> {
15260        // If there is one definition, just open it directly
15261        if definitions.len() == 1 {
15262            let definition = definitions.pop().unwrap();
15263
15264            enum TargetTaskResult {
15265                Location(Option<Location>),
15266                AlreadyNavigated,
15267            }
15268
15269            let target_task = match definition {
15270                HoverLink::Text(link) => {
15271                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
15272                }
15273                HoverLink::InlayHint(lsp_location, server_id) => {
15274                    let computation =
15275                        self.compute_target_location(lsp_location, server_id, window, cx);
15276                    cx.background_spawn(async move {
15277                        let location = computation.await?;
15278                        Ok(TargetTaskResult::Location(location))
15279                    })
15280                }
15281                HoverLink::Url(url) => {
15282                    cx.open_url(&url);
15283                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
15284                }
15285                HoverLink::File(path) => {
15286                    if let Some(workspace) = self.workspace() {
15287                        cx.spawn_in(window, async move |_, cx| {
15288                            workspace
15289                                .update_in(cx, |workspace, window, cx| {
15290                                    workspace.open_resolved_path(path, window, cx)
15291                                })?
15292                                .await
15293                                .map(|_| TargetTaskResult::AlreadyNavigated)
15294                        })
15295                    } else {
15296                        Task::ready(Ok(TargetTaskResult::Location(None)))
15297                    }
15298                }
15299            };
15300            cx.spawn_in(window, async move |editor, cx| {
15301                let target = match target_task.await.context("target resolution task")? {
15302                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
15303                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
15304                    TargetTaskResult::Location(Some(target)) => target,
15305                };
15306
15307                editor.update_in(cx, |editor, window, cx| {
15308                    let Some(workspace) = editor.workspace() else {
15309                        return Navigated::No;
15310                    };
15311                    let pane = workspace.read(cx).active_pane().clone();
15312
15313                    let range = target.range.to_point(target.buffer.read(cx));
15314                    let range = editor.range_for_match(&range);
15315                    let range = collapse_multiline_range(range);
15316
15317                    if !split
15318                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15319                    {
15320                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15321                    } else {
15322                        window.defer(cx, move |window, cx| {
15323                            let target_editor: Entity<Self> =
15324                                workspace.update(cx, |workspace, cx| {
15325                                    let pane = if split {
15326                                        workspace.adjacent_pane(window, cx)
15327                                    } else {
15328                                        workspace.active_pane().clone()
15329                                    };
15330
15331                                    workspace.open_project_item(
15332                                        pane,
15333                                        target.buffer.clone(),
15334                                        true,
15335                                        true,
15336                                        window,
15337                                        cx,
15338                                    )
15339                                });
15340                            target_editor.update(cx, |target_editor, cx| {
15341                                // When selecting a definition in a different buffer, disable the nav history
15342                                // to avoid creating a history entry at the previous cursor location.
15343                                pane.update(cx, |pane, _| pane.disable_history());
15344                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15345                                pane.update(cx, |pane, _| pane.enable_history());
15346                            });
15347                        });
15348                    }
15349                    Navigated::Yes
15350                })
15351            })
15352        } else if !definitions.is_empty() {
15353            cx.spawn_in(window, async move |editor, cx| {
15354                let (title, location_tasks, workspace) = editor
15355                    .update_in(cx, |editor, window, cx| {
15356                        let tab_kind = match kind {
15357                            Some(GotoDefinitionKind::Implementation) => "Implementations",
15358                            _ => "Definitions",
15359                        };
15360                        let title = definitions
15361                            .iter()
15362                            .find_map(|definition| match definition {
15363                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
15364                                    let buffer = origin.buffer.read(cx);
15365                                    format!(
15366                                        "{} for {}",
15367                                        tab_kind,
15368                                        buffer
15369                                            .text_for_range(origin.range.clone())
15370                                            .collect::<String>()
15371                                    )
15372                                }),
15373                                HoverLink::InlayHint(_, _) => None,
15374                                HoverLink::Url(_) => None,
15375                                HoverLink::File(_) => None,
15376                            })
15377                            .unwrap_or(tab_kind.to_string());
15378                        let location_tasks = definitions
15379                            .into_iter()
15380                            .map(|definition| match definition {
15381                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
15382                                HoverLink::InlayHint(lsp_location, server_id) => editor
15383                                    .compute_target_location(lsp_location, server_id, window, cx),
15384                                HoverLink::Url(_) => Task::ready(Ok(None)),
15385                                HoverLink::File(_) => Task::ready(Ok(None)),
15386                            })
15387                            .collect::<Vec<_>>();
15388                        (title, location_tasks, editor.workspace().clone())
15389                    })
15390                    .context("location tasks preparation")?;
15391
15392                let locations: Vec<Location> = future::join_all(location_tasks)
15393                    .await
15394                    .into_iter()
15395                    .filter_map(|location| location.transpose())
15396                    .collect::<Result<_>>()
15397                    .context("location tasks")?;
15398
15399                if locations.is_empty() {
15400                    return Ok(Navigated::No);
15401                }
15402
15403                let Some(workspace) = workspace else {
15404                    return Ok(Navigated::No);
15405                };
15406
15407                let opened = workspace
15408                    .update_in(cx, |workspace, window, cx| {
15409                        Self::open_locations_in_multibuffer(
15410                            workspace,
15411                            locations,
15412                            title,
15413                            split,
15414                            MultibufferSelectionMode::First,
15415                            window,
15416                            cx,
15417                        )
15418                    })
15419                    .ok();
15420
15421                anyhow::Ok(Navigated::from_bool(opened.is_some()))
15422            })
15423        } else {
15424            Task::ready(Ok(Navigated::No))
15425        }
15426    }
15427
15428    fn compute_target_location(
15429        &self,
15430        lsp_location: lsp::Location,
15431        server_id: LanguageServerId,
15432        window: &mut Window,
15433        cx: &mut Context<Self>,
15434    ) -> Task<anyhow::Result<Option<Location>>> {
15435        let Some(project) = self.project.clone() else {
15436            return Task::ready(Ok(None));
15437        };
15438
15439        cx.spawn_in(window, async move |editor, cx| {
15440            let location_task = editor.update(cx, |_, cx| {
15441                project.update(cx, |project, cx| {
15442                    let language_server_name = project
15443                        .language_server_statuses(cx)
15444                        .find(|(id, _)| server_id == *id)
15445                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
15446                    language_server_name.map(|language_server_name| {
15447                        project.open_local_buffer_via_lsp(
15448                            lsp_location.uri.clone(),
15449                            server_id,
15450                            language_server_name,
15451                            cx,
15452                        )
15453                    })
15454                })
15455            })?;
15456            let location = match location_task {
15457                Some(task) => Some({
15458                    let target_buffer_handle = task.await.context("open local buffer")?;
15459                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
15460                        let target_start = target_buffer
15461                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
15462                        let target_end = target_buffer
15463                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
15464                        target_buffer.anchor_after(target_start)
15465                            ..target_buffer.anchor_before(target_end)
15466                    })?;
15467                    Location {
15468                        buffer: target_buffer_handle,
15469                        range,
15470                    }
15471                }),
15472                None => None,
15473            };
15474            Ok(location)
15475        })
15476    }
15477
15478    pub fn find_all_references(
15479        &mut self,
15480        _: &FindAllReferences,
15481        window: &mut Window,
15482        cx: &mut Context<Self>,
15483    ) -> Option<Task<Result<Navigated>>> {
15484        let selection = self.selections.newest::<usize>(cx);
15485        let multi_buffer = self.buffer.read(cx);
15486        let head = selection.head();
15487
15488        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
15489        let head_anchor = multi_buffer_snapshot.anchor_at(
15490            head,
15491            if head < selection.tail() {
15492                Bias::Right
15493            } else {
15494                Bias::Left
15495            },
15496        );
15497
15498        match self
15499            .find_all_references_task_sources
15500            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15501        {
15502            Ok(_) => {
15503                log::info!(
15504                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
15505                );
15506                return None;
15507            }
15508            Err(i) => {
15509                self.find_all_references_task_sources.insert(i, head_anchor);
15510            }
15511        }
15512
15513        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
15514        let workspace = self.workspace()?;
15515        let project = workspace.read(cx).project().clone();
15516        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
15517        Some(cx.spawn_in(window, async move |editor, cx| {
15518            let _cleanup = cx.on_drop(&editor, move |editor, _| {
15519                if let Ok(i) = editor
15520                    .find_all_references_task_sources
15521                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
15522                {
15523                    editor.find_all_references_task_sources.remove(i);
15524                }
15525            });
15526
15527            let locations = references.await?;
15528            if locations.is_empty() {
15529                return anyhow::Ok(Navigated::No);
15530            }
15531
15532            workspace.update_in(cx, |workspace, window, cx| {
15533                let title = locations
15534                    .first()
15535                    .as_ref()
15536                    .map(|location| {
15537                        let buffer = location.buffer.read(cx);
15538                        format!(
15539                            "References to `{}`",
15540                            buffer
15541                                .text_for_range(location.range.clone())
15542                                .collect::<String>()
15543                        )
15544                    })
15545                    .unwrap();
15546                Self::open_locations_in_multibuffer(
15547                    workspace,
15548                    locations,
15549                    title,
15550                    false,
15551                    MultibufferSelectionMode::First,
15552                    window,
15553                    cx,
15554                );
15555                Navigated::Yes
15556            })
15557        }))
15558    }
15559
15560    /// Opens a multibuffer with the given project locations in it
15561    pub fn open_locations_in_multibuffer(
15562        workspace: &mut Workspace,
15563        mut locations: Vec<Location>,
15564        title: String,
15565        split: bool,
15566        multibuffer_selection_mode: MultibufferSelectionMode,
15567        window: &mut Window,
15568        cx: &mut Context<Workspace>,
15569    ) {
15570        if locations.is_empty() {
15571            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
15572            return;
15573        }
15574
15575        // If there are multiple definitions, open them in a multibuffer
15576        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
15577        let mut locations = locations.into_iter().peekable();
15578        let mut ranges: Vec<Range<Anchor>> = Vec::new();
15579        let capability = workspace.project().read(cx).capability();
15580
15581        let excerpt_buffer = cx.new(|cx| {
15582            let mut multibuffer = MultiBuffer::new(capability);
15583            while let Some(location) = locations.next() {
15584                let buffer = location.buffer.read(cx);
15585                let mut ranges_for_buffer = Vec::new();
15586                let range = location.range.to_point(buffer);
15587                ranges_for_buffer.push(range.clone());
15588
15589                while let Some(next_location) = locations.peek() {
15590                    if next_location.buffer == location.buffer {
15591                        ranges_for_buffer.push(next_location.range.to_point(buffer));
15592                        locations.next();
15593                    } else {
15594                        break;
15595                    }
15596                }
15597
15598                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
15599                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
15600                    PathKey::for_buffer(&location.buffer, cx),
15601                    location.buffer.clone(),
15602                    ranges_for_buffer,
15603                    DEFAULT_MULTIBUFFER_CONTEXT,
15604                    cx,
15605                );
15606                ranges.extend(new_ranges)
15607            }
15608
15609            multibuffer.with_title(title)
15610        });
15611
15612        let editor = cx.new(|cx| {
15613            Editor::for_multibuffer(
15614                excerpt_buffer,
15615                Some(workspace.project().clone()),
15616                window,
15617                cx,
15618            )
15619        });
15620        editor.update(cx, |editor, cx| {
15621            match multibuffer_selection_mode {
15622                MultibufferSelectionMode::First => {
15623                    if let Some(first_range) = ranges.first() {
15624                        editor.change_selections(None, window, cx, |selections| {
15625                            selections.clear_disjoint();
15626                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15627                        });
15628                    }
15629                    editor.highlight_background::<Self>(
15630                        &ranges,
15631                        |theme| theme.colors().editor_highlighted_line_background,
15632                        cx,
15633                    );
15634                }
15635                MultibufferSelectionMode::All => {
15636                    editor.change_selections(None, window, cx, |selections| {
15637                        selections.clear_disjoint();
15638                        selections.select_anchor_ranges(ranges);
15639                    });
15640                }
15641            }
15642            editor.register_buffers_with_language_servers(cx);
15643        });
15644
15645        let item = Box::new(editor);
15646        let item_id = item.item_id();
15647
15648        if split {
15649            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15650        } else {
15651            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15652                let (preview_item_id, preview_item_idx) =
15653                    workspace.active_pane().read_with(cx, |pane, _| {
15654                        (pane.preview_item_id(), pane.preview_item_idx())
15655                    });
15656
15657                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15658
15659                if let Some(preview_item_id) = preview_item_id {
15660                    workspace.active_pane().update(cx, |pane, cx| {
15661                        pane.remove_item(preview_item_id, false, false, window, cx);
15662                    });
15663                }
15664            } else {
15665                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15666            }
15667        }
15668        workspace.active_pane().update(cx, |pane, cx| {
15669            pane.set_preview_item_id(Some(item_id), cx);
15670        });
15671    }
15672
15673    pub fn rename(
15674        &mut self,
15675        _: &Rename,
15676        window: &mut Window,
15677        cx: &mut Context<Self>,
15678    ) -> Option<Task<Result<()>>> {
15679        use language::ToOffset as _;
15680
15681        let provider = self.semantics_provider.clone()?;
15682        let selection = self.selections.newest_anchor().clone();
15683        let (cursor_buffer, cursor_buffer_position) = self
15684            .buffer
15685            .read(cx)
15686            .text_anchor_for_position(selection.head(), cx)?;
15687        let (tail_buffer, cursor_buffer_position_end) = self
15688            .buffer
15689            .read(cx)
15690            .text_anchor_for_position(selection.tail(), cx)?;
15691        if tail_buffer != cursor_buffer {
15692            return None;
15693        }
15694
15695        let snapshot = cursor_buffer.read(cx).snapshot();
15696        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15697        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15698        let prepare_rename = provider
15699            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15700            .unwrap_or_else(|| Task::ready(Ok(None)));
15701        drop(snapshot);
15702
15703        Some(cx.spawn_in(window, async move |this, cx| {
15704            let rename_range = if let Some(range) = prepare_rename.await? {
15705                Some(range)
15706            } else {
15707                this.update(cx, |this, cx| {
15708                    let buffer = this.buffer.read(cx).snapshot(cx);
15709                    let mut buffer_highlights = this
15710                        .document_highlights_for_position(selection.head(), &buffer)
15711                        .filter(|highlight| {
15712                            highlight.start.excerpt_id == selection.head().excerpt_id
15713                                && highlight.end.excerpt_id == selection.head().excerpt_id
15714                        });
15715                    buffer_highlights
15716                        .next()
15717                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15718                })?
15719            };
15720            if let Some(rename_range) = rename_range {
15721                this.update_in(cx, |this, window, cx| {
15722                    let snapshot = cursor_buffer.read(cx).snapshot();
15723                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15724                    let cursor_offset_in_rename_range =
15725                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15726                    let cursor_offset_in_rename_range_end =
15727                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15728
15729                    this.take_rename(false, window, cx);
15730                    let buffer = this.buffer.read(cx).read(cx);
15731                    let cursor_offset = selection.head().to_offset(&buffer);
15732                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15733                    let rename_end = rename_start + rename_buffer_range.len();
15734                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15735                    let mut old_highlight_id = None;
15736                    let old_name: Arc<str> = buffer
15737                        .chunks(rename_start..rename_end, true)
15738                        .map(|chunk| {
15739                            if old_highlight_id.is_none() {
15740                                old_highlight_id = chunk.syntax_highlight_id;
15741                            }
15742                            chunk.text
15743                        })
15744                        .collect::<String>()
15745                        .into();
15746
15747                    drop(buffer);
15748
15749                    // Position the selection in the rename editor so that it matches the current selection.
15750                    this.show_local_selections = false;
15751                    let rename_editor = cx.new(|cx| {
15752                        let mut editor = Editor::single_line(window, cx);
15753                        editor.buffer.update(cx, |buffer, cx| {
15754                            buffer.edit([(0..0, old_name.clone())], None, cx)
15755                        });
15756                        let rename_selection_range = match cursor_offset_in_rename_range
15757                            .cmp(&cursor_offset_in_rename_range_end)
15758                        {
15759                            Ordering::Equal => {
15760                                editor.select_all(&SelectAll, window, cx);
15761                                return editor;
15762                            }
15763                            Ordering::Less => {
15764                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15765                            }
15766                            Ordering::Greater => {
15767                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15768                            }
15769                        };
15770                        if rename_selection_range.end > old_name.len() {
15771                            editor.select_all(&SelectAll, window, cx);
15772                        } else {
15773                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15774                                s.select_ranges([rename_selection_range]);
15775                            });
15776                        }
15777                        editor
15778                    });
15779                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15780                        if e == &EditorEvent::Focused {
15781                            cx.emit(EditorEvent::FocusedIn)
15782                        }
15783                    })
15784                    .detach();
15785
15786                    let write_highlights =
15787                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15788                    let read_highlights =
15789                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15790                    let ranges = write_highlights
15791                        .iter()
15792                        .flat_map(|(_, ranges)| ranges.iter())
15793                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15794                        .cloned()
15795                        .collect();
15796
15797                    this.highlight_text::<Rename>(
15798                        ranges,
15799                        HighlightStyle {
15800                            fade_out: Some(0.6),
15801                            ..Default::default()
15802                        },
15803                        cx,
15804                    );
15805                    let rename_focus_handle = rename_editor.focus_handle(cx);
15806                    window.focus(&rename_focus_handle);
15807                    let block_id = this.insert_blocks(
15808                        [BlockProperties {
15809                            style: BlockStyle::Flex,
15810                            placement: BlockPlacement::Below(range.start),
15811                            height: Some(1),
15812                            render: Arc::new({
15813                                let rename_editor = rename_editor.clone();
15814                                move |cx: &mut BlockContext| {
15815                                    let mut text_style = cx.editor_style.text.clone();
15816                                    if let Some(highlight_style) = old_highlight_id
15817                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15818                                    {
15819                                        text_style = text_style.highlight(highlight_style);
15820                                    }
15821                                    div()
15822                                        .block_mouse_except_scroll()
15823                                        .pl(cx.anchor_x)
15824                                        .child(EditorElement::new(
15825                                            &rename_editor,
15826                                            EditorStyle {
15827                                                background: cx.theme().system().transparent,
15828                                                local_player: cx.editor_style.local_player,
15829                                                text: text_style,
15830                                                scrollbar_width: cx.editor_style.scrollbar_width,
15831                                                syntax: cx.editor_style.syntax.clone(),
15832                                                status: cx.editor_style.status.clone(),
15833                                                inlay_hints_style: HighlightStyle {
15834                                                    font_weight: Some(FontWeight::BOLD),
15835                                                    ..make_inlay_hints_style(cx.app)
15836                                                },
15837                                                inline_completion_styles: make_suggestion_styles(
15838                                                    cx.app,
15839                                                ),
15840                                                ..EditorStyle::default()
15841                                            },
15842                                        ))
15843                                        .into_any_element()
15844                                }
15845                            }),
15846                            priority: 0,
15847                            render_in_minimap: true,
15848                        }],
15849                        Some(Autoscroll::fit()),
15850                        cx,
15851                    )[0];
15852                    this.pending_rename = Some(RenameState {
15853                        range,
15854                        old_name,
15855                        editor: rename_editor,
15856                        block_id,
15857                    });
15858                })?;
15859            }
15860
15861            Ok(())
15862        }))
15863    }
15864
15865    pub fn confirm_rename(
15866        &mut self,
15867        _: &ConfirmRename,
15868        window: &mut Window,
15869        cx: &mut Context<Self>,
15870    ) -> Option<Task<Result<()>>> {
15871        let rename = self.take_rename(false, window, cx)?;
15872        let workspace = self.workspace()?.downgrade();
15873        let (buffer, start) = self
15874            .buffer
15875            .read(cx)
15876            .text_anchor_for_position(rename.range.start, cx)?;
15877        let (end_buffer, _) = self
15878            .buffer
15879            .read(cx)
15880            .text_anchor_for_position(rename.range.end, cx)?;
15881        if buffer != end_buffer {
15882            return None;
15883        }
15884
15885        let old_name = rename.old_name;
15886        let new_name = rename.editor.read(cx).text(cx);
15887
15888        let rename = self.semantics_provider.as_ref()?.perform_rename(
15889            &buffer,
15890            start,
15891            new_name.clone(),
15892            cx,
15893        )?;
15894
15895        Some(cx.spawn_in(window, async move |editor, cx| {
15896            let project_transaction = rename.await?;
15897            Self::open_project_transaction(
15898                &editor,
15899                workspace,
15900                project_transaction,
15901                format!("Rename: {}{}", old_name, new_name),
15902                cx,
15903            )
15904            .await?;
15905
15906            editor.update(cx, |editor, cx| {
15907                editor.refresh_document_highlights(cx);
15908            })?;
15909            Ok(())
15910        }))
15911    }
15912
15913    fn take_rename(
15914        &mut self,
15915        moving_cursor: bool,
15916        window: &mut Window,
15917        cx: &mut Context<Self>,
15918    ) -> Option<RenameState> {
15919        let rename = self.pending_rename.take()?;
15920        if rename.editor.focus_handle(cx).is_focused(window) {
15921            window.focus(&self.focus_handle);
15922        }
15923
15924        self.remove_blocks(
15925            [rename.block_id].into_iter().collect(),
15926            Some(Autoscroll::fit()),
15927            cx,
15928        );
15929        self.clear_highlights::<Rename>(cx);
15930        self.show_local_selections = true;
15931
15932        if moving_cursor {
15933            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15934                editor.selections.newest::<usize>(cx).head()
15935            });
15936
15937            // Update the selection to match the position of the selection inside
15938            // the rename editor.
15939            let snapshot = self.buffer.read(cx).read(cx);
15940            let rename_range = rename.range.to_offset(&snapshot);
15941            let cursor_in_editor = snapshot
15942                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15943                .min(rename_range.end);
15944            drop(snapshot);
15945
15946            self.change_selections(None, window, cx, |s| {
15947                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15948            });
15949        } else {
15950            self.refresh_document_highlights(cx);
15951        }
15952
15953        Some(rename)
15954    }
15955
15956    pub fn pending_rename(&self) -> Option<&RenameState> {
15957        self.pending_rename.as_ref()
15958    }
15959
15960    fn format(
15961        &mut self,
15962        _: &Format,
15963        window: &mut Window,
15964        cx: &mut Context<Self>,
15965    ) -> Option<Task<Result<()>>> {
15966        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15967
15968        let project = match &self.project {
15969            Some(project) => project.clone(),
15970            None => return None,
15971        };
15972
15973        Some(self.perform_format(
15974            project,
15975            FormatTrigger::Manual,
15976            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
15977            window,
15978            cx,
15979        ))
15980    }
15981
15982    fn format_selections(
15983        &mut self,
15984        _: &FormatSelections,
15985        window: &mut Window,
15986        cx: &mut Context<Self>,
15987    ) -> Option<Task<Result<()>>> {
15988        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15989
15990        let project = match &self.project {
15991            Some(project) => project.clone(),
15992            None => return None,
15993        };
15994
15995        let ranges = self
15996            .selections
15997            .all_adjusted(cx)
15998            .into_iter()
15999            .map(|selection| selection.range())
16000            .collect_vec();
16001
16002        Some(self.perform_format(
16003            project,
16004            FormatTrigger::Manual,
16005            FormatTarget::Ranges(ranges),
16006            window,
16007            cx,
16008        ))
16009    }
16010
16011    fn perform_format(
16012        &mut self,
16013        project: Entity<Project>,
16014        trigger: FormatTrigger,
16015        target: FormatTarget,
16016        window: &mut Window,
16017        cx: &mut Context<Self>,
16018    ) -> Task<Result<()>> {
16019        let buffer = self.buffer.clone();
16020        let (buffers, target) = match target {
16021            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16022            FormatTarget::Ranges(selection_ranges) => {
16023                let multi_buffer = buffer.read(cx);
16024                let snapshot = multi_buffer.read(cx);
16025                let mut buffers = HashSet::default();
16026                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16027                    BTreeMap::new();
16028                for selection_range in selection_ranges {
16029                    for (buffer, buffer_range, _) in
16030                        snapshot.range_to_buffer_ranges(selection_range)
16031                    {
16032                        let buffer_id = buffer.remote_id();
16033                        let start = buffer.anchor_before(buffer_range.start);
16034                        let end = buffer.anchor_after(buffer_range.end);
16035                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16036                        buffer_id_to_ranges
16037                            .entry(buffer_id)
16038                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16039                            .or_insert_with(|| vec![start..end]);
16040                    }
16041                }
16042                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16043            }
16044        };
16045
16046        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16047        let selections_prev = transaction_id_prev
16048            .and_then(|transaction_id_prev| {
16049                // default to selections as they were after the last edit, if we have them,
16050                // instead of how they are now.
16051                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16052                // will take you back to where you made the last edit, instead of staying where you scrolled
16053                self.selection_history
16054                    .transaction(transaction_id_prev)
16055                    .map(|t| t.0.clone())
16056            })
16057            .unwrap_or_else(|| {
16058                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16059                self.selections.disjoint_anchors()
16060            });
16061
16062        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16063        let format = project.update(cx, |project, cx| {
16064            project.format(buffers, target, true, trigger, cx)
16065        });
16066
16067        cx.spawn_in(window, async move |editor, cx| {
16068            let transaction = futures::select_biased! {
16069                transaction = format.log_err().fuse() => transaction,
16070                () = timeout => {
16071                    log::warn!("timed out waiting for formatting");
16072                    None
16073                }
16074            };
16075
16076            buffer
16077                .update(cx, |buffer, cx| {
16078                    if let Some(transaction) = transaction {
16079                        if !buffer.is_singleton() {
16080                            buffer.push_transaction(&transaction.0, cx);
16081                        }
16082                    }
16083                    cx.notify();
16084                })
16085                .ok();
16086
16087            if let Some(transaction_id_now) =
16088                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16089            {
16090                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16091                if has_new_transaction {
16092                    _ = editor.update(cx, |editor, _| {
16093                        editor
16094                            .selection_history
16095                            .insert_transaction(transaction_id_now, selections_prev);
16096                    });
16097                }
16098            }
16099
16100            Ok(())
16101        })
16102    }
16103
16104    fn organize_imports(
16105        &mut self,
16106        _: &OrganizeImports,
16107        window: &mut Window,
16108        cx: &mut Context<Self>,
16109    ) -> Option<Task<Result<()>>> {
16110        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16111        let project = match &self.project {
16112            Some(project) => project.clone(),
16113            None => return None,
16114        };
16115        Some(self.perform_code_action_kind(
16116            project,
16117            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16118            window,
16119            cx,
16120        ))
16121    }
16122
16123    fn perform_code_action_kind(
16124        &mut self,
16125        project: Entity<Project>,
16126        kind: CodeActionKind,
16127        window: &mut Window,
16128        cx: &mut Context<Self>,
16129    ) -> Task<Result<()>> {
16130        let buffer = self.buffer.clone();
16131        let buffers = buffer.read(cx).all_buffers();
16132        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16133        let apply_action = project.update(cx, |project, cx| {
16134            project.apply_code_action_kind(buffers, kind, true, cx)
16135        });
16136        cx.spawn_in(window, async move |_, cx| {
16137            let transaction = futures::select_biased! {
16138                () = timeout => {
16139                    log::warn!("timed out waiting for executing code action");
16140                    None
16141                }
16142                transaction = apply_action.log_err().fuse() => transaction,
16143            };
16144            buffer
16145                .update(cx, |buffer, cx| {
16146                    // check if we need this
16147                    if let Some(transaction) = transaction {
16148                        if !buffer.is_singleton() {
16149                            buffer.push_transaction(&transaction.0, cx);
16150                        }
16151                    }
16152                    cx.notify();
16153                })
16154                .ok();
16155            Ok(())
16156        })
16157    }
16158
16159    fn restart_language_server(
16160        &mut self,
16161        _: &RestartLanguageServer,
16162        _: &mut Window,
16163        cx: &mut Context<Self>,
16164    ) {
16165        if let Some(project) = self.project.clone() {
16166            self.buffer.update(cx, |multi_buffer, cx| {
16167                project.update(cx, |project, cx| {
16168                    project.restart_language_servers_for_buffers(
16169                        multi_buffer.all_buffers().into_iter().collect(),
16170                        cx,
16171                    );
16172                });
16173            })
16174        }
16175    }
16176
16177    fn stop_language_server(
16178        &mut self,
16179        _: &StopLanguageServer,
16180        _: &mut Window,
16181        cx: &mut Context<Self>,
16182    ) {
16183        if let Some(project) = self.project.clone() {
16184            self.buffer.update(cx, |multi_buffer, cx| {
16185                project.update(cx, |project, cx| {
16186                    project.stop_language_servers_for_buffers(
16187                        multi_buffer.all_buffers().into_iter().collect(),
16188                        cx,
16189                    );
16190                    cx.emit(project::Event::RefreshInlayHints);
16191                });
16192            });
16193        }
16194    }
16195
16196    fn cancel_language_server_work(
16197        workspace: &mut Workspace,
16198        _: &actions::CancelLanguageServerWork,
16199        _: &mut Window,
16200        cx: &mut Context<Workspace>,
16201    ) {
16202        let project = workspace.project();
16203        let buffers = workspace
16204            .active_item(cx)
16205            .and_then(|item| item.act_as::<Editor>(cx))
16206            .map_or(HashSet::default(), |editor| {
16207                editor.read(cx).buffer.read(cx).all_buffers()
16208            });
16209        project.update(cx, |project, cx| {
16210            project.cancel_language_server_work_for_buffers(buffers, cx);
16211        });
16212    }
16213
16214    fn show_character_palette(
16215        &mut self,
16216        _: &ShowCharacterPalette,
16217        window: &mut Window,
16218        _: &mut Context<Self>,
16219    ) {
16220        window.show_character_palette();
16221    }
16222
16223    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16224        if !self.diagnostics_enabled() {
16225            return;
16226        }
16227
16228        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16229            let buffer = self.buffer.read(cx).snapshot(cx);
16230            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16231            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16232            let is_valid = buffer
16233                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16234                .any(|entry| {
16235                    entry.diagnostic.is_primary
16236                        && !entry.range.is_empty()
16237                        && entry.range.start == primary_range_start
16238                        && entry.diagnostic.message == active_diagnostics.active_message
16239                });
16240
16241            if !is_valid {
16242                self.dismiss_diagnostics(cx);
16243            }
16244        }
16245    }
16246
16247    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16248        match &self.active_diagnostics {
16249            ActiveDiagnostic::Group(group) => Some(group),
16250            _ => None,
16251        }
16252    }
16253
16254    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16255        if !self.diagnostics_enabled() {
16256            return;
16257        }
16258        self.dismiss_diagnostics(cx);
16259        self.active_diagnostics = ActiveDiagnostic::All;
16260    }
16261
16262    fn activate_diagnostics(
16263        &mut self,
16264        buffer_id: BufferId,
16265        diagnostic: DiagnosticEntry<usize>,
16266        window: &mut Window,
16267        cx: &mut Context<Self>,
16268    ) {
16269        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16270            return;
16271        }
16272        self.dismiss_diagnostics(cx);
16273        let snapshot = self.snapshot(window, cx);
16274        let buffer = self.buffer.read(cx).snapshot(cx);
16275        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16276            return;
16277        };
16278
16279        let diagnostic_group = buffer
16280            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16281            .collect::<Vec<_>>();
16282
16283        let blocks =
16284            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16285
16286        let blocks = self.display_map.update(cx, |display_map, cx| {
16287            display_map.insert_blocks(blocks, cx).into_iter().collect()
16288        });
16289        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16290            active_range: buffer.anchor_before(diagnostic.range.start)
16291                ..buffer.anchor_after(diagnostic.range.end),
16292            active_message: diagnostic.diagnostic.message.clone(),
16293            group_id: diagnostic.diagnostic.group_id,
16294            blocks,
16295        });
16296        cx.notify();
16297    }
16298
16299    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16300        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16301            return;
16302        };
16303
16304        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16305        if let ActiveDiagnostic::Group(group) = prev {
16306            self.display_map.update(cx, |display_map, cx| {
16307                display_map.remove_blocks(group.blocks, cx);
16308            });
16309            cx.notify();
16310        }
16311    }
16312
16313    /// Disable inline diagnostics rendering for this editor.
16314    pub fn disable_inline_diagnostics(&mut self) {
16315        self.inline_diagnostics_enabled = false;
16316        self.inline_diagnostics_update = Task::ready(());
16317        self.inline_diagnostics.clear();
16318    }
16319
16320    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16321        self.diagnostics_enabled = false;
16322        self.dismiss_diagnostics(cx);
16323        self.inline_diagnostics_update = Task::ready(());
16324        self.inline_diagnostics.clear();
16325    }
16326
16327    pub fn diagnostics_enabled(&self) -> bool {
16328        self.diagnostics_enabled && self.mode.is_full()
16329    }
16330
16331    pub fn inline_diagnostics_enabled(&self) -> bool {
16332        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16333    }
16334
16335    pub fn show_inline_diagnostics(&self) -> bool {
16336        self.show_inline_diagnostics
16337    }
16338
16339    pub fn toggle_inline_diagnostics(
16340        &mut self,
16341        _: &ToggleInlineDiagnostics,
16342        window: &mut Window,
16343        cx: &mut Context<Editor>,
16344    ) {
16345        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16346        self.refresh_inline_diagnostics(false, window, cx);
16347    }
16348
16349    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16350        self.diagnostics_max_severity = severity;
16351        self.display_map.update(cx, |display_map, _| {
16352            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16353        });
16354    }
16355
16356    pub fn toggle_diagnostics(
16357        &mut self,
16358        _: &ToggleDiagnostics,
16359        window: &mut Window,
16360        cx: &mut Context<Editor>,
16361    ) {
16362        if !self.diagnostics_enabled() {
16363            return;
16364        }
16365
16366        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16367            EditorSettings::get_global(cx)
16368                .diagnostics_max_severity
16369                .filter(|severity| severity != &DiagnosticSeverity::Off)
16370                .unwrap_or(DiagnosticSeverity::Hint)
16371        } else {
16372            DiagnosticSeverity::Off
16373        };
16374        self.set_max_diagnostics_severity(new_severity, cx);
16375        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16376            self.active_diagnostics = ActiveDiagnostic::None;
16377            self.inline_diagnostics_update = Task::ready(());
16378            self.inline_diagnostics.clear();
16379        } else {
16380            self.refresh_inline_diagnostics(false, window, cx);
16381        }
16382
16383        cx.notify();
16384    }
16385
16386    pub fn toggle_minimap(
16387        &mut self,
16388        _: &ToggleMinimap,
16389        window: &mut Window,
16390        cx: &mut Context<Editor>,
16391    ) {
16392        if self.supports_minimap(cx) {
16393            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16394        }
16395    }
16396
16397    fn refresh_inline_diagnostics(
16398        &mut self,
16399        debounce: bool,
16400        window: &mut Window,
16401        cx: &mut Context<Self>,
16402    ) {
16403        let max_severity = ProjectSettings::get_global(cx)
16404            .diagnostics
16405            .inline
16406            .max_severity
16407            .unwrap_or(self.diagnostics_max_severity);
16408
16409        if !self.inline_diagnostics_enabled()
16410            || !self.show_inline_diagnostics
16411            || max_severity == DiagnosticSeverity::Off
16412        {
16413            self.inline_diagnostics_update = Task::ready(());
16414            self.inline_diagnostics.clear();
16415            return;
16416        }
16417
16418        let debounce_ms = ProjectSettings::get_global(cx)
16419            .diagnostics
16420            .inline
16421            .update_debounce_ms;
16422        let debounce = if debounce && debounce_ms > 0 {
16423            Some(Duration::from_millis(debounce_ms))
16424        } else {
16425            None
16426        };
16427        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16428            if let Some(debounce) = debounce {
16429                cx.background_executor().timer(debounce).await;
16430            }
16431            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16432                editor
16433                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16434                    .ok()
16435            }) else {
16436                return;
16437            };
16438
16439            let new_inline_diagnostics = cx
16440                .background_spawn(async move {
16441                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
16442                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
16443                        let message = diagnostic_entry
16444                            .diagnostic
16445                            .message
16446                            .split_once('\n')
16447                            .map(|(line, _)| line)
16448                            .map(SharedString::new)
16449                            .unwrap_or_else(|| {
16450                                SharedString::from(diagnostic_entry.diagnostic.message)
16451                            });
16452                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
16453                        let (Ok(i) | Err(i)) = inline_diagnostics
16454                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
16455                        inline_diagnostics.insert(
16456                            i,
16457                            (
16458                                start_anchor,
16459                                InlineDiagnostic {
16460                                    message,
16461                                    group_id: diagnostic_entry.diagnostic.group_id,
16462                                    start: diagnostic_entry.range.start.to_point(&snapshot),
16463                                    is_primary: diagnostic_entry.diagnostic.is_primary,
16464                                    severity: diagnostic_entry.diagnostic.severity,
16465                                },
16466                            ),
16467                        );
16468                    }
16469                    inline_diagnostics
16470                })
16471                .await;
16472
16473            editor
16474                .update(cx, |editor, cx| {
16475                    editor.inline_diagnostics = new_inline_diagnostics;
16476                    cx.notify();
16477                })
16478                .ok();
16479        });
16480    }
16481
16482    fn pull_diagnostics(
16483        &mut self,
16484        buffer_id: Option<BufferId>,
16485        window: &Window,
16486        cx: &mut Context<Self>,
16487    ) -> Option<()> {
16488        if !self.mode().is_full() {
16489            return None;
16490        }
16491        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
16492            .diagnostics
16493            .lsp_pull_diagnostics;
16494        if !pull_diagnostics_settings.enabled {
16495            return None;
16496        }
16497        let project = self.project.as_ref()?.downgrade();
16498        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
16499        let mut buffers = self.buffer.read(cx).all_buffers();
16500        if let Some(buffer_id) = buffer_id {
16501            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
16502        }
16503
16504        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
16505            cx.background_executor().timer(debounce).await;
16506
16507            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
16508                buffers
16509                    .into_iter()
16510                    .filter_map(|buffer| {
16511                        project
16512                            .update(cx, |project, cx| {
16513                                project.lsp_store().update(cx, |lsp_store, cx| {
16514                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
16515                                })
16516                            })
16517                            .ok()
16518                    })
16519                    .collect::<FuturesUnordered<_>>()
16520            }) else {
16521                return;
16522            };
16523
16524            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
16525                match pull_task {
16526                    Ok(()) => {
16527                        if editor
16528                            .update_in(cx, |editor, window, cx| {
16529                                editor.update_diagnostics_state(window, cx);
16530                            })
16531                            .is_err()
16532                        {
16533                            return;
16534                        }
16535                    }
16536                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
16537                }
16538            }
16539        });
16540
16541        Some(())
16542    }
16543
16544    pub fn set_selections_from_remote(
16545        &mut self,
16546        selections: Vec<Selection<Anchor>>,
16547        pending_selection: Option<Selection<Anchor>>,
16548        window: &mut Window,
16549        cx: &mut Context<Self>,
16550    ) {
16551        let old_cursor_position = self.selections.newest_anchor().head();
16552        self.selections.change_with(cx, |s| {
16553            s.select_anchors(selections);
16554            if let Some(pending_selection) = pending_selection {
16555                s.set_pending(pending_selection, SelectMode::Character);
16556            } else {
16557                s.clear_pending();
16558            }
16559        });
16560        self.selections_did_change(
16561            false,
16562            &old_cursor_position,
16563            SelectionEffects::default(),
16564            window,
16565            cx,
16566        );
16567    }
16568
16569    pub fn transact(
16570        &mut self,
16571        window: &mut Window,
16572        cx: &mut Context<Self>,
16573        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
16574    ) -> Option<TransactionId> {
16575        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16576            this.start_transaction_at(Instant::now(), window, cx);
16577            update(this, window, cx);
16578            this.end_transaction_at(Instant::now(), cx)
16579        })
16580    }
16581
16582    pub fn start_transaction_at(
16583        &mut self,
16584        now: Instant,
16585        window: &mut Window,
16586        cx: &mut Context<Self>,
16587    ) {
16588        self.end_selection(window, cx);
16589        if let Some(tx_id) = self
16590            .buffer
16591            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
16592        {
16593            self.selection_history
16594                .insert_transaction(tx_id, self.selections.disjoint_anchors());
16595            cx.emit(EditorEvent::TransactionBegun {
16596                transaction_id: tx_id,
16597            })
16598        }
16599    }
16600
16601    pub fn end_transaction_at(
16602        &mut self,
16603        now: Instant,
16604        cx: &mut Context<Self>,
16605    ) -> Option<TransactionId> {
16606        if let Some(transaction_id) = self
16607            .buffer
16608            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
16609        {
16610            if let Some((_, end_selections)) =
16611                self.selection_history.transaction_mut(transaction_id)
16612            {
16613                *end_selections = Some(self.selections.disjoint_anchors());
16614            } else {
16615                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
16616            }
16617
16618            cx.emit(EditorEvent::Edited { transaction_id });
16619            Some(transaction_id)
16620        } else {
16621            None
16622        }
16623    }
16624
16625    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
16626        if self.selection_mark_mode {
16627            self.change_selections(None, window, cx, |s| {
16628                s.move_with(|_, sel| {
16629                    sel.collapse_to(sel.head(), SelectionGoal::None);
16630                });
16631            })
16632        }
16633        self.selection_mark_mode = true;
16634        cx.notify();
16635    }
16636
16637    pub fn swap_selection_ends(
16638        &mut self,
16639        _: &actions::SwapSelectionEnds,
16640        window: &mut Window,
16641        cx: &mut Context<Self>,
16642    ) {
16643        self.change_selections(None, window, cx, |s| {
16644            s.move_with(|_, sel| {
16645                if sel.start != sel.end {
16646                    sel.reversed = !sel.reversed
16647                }
16648            });
16649        });
16650        self.request_autoscroll(Autoscroll::newest(), cx);
16651        cx.notify();
16652    }
16653
16654    pub fn toggle_fold(
16655        &mut self,
16656        _: &actions::ToggleFold,
16657        window: &mut Window,
16658        cx: &mut Context<Self>,
16659    ) {
16660        if self.is_singleton(cx) {
16661            let selection = self.selections.newest::<Point>(cx);
16662
16663            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16664            let range = if selection.is_empty() {
16665                let point = selection.head().to_display_point(&display_map);
16666                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16667                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16668                    .to_point(&display_map);
16669                start..end
16670            } else {
16671                selection.range()
16672            };
16673            if display_map.folds_in_range(range).next().is_some() {
16674                self.unfold_lines(&Default::default(), window, cx)
16675            } else {
16676                self.fold(&Default::default(), window, cx)
16677            }
16678        } else {
16679            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16680            let buffer_ids: HashSet<_> = self
16681                .selections
16682                .disjoint_anchor_ranges()
16683                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16684                .collect();
16685
16686            let should_unfold = buffer_ids
16687                .iter()
16688                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16689
16690            for buffer_id in buffer_ids {
16691                if should_unfold {
16692                    self.unfold_buffer(buffer_id, cx);
16693                } else {
16694                    self.fold_buffer(buffer_id, cx);
16695                }
16696            }
16697        }
16698    }
16699
16700    pub fn toggle_fold_recursive(
16701        &mut self,
16702        _: &actions::ToggleFoldRecursive,
16703        window: &mut Window,
16704        cx: &mut Context<Self>,
16705    ) {
16706        let selection = self.selections.newest::<Point>(cx);
16707
16708        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16709        let range = if selection.is_empty() {
16710            let point = selection.head().to_display_point(&display_map);
16711            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16712            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16713                .to_point(&display_map);
16714            start..end
16715        } else {
16716            selection.range()
16717        };
16718        if display_map.folds_in_range(range).next().is_some() {
16719            self.unfold_recursive(&Default::default(), window, cx)
16720        } else {
16721            self.fold_recursive(&Default::default(), window, cx)
16722        }
16723    }
16724
16725    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16726        if self.is_singleton(cx) {
16727            let mut to_fold = Vec::new();
16728            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16729            let selections = self.selections.all_adjusted(cx);
16730
16731            for selection in selections {
16732                let range = selection.range().sorted();
16733                let buffer_start_row = range.start.row;
16734
16735                if range.start.row != range.end.row {
16736                    let mut found = false;
16737                    let mut row = range.start.row;
16738                    while row <= range.end.row {
16739                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16740                        {
16741                            found = true;
16742                            row = crease.range().end.row + 1;
16743                            to_fold.push(crease);
16744                        } else {
16745                            row += 1
16746                        }
16747                    }
16748                    if found {
16749                        continue;
16750                    }
16751                }
16752
16753                for row in (0..=range.start.row).rev() {
16754                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16755                        if crease.range().end.row >= buffer_start_row {
16756                            to_fold.push(crease);
16757                            if row <= range.start.row {
16758                                break;
16759                            }
16760                        }
16761                    }
16762                }
16763            }
16764
16765            self.fold_creases(to_fold, true, window, cx);
16766        } else {
16767            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16768            let buffer_ids = self
16769                .selections
16770                .disjoint_anchor_ranges()
16771                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16772                .collect::<HashSet<_>>();
16773            for buffer_id in buffer_ids {
16774                self.fold_buffer(buffer_id, cx);
16775            }
16776        }
16777    }
16778
16779    fn fold_at_level(
16780        &mut self,
16781        fold_at: &FoldAtLevel,
16782        window: &mut Window,
16783        cx: &mut Context<Self>,
16784    ) {
16785        if !self.buffer.read(cx).is_singleton() {
16786            return;
16787        }
16788
16789        let fold_at_level = fold_at.0;
16790        let snapshot = self.buffer.read(cx).snapshot(cx);
16791        let mut to_fold = Vec::new();
16792        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16793
16794        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16795            while start_row < end_row {
16796                match self
16797                    .snapshot(window, cx)
16798                    .crease_for_buffer_row(MultiBufferRow(start_row))
16799                {
16800                    Some(crease) => {
16801                        let nested_start_row = crease.range().start.row + 1;
16802                        let nested_end_row = crease.range().end.row;
16803
16804                        if current_level < fold_at_level {
16805                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16806                        } else if current_level == fold_at_level {
16807                            to_fold.push(crease);
16808                        }
16809
16810                        start_row = nested_end_row + 1;
16811                    }
16812                    None => start_row += 1,
16813                }
16814            }
16815        }
16816
16817        self.fold_creases(to_fold, true, window, cx);
16818    }
16819
16820    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16821        if self.buffer.read(cx).is_singleton() {
16822            let mut fold_ranges = Vec::new();
16823            let snapshot = self.buffer.read(cx).snapshot(cx);
16824
16825            for row in 0..snapshot.max_row().0 {
16826                if let Some(foldable_range) = self
16827                    .snapshot(window, cx)
16828                    .crease_for_buffer_row(MultiBufferRow(row))
16829                {
16830                    fold_ranges.push(foldable_range);
16831                }
16832            }
16833
16834            self.fold_creases(fold_ranges, true, window, cx);
16835        } else {
16836            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16837                editor
16838                    .update_in(cx, |editor, _, cx| {
16839                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16840                            editor.fold_buffer(buffer_id, cx);
16841                        }
16842                    })
16843                    .ok();
16844            });
16845        }
16846    }
16847
16848    pub fn fold_function_bodies(
16849        &mut self,
16850        _: &actions::FoldFunctionBodies,
16851        window: &mut Window,
16852        cx: &mut Context<Self>,
16853    ) {
16854        let snapshot = self.buffer.read(cx).snapshot(cx);
16855
16856        let ranges = snapshot
16857            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16858            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16859            .collect::<Vec<_>>();
16860
16861        let creases = ranges
16862            .into_iter()
16863            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16864            .collect();
16865
16866        self.fold_creases(creases, true, window, cx);
16867    }
16868
16869    pub fn fold_recursive(
16870        &mut self,
16871        _: &actions::FoldRecursive,
16872        window: &mut Window,
16873        cx: &mut Context<Self>,
16874    ) {
16875        let mut to_fold = Vec::new();
16876        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16877        let selections = self.selections.all_adjusted(cx);
16878
16879        for selection in selections {
16880            let range = selection.range().sorted();
16881            let buffer_start_row = range.start.row;
16882
16883            if range.start.row != range.end.row {
16884                let mut found = false;
16885                for row in range.start.row..=range.end.row {
16886                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16887                        found = true;
16888                        to_fold.push(crease);
16889                    }
16890                }
16891                if found {
16892                    continue;
16893                }
16894            }
16895
16896            for row in (0..=range.start.row).rev() {
16897                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16898                    if crease.range().end.row >= buffer_start_row {
16899                        to_fold.push(crease);
16900                    } else {
16901                        break;
16902                    }
16903                }
16904            }
16905        }
16906
16907        self.fold_creases(to_fold, true, window, cx);
16908    }
16909
16910    pub fn fold_at(
16911        &mut self,
16912        buffer_row: MultiBufferRow,
16913        window: &mut Window,
16914        cx: &mut Context<Self>,
16915    ) {
16916        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16917
16918        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16919            let autoscroll = self
16920                .selections
16921                .all::<Point>(cx)
16922                .iter()
16923                .any(|selection| crease.range().overlaps(&selection.range()));
16924
16925            self.fold_creases(vec![crease], autoscroll, window, cx);
16926        }
16927    }
16928
16929    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16930        if self.is_singleton(cx) {
16931            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16932            let buffer = &display_map.buffer_snapshot;
16933            let selections = self.selections.all::<Point>(cx);
16934            let ranges = selections
16935                .iter()
16936                .map(|s| {
16937                    let range = s.display_range(&display_map).sorted();
16938                    let mut start = range.start.to_point(&display_map);
16939                    let mut end = range.end.to_point(&display_map);
16940                    start.column = 0;
16941                    end.column = buffer.line_len(MultiBufferRow(end.row));
16942                    start..end
16943                })
16944                .collect::<Vec<_>>();
16945
16946            self.unfold_ranges(&ranges, true, true, cx);
16947        } else {
16948            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16949            let buffer_ids = self
16950                .selections
16951                .disjoint_anchor_ranges()
16952                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16953                .collect::<HashSet<_>>();
16954            for buffer_id in buffer_ids {
16955                self.unfold_buffer(buffer_id, cx);
16956            }
16957        }
16958    }
16959
16960    pub fn unfold_recursive(
16961        &mut self,
16962        _: &UnfoldRecursive,
16963        _window: &mut Window,
16964        cx: &mut Context<Self>,
16965    ) {
16966        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16967        let selections = self.selections.all::<Point>(cx);
16968        let ranges = selections
16969            .iter()
16970            .map(|s| {
16971                let mut range = s.display_range(&display_map).sorted();
16972                *range.start.column_mut() = 0;
16973                *range.end.column_mut() = display_map.line_len(range.end.row());
16974                let start = range.start.to_point(&display_map);
16975                let end = range.end.to_point(&display_map);
16976                start..end
16977            })
16978            .collect::<Vec<_>>();
16979
16980        self.unfold_ranges(&ranges, true, true, cx);
16981    }
16982
16983    pub fn unfold_at(
16984        &mut self,
16985        buffer_row: MultiBufferRow,
16986        _window: &mut Window,
16987        cx: &mut Context<Self>,
16988    ) {
16989        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16990
16991        let intersection_range = Point::new(buffer_row.0, 0)
16992            ..Point::new(
16993                buffer_row.0,
16994                display_map.buffer_snapshot.line_len(buffer_row),
16995            );
16996
16997        let autoscroll = self
16998            .selections
16999            .all::<Point>(cx)
17000            .iter()
17001            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17002
17003        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17004    }
17005
17006    pub fn unfold_all(
17007        &mut self,
17008        _: &actions::UnfoldAll,
17009        _window: &mut Window,
17010        cx: &mut Context<Self>,
17011    ) {
17012        if self.buffer.read(cx).is_singleton() {
17013            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17014            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17015        } else {
17016            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17017                editor
17018                    .update(cx, |editor, cx| {
17019                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17020                            editor.unfold_buffer(buffer_id, cx);
17021                        }
17022                    })
17023                    .ok();
17024            });
17025        }
17026    }
17027
17028    pub fn fold_selected_ranges(
17029        &mut self,
17030        _: &FoldSelectedRanges,
17031        window: &mut Window,
17032        cx: &mut Context<Self>,
17033    ) {
17034        let selections = self.selections.all_adjusted(cx);
17035        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17036        let ranges = selections
17037            .into_iter()
17038            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17039            .collect::<Vec<_>>();
17040        self.fold_creases(ranges, true, window, cx);
17041    }
17042
17043    pub fn fold_ranges<T: ToOffset + Clone>(
17044        &mut self,
17045        ranges: Vec<Range<T>>,
17046        auto_scroll: bool,
17047        window: &mut Window,
17048        cx: &mut Context<Self>,
17049    ) {
17050        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17051        let ranges = ranges
17052            .into_iter()
17053            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17054            .collect::<Vec<_>>();
17055        self.fold_creases(ranges, auto_scroll, window, cx);
17056    }
17057
17058    pub fn fold_creases<T: ToOffset + Clone>(
17059        &mut self,
17060        creases: Vec<Crease<T>>,
17061        auto_scroll: bool,
17062        _window: &mut Window,
17063        cx: &mut Context<Self>,
17064    ) {
17065        if creases.is_empty() {
17066            return;
17067        }
17068
17069        let mut buffers_affected = HashSet::default();
17070        let multi_buffer = self.buffer().read(cx);
17071        for crease in &creases {
17072            if let Some((_, buffer, _)) =
17073                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
17074            {
17075                buffers_affected.insert(buffer.read(cx).remote_id());
17076            };
17077        }
17078
17079        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17080
17081        if auto_scroll {
17082            self.request_autoscroll(Autoscroll::fit(), cx);
17083        }
17084
17085        cx.notify();
17086
17087        self.scrollbar_marker_state.dirty = true;
17088        self.folds_did_change(cx);
17089    }
17090
17091    /// Removes any folds whose ranges intersect any of the given ranges.
17092    pub fn unfold_ranges<T: ToOffset + Clone>(
17093        &mut self,
17094        ranges: &[Range<T>],
17095        inclusive: bool,
17096        auto_scroll: bool,
17097        cx: &mut Context<Self>,
17098    ) {
17099        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17100            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17101        });
17102        self.folds_did_change(cx);
17103    }
17104
17105    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17106        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17107            return;
17108        }
17109        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17110        self.display_map.update(cx, |display_map, cx| {
17111            display_map.fold_buffers([buffer_id], cx)
17112        });
17113        cx.emit(EditorEvent::BufferFoldToggled {
17114            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17115            folded: true,
17116        });
17117        cx.notify();
17118    }
17119
17120    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17121        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17122            return;
17123        }
17124        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17125        self.display_map.update(cx, |display_map, cx| {
17126            display_map.unfold_buffers([buffer_id], cx);
17127        });
17128        cx.emit(EditorEvent::BufferFoldToggled {
17129            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17130            folded: false,
17131        });
17132        cx.notify();
17133    }
17134
17135    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17136        self.display_map.read(cx).is_buffer_folded(buffer)
17137    }
17138
17139    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17140        self.display_map.read(cx).folded_buffers()
17141    }
17142
17143    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17144        self.display_map.update(cx, |display_map, cx| {
17145            display_map.disable_header_for_buffer(buffer_id, cx);
17146        });
17147        cx.notify();
17148    }
17149
17150    /// Removes any folds with the given ranges.
17151    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17152        &mut self,
17153        ranges: &[Range<T>],
17154        type_id: TypeId,
17155        auto_scroll: bool,
17156        cx: &mut Context<Self>,
17157    ) {
17158        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17159            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17160        });
17161        self.folds_did_change(cx);
17162    }
17163
17164    fn remove_folds_with<T: ToOffset + Clone>(
17165        &mut self,
17166        ranges: &[Range<T>],
17167        auto_scroll: bool,
17168        cx: &mut Context<Self>,
17169        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17170    ) {
17171        if ranges.is_empty() {
17172            return;
17173        }
17174
17175        let mut buffers_affected = HashSet::default();
17176        let multi_buffer = self.buffer().read(cx);
17177        for range in ranges {
17178            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17179                buffers_affected.insert(buffer.read(cx).remote_id());
17180            };
17181        }
17182
17183        self.display_map.update(cx, update);
17184
17185        if auto_scroll {
17186            self.request_autoscroll(Autoscroll::fit(), cx);
17187        }
17188
17189        cx.notify();
17190        self.scrollbar_marker_state.dirty = true;
17191        self.active_indent_guides_state.dirty = true;
17192    }
17193
17194    pub fn update_fold_widths(
17195        &mut self,
17196        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
17197        cx: &mut Context<Self>,
17198    ) -> bool {
17199        self.display_map
17200            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17201    }
17202
17203    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17204        self.display_map.read(cx).fold_placeholder.clone()
17205    }
17206
17207    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17208        self.buffer.update(cx, |buffer, cx| {
17209            buffer.set_all_diff_hunks_expanded(cx);
17210        });
17211    }
17212
17213    pub fn expand_all_diff_hunks(
17214        &mut self,
17215        _: &ExpandAllDiffHunks,
17216        _window: &mut Window,
17217        cx: &mut Context<Self>,
17218    ) {
17219        self.buffer.update(cx, |buffer, cx| {
17220            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17221        });
17222    }
17223
17224    pub fn toggle_selected_diff_hunks(
17225        &mut self,
17226        _: &ToggleSelectedDiffHunks,
17227        _window: &mut Window,
17228        cx: &mut Context<Self>,
17229    ) {
17230        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17231        self.toggle_diff_hunks_in_ranges(ranges, cx);
17232    }
17233
17234    pub fn diff_hunks_in_ranges<'a>(
17235        &'a self,
17236        ranges: &'a [Range<Anchor>],
17237        buffer: &'a MultiBufferSnapshot,
17238    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17239        ranges.iter().flat_map(move |range| {
17240            let end_excerpt_id = range.end.excerpt_id;
17241            let range = range.to_point(buffer);
17242            let mut peek_end = range.end;
17243            if range.end.row < buffer.max_row().0 {
17244                peek_end = Point::new(range.end.row + 1, 0);
17245            }
17246            buffer
17247                .diff_hunks_in_range(range.start..peek_end)
17248                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17249        })
17250    }
17251
17252    pub fn has_stageable_diff_hunks_in_ranges(
17253        &self,
17254        ranges: &[Range<Anchor>],
17255        snapshot: &MultiBufferSnapshot,
17256    ) -> bool {
17257        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17258        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17259    }
17260
17261    pub fn toggle_staged_selected_diff_hunks(
17262        &mut self,
17263        _: &::git::ToggleStaged,
17264        _: &mut Window,
17265        cx: &mut Context<Self>,
17266    ) {
17267        let snapshot = self.buffer.read(cx).snapshot(cx);
17268        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17269        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17270        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17271    }
17272
17273    pub fn set_render_diff_hunk_controls(
17274        &mut self,
17275        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17276        cx: &mut Context<Self>,
17277    ) {
17278        self.render_diff_hunk_controls = render_diff_hunk_controls;
17279        cx.notify();
17280    }
17281
17282    pub fn stage_and_next(
17283        &mut self,
17284        _: &::git::StageAndNext,
17285        window: &mut Window,
17286        cx: &mut Context<Self>,
17287    ) {
17288        self.do_stage_or_unstage_and_next(true, window, cx);
17289    }
17290
17291    pub fn unstage_and_next(
17292        &mut self,
17293        _: &::git::UnstageAndNext,
17294        window: &mut Window,
17295        cx: &mut Context<Self>,
17296    ) {
17297        self.do_stage_or_unstage_and_next(false, window, cx);
17298    }
17299
17300    pub fn stage_or_unstage_diff_hunks(
17301        &mut self,
17302        stage: bool,
17303        ranges: Vec<Range<Anchor>>,
17304        cx: &mut Context<Self>,
17305    ) {
17306        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17307        cx.spawn(async move |this, cx| {
17308            task.await?;
17309            this.update(cx, |this, cx| {
17310                let snapshot = this.buffer.read(cx).snapshot(cx);
17311                let chunk_by = this
17312                    .diff_hunks_in_ranges(&ranges, &snapshot)
17313                    .chunk_by(|hunk| hunk.buffer_id);
17314                for (buffer_id, hunks) in &chunk_by {
17315                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17316                }
17317            })
17318        })
17319        .detach_and_log_err(cx);
17320    }
17321
17322    fn save_buffers_for_ranges_if_needed(
17323        &mut self,
17324        ranges: &[Range<Anchor>],
17325        cx: &mut Context<Editor>,
17326    ) -> Task<Result<()>> {
17327        let multibuffer = self.buffer.read(cx);
17328        let snapshot = multibuffer.read(cx);
17329        let buffer_ids: HashSet<_> = ranges
17330            .iter()
17331            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17332            .collect();
17333        drop(snapshot);
17334
17335        let mut buffers = HashSet::default();
17336        for buffer_id in buffer_ids {
17337            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17338                let buffer = buffer_entity.read(cx);
17339                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17340                {
17341                    buffers.insert(buffer_entity);
17342                }
17343            }
17344        }
17345
17346        if let Some(project) = &self.project {
17347            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17348        } else {
17349            Task::ready(Ok(()))
17350        }
17351    }
17352
17353    fn do_stage_or_unstage_and_next(
17354        &mut self,
17355        stage: bool,
17356        window: &mut Window,
17357        cx: &mut Context<Self>,
17358    ) {
17359        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17360
17361        if ranges.iter().any(|range| range.start != range.end) {
17362            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17363            return;
17364        }
17365
17366        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17367        let snapshot = self.snapshot(window, cx);
17368        let position = self.selections.newest::<Point>(cx).head();
17369        let mut row = snapshot
17370            .buffer_snapshot
17371            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17372            .find(|hunk| hunk.row_range.start.0 > position.row)
17373            .map(|hunk| hunk.row_range.start);
17374
17375        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17376        // Outside of the project diff editor, wrap around to the beginning.
17377        if !all_diff_hunks_expanded {
17378            row = row.or_else(|| {
17379                snapshot
17380                    .buffer_snapshot
17381                    .diff_hunks_in_range(Point::zero()..position)
17382                    .find(|hunk| hunk.row_range.end.0 < position.row)
17383                    .map(|hunk| hunk.row_range.start)
17384            });
17385        }
17386
17387        if let Some(row) = row {
17388            let destination = Point::new(row.0, 0);
17389            let autoscroll = Autoscroll::center();
17390
17391            self.unfold_ranges(&[destination..destination], false, false, cx);
17392            self.change_selections(Some(autoscroll), window, cx, |s| {
17393                s.select_ranges([destination..destination]);
17394            });
17395        }
17396    }
17397
17398    fn do_stage_or_unstage(
17399        &self,
17400        stage: bool,
17401        buffer_id: BufferId,
17402        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
17403        cx: &mut App,
17404    ) -> Option<()> {
17405        let project = self.project.as_ref()?;
17406        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
17407        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
17408        let buffer_snapshot = buffer.read(cx).snapshot();
17409        let file_exists = buffer_snapshot
17410            .file()
17411            .is_some_and(|file| file.disk_state().exists());
17412        diff.update(cx, |diff, cx| {
17413            diff.stage_or_unstage_hunks(
17414                stage,
17415                &hunks
17416                    .map(|hunk| buffer_diff::DiffHunk {
17417                        buffer_range: hunk.buffer_range,
17418                        diff_base_byte_range: hunk.diff_base_byte_range,
17419                        secondary_status: hunk.secondary_status,
17420                        range: Point::zero()..Point::zero(), // unused
17421                    })
17422                    .collect::<Vec<_>>(),
17423                &buffer_snapshot,
17424                file_exists,
17425                cx,
17426            )
17427        });
17428        None
17429    }
17430
17431    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
17432        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17433        self.buffer
17434            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
17435    }
17436
17437    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
17438        self.buffer.update(cx, |buffer, cx| {
17439            let ranges = vec![Anchor::min()..Anchor::max()];
17440            if !buffer.all_diff_hunks_expanded()
17441                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
17442            {
17443                buffer.collapse_diff_hunks(ranges, cx);
17444                true
17445            } else {
17446                false
17447            }
17448        })
17449    }
17450
17451    fn toggle_diff_hunks_in_ranges(
17452        &mut self,
17453        ranges: Vec<Range<Anchor>>,
17454        cx: &mut Context<Editor>,
17455    ) {
17456        self.buffer.update(cx, |buffer, cx| {
17457            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
17458            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
17459        })
17460    }
17461
17462    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
17463        self.buffer.update(cx, |buffer, cx| {
17464            let snapshot = buffer.snapshot(cx);
17465            let excerpt_id = range.end.excerpt_id;
17466            let point_range = range.to_point(&snapshot);
17467            let expand = !buffer.single_hunk_is_expanded(range, cx);
17468            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
17469        })
17470    }
17471
17472    pub(crate) fn apply_all_diff_hunks(
17473        &mut self,
17474        _: &ApplyAllDiffHunks,
17475        window: &mut Window,
17476        cx: &mut Context<Self>,
17477    ) {
17478        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17479
17480        let buffers = self.buffer.read(cx).all_buffers();
17481        for branch_buffer in buffers {
17482            branch_buffer.update(cx, |branch_buffer, cx| {
17483                branch_buffer.merge_into_base(Vec::new(), cx);
17484            });
17485        }
17486
17487        if let Some(project) = self.project.clone() {
17488            self.save(
17489                SaveOptions {
17490                    format: true,
17491                    autosave: false,
17492                },
17493                project,
17494                window,
17495                cx,
17496            )
17497            .detach_and_log_err(cx);
17498        }
17499    }
17500
17501    pub(crate) fn apply_selected_diff_hunks(
17502        &mut self,
17503        _: &ApplyDiffHunk,
17504        window: &mut Window,
17505        cx: &mut Context<Self>,
17506    ) {
17507        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17508        let snapshot = self.snapshot(window, cx);
17509        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
17510        let mut ranges_by_buffer = HashMap::default();
17511        self.transact(window, cx, |editor, _window, cx| {
17512            for hunk in hunks {
17513                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
17514                    ranges_by_buffer
17515                        .entry(buffer.clone())
17516                        .or_insert_with(Vec::new)
17517                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
17518                }
17519            }
17520
17521            for (buffer, ranges) in ranges_by_buffer {
17522                buffer.update(cx, |buffer, cx| {
17523                    buffer.merge_into_base(ranges, cx);
17524                });
17525            }
17526        });
17527
17528        if let Some(project) = self.project.clone() {
17529            self.save(
17530                SaveOptions {
17531                    format: true,
17532                    autosave: false,
17533                },
17534                project,
17535                window,
17536                cx,
17537            )
17538            .detach_and_log_err(cx);
17539        }
17540    }
17541
17542    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
17543        if hovered != self.gutter_hovered {
17544            self.gutter_hovered = hovered;
17545            cx.notify();
17546        }
17547    }
17548
17549    pub fn insert_blocks(
17550        &mut self,
17551        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
17552        autoscroll: Option<Autoscroll>,
17553        cx: &mut Context<Self>,
17554    ) -> Vec<CustomBlockId> {
17555        let blocks = self
17556            .display_map
17557            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
17558        if let Some(autoscroll) = autoscroll {
17559            self.request_autoscroll(autoscroll, cx);
17560        }
17561        cx.notify();
17562        blocks
17563    }
17564
17565    pub fn resize_blocks(
17566        &mut self,
17567        heights: HashMap<CustomBlockId, u32>,
17568        autoscroll: Option<Autoscroll>,
17569        cx: &mut Context<Self>,
17570    ) {
17571        self.display_map
17572            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
17573        if let Some(autoscroll) = autoscroll {
17574            self.request_autoscroll(autoscroll, cx);
17575        }
17576        cx.notify();
17577    }
17578
17579    pub fn replace_blocks(
17580        &mut self,
17581        renderers: HashMap<CustomBlockId, RenderBlock>,
17582        autoscroll: Option<Autoscroll>,
17583        cx: &mut Context<Self>,
17584    ) {
17585        self.display_map
17586            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
17587        if let Some(autoscroll) = autoscroll {
17588            self.request_autoscroll(autoscroll, cx);
17589        }
17590        cx.notify();
17591    }
17592
17593    pub fn remove_blocks(
17594        &mut self,
17595        block_ids: HashSet<CustomBlockId>,
17596        autoscroll: Option<Autoscroll>,
17597        cx: &mut Context<Self>,
17598    ) {
17599        self.display_map.update(cx, |display_map, cx| {
17600            display_map.remove_blocks(block_ids, cx)
17601        });
17602        if let Some(autoscroll) = autoscroll {
17603            self.request_autoscroll(autoscroll, cx);
17604        }
17605        cx.notify();
17606    }
17607
17608    pub fn row_for_block(
17609        &self,
17610        block_id: CustomBlockId,
17611        cx: &mut Context<Self>,
17612    ) -> Option<DisplayRow> {
17613        self.display_map
17614            .update(cx, |map, cx| map.row_for_block(block_id, cx))
17615    }
17616
17617    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
17618        self.focused_block = Some(focused_block);
17619    }
17620
17621    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
17622        self.focused_block.take()
17623    }
17624
17625    pub fn insert_creases(
17626        &mut self,
17627        creases: impl IntoIterator<Item = Crease<Anchor>>,
17628        cx: &mut Context<Self>,
17629    ) -> Vec<CreaseId> {
17630        self.display_map
17631            .update(cx, |map, cx| map.insert_creases(creases, cx))
17632    }
17633
17634    pub fn remove_creases(
17635        &mut self,
17636        ids: impl IntoIterator<Item = CreaseId>,
17637        cx: &mut Context<Self>,
17638    ) -> Vec<(CreaseId, Range<Anchor>)> {
17639        self.display_map
17640            .update(cx, |map, cx| map.remove_creases(ids, cx))
17641    }
17642
17643    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
17644        self.display_map
17645            .update(cx, |map, cx| map.snapshot(cx))
17646            .longest_row()
17647    }
17648
17649    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
17650        self.display_map
17651            .update(cx, |map, cx| map.snapshot(cx))
17652            .max_point()
17653    }
17654
17655    pub fn text(&self, cx: &App) -> String {
17656        self.buffer.read(cx).read(cx).text()
17657    }
17658
17659    pub fn is_empty(&self, cx: &App) -> bool {
17660        self.buffer.read(cx).read(cx).is_empty()
17661    }
17662
17663    pub fn text_option(&self, cx: &App) -> Option<String> {
17664        let text = self.text(cx);
17665        let text = text.trim();
17666
17667        if text.is_empty() {
17668            return None;
17669        }
17670
17671        Some(text.to_string())
17672    }
17673
17674    pub fn set_text(
17675        &mut self,
17676        text: impl Into<Arc<str>>,
17677        window: &mut Window,
17678        cx: &mut Context<Self>,
17679    ) {
17680        self.transact(window, cx, |this, _, cx| {
17681            this.buffer
17682                .read(cx)
17683                .as_singleton()
17684                .expect("you can only call set_text on editors for singleton buffers")
17685                .update(cx, |buffer, cx| buffer.set_text(text, cx));
17686        });
17687    }
17688
17689    pub fn display_text(&self, cx: &mut App) -> String {
17690        self.display_map
17691            .update(cx, |map, cx| map.snapshot(cx))
17692            .text()
17693    }
17694
17695    fn create_minimap(
17696        &self,
17697        minimap_settings: MinimapSettings,
17698        window: &mut Window,
17699        cx: &mut Context<Self>,
17700    ) -> Option<Entity<Self>> {
17701        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
17702            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17703    }
17704
17705    fn initialize_new_minimap(
17706        &self,
17707        minimap_settings: MinimapSettings,
17708        window: &mut Window,
17709        cx: &mut Context<Self>,
17710    ) -> Entity<Self> {
17711        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17712
17713        let mut minimap = Editor::new_internal(
17714            EditorMode::Minimap {
17715                parent: cx.weak_entity(),
17716            },
17717            self.buffer.clone(),
17718            self.project.clone(),
17719            Some(self.display_map.clone()),
17720            window,
17721            cx,
17722        );
17723        minimap.scroll_manager.clone_state(&self.scroll_manager);
17724        minimap.set_text_style_refinement(TextStyleRefinement {
17725            font_size: Some(MINIMAP_FONT_SIZE),
17726            font_weight: Some(MINIMAP_FONT_WEIGHT),
17727            ..Default::default()
17728        });
17729        minimap.update_minimap_configuration(minimap_settings, cx);
17730        cx.new(|_| minimap)
17731    }
17732
17733    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17734        let current_line_highlight = minimap_settings
17735            .current_line_highlight
17736            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17737        self.set_current_line_highlight(Some(current_line_highlight));
17738    }
17739
17740    pub fn minimap(&self) -> Option<&Entity<Self>> {
17741        self.minimap
17742            .as_ref()
17743            .filter(|_| self.minimap_visibility.visible())
17744    }
17745
17746    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17747        let mut wrap_guides = smallvec![];
17748
17749        if self.show_wrap_guides == Some(false) {
17750            return wrap_guides;
17751        }
17752
17753        let settings = self.buffer.read(cx).language_settings(cx);
17754        if settings.show_wrap_guides {
17755            match self.soft_wrap_mode(cx) {
17756                SoftWrap::Column(soft_wrap) => {
17757                    wrap_guides.push((soft_wrap as usize, true));
17758                }
17759                SoftWrap::Bounded(soft_wrap) => {
17760                    wrap_guides.push((soft_wrap as usize, true));
17761                }
17762                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17763            }
17764            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17765        }
17766
17767        wrap_guides
17768    }
17769
17770    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17771        let settings = self.buffer.read(cx).language_settings(cx);
17772        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17773        match mode {
17774            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17775                SoftWrap::None
17776            }
17777            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17778            language_settings::SoftWrap::PreferredLineLength => {
17779                SoftWrap::Column(settings.preferred_line_length)
17780            }
17781            language_settings::SoftWrap::Bounded => {
17782                SoftWrap::Bounded(settings.preferred_line_length)
17783            }
17784        }
17785    }
17786
17787    pub fn set_soft_wrap_mode(
17788        &mut self,
17789        mode: language_settings::SoftWrap,
17790
17791        cx: &mut Context<Self>,
17792    ) {
17793        self.soft_wrap_mode_override = Some(mode);
17794        cx.notify();
17795    }
17796
17797    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17798        self.hard_wrap = hard_wrap;
17799        cx.notify();
17800    }
17801
17802    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17803        self.text_style_refinement = Some(style);
17804    }
17805
17806    /// called by the Element so we know what style we were most recently rendered with.
17807    pub(crate) fn set_style(
17808        &mut self,
17809        style: EditorStyle,
17810        window: &mut Window,
17811        cx: &mut Context<Self>,
17812    ) {
17813        // We intentionally do not inform the display map about the minimap style
17814        // so that wrapping is not recalculated and stays consistent for the editor
17815        // and its linked minimap.
17816        if !self.mode.is_minimap() {
17817            let rem_size = window.rem_size();
17818            self.display_map.update(cx, |map, cx| {
17819                map.set_font(
17820                    style.text.font(),
17821                    style.text.font_size.to_pixels(rem_size),
17822                    cx,
17823                )
17824            });
17825        }
17826        self.style = Some(style);
17827    }
17828
17829    pub fn style(&self) -> Option<&EditorStyle> {
17830        self.style.as_ref()
17831    }
17832
17833    // Called by the element. This method is not designed to be called outside of the editor
17834    // element's layout code because it does not notify when rewrapping is computed synchronously.
17835    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17836        self.display_map
17837            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17838    }
17839
17840    pub fn set_soft_wrap(&mut self) {
17841        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17842    }
17843
17844    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17845        if self.soft_wrap_mode_override.is_some() {
17846            self.soft_wrap_mode_override.take();
17847        } else {
17848            let soft_wrap = match self.soft_wrap_mode(cx) {
17849                SoftWrap::GitDiff => return,
17850                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17851                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17852                    language_settings::SoftWrap::None
17853                }
17854            };
17855            self.soft_wrap_mode_override = Some(soft_wrap);
17856        }
17857        cx.notify();
17858    }
17859
17860    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17861        let Some(workspace) = self.workspace() else {
17862            return;
17863        };
17864        let fs = workspace.read(cx).app_state().fs.clone();
17865        let current_show = TabBarSettings::get_global(cx).show;
17866        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17867            setting.show = Some(!current_show);
17868        });
17869    }
17870
17871    pub fn toggle_indent_guides(
17872        &mut self,
17873        _: &ToggleIndentGuides,
17874        _: &mut Window,
17875        cx: &mut Context<Self>,
17876    ) {
17877        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17878            self.buffer
17879                .read(cx)
17880                .language_settings(cx)
17881                .indent_guides
17882                .enabled
17883        });
17884        self.show_indent_guides = Some(!currently_enabled);
17885        cx.notify();
17886    }
17887
17888    fn should_show_indent_guides(&self) -> Option<bool> {
17889        self.show_indent_guides
17890    }
17891
17892    pub fn toggle_line_numbers(
17893        &mut self,
17894        _: &ToggleLineNumbers,
17895        _: &mut Window,
17896        cx: &mut Context<Self>,
17897    ) {
17898        let mut editor_settings = EditorSettings::get_global(cx).clone();
17899        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17900        EditorSettings::override_global(editor_settings, cx);
17901    }
17902
17903    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17904        if let Some(show_line_numbers) = self.show_line_numbers {
17905            return show_line_numbers;
17906        }
17907        EditorSettings::get_global(cx).gutter.line_numbers
17908    }
17909
17910    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17911        self.use_relative_line_numbers
17912            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17913    }
17914
17915    pub fn toggle_relative_line_numbers(
17916        &mut self,
17917        _: &ToggleRelativeLineNumbers,
17918        _: &mut Window,
17919        cx: &mut Context<Self>,
17920    ) {
17921        let is_relative = self.should_use_relative_line_numbers(cx);
17922        self.set_relative_line_number(Some(!is_relative), cx)
17923    }
17924
17925    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17926        self.use_relative_line_numbers = is_relative;
17927        cx.notify();
17928    }
17929
17930    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17931        self.show_gutter = show_gutter;
17932        cx.notify();
17933    }
17934
17935    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17936        self.show_scrollbars = ScrollbarAxes {
17937            horizontal: show,
17938            vertical: show,
17939        };
17940        cx.notify();
17941    }
17942
17943    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17944        self.show_scrollbars.vertical = show;
17945        cx.notify();
17946    }
17947
17948    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17949        self.show_scrollbars.horizontal = show;
17950        cx.notify();
17951    }
17952
17953    pub fn set_minimap_visibility(
17954        &mut self,
17955        minimap_visibility: MinimapVisibility,
17956        window: &mut Window,
17957        cx: &mut Context<Self>,
17958    ) {
17959        if self.minimap_visibility != minimap_visibility {
17960            if minimap_visibility.visible() && self.minimap.is_none() {
17961                let minimap_settings = EditorSettings::get_global(cx).minimap;
17962                self.minimap =
17963                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17964            }
17965            self.minimap_visibility = minimap_visibility;
17966            cx.notify();
17967        }
17968    }
17969
17970    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17971        self.set_show_scrollbars(false, cx);
17972        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17973    }
17974
17975    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17976        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17977    }
17978
17979    /// Normally the text in full mode and auto height editors is padded on the
17980    /// left side by roughly half a character width for improved hit testing.
17981    ///
17982    /// Use this method to disable this for cases where this is not wanted (e.g.
17983    /// if you want to align the editor text with some other text above or below)
17984    /// or if you want to add this padding to single-line editors.
17985    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17986        self.offset_content = offset_content;
17987        cx.notify();
17988    }
17989
17990    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17991        self.show_line_numbers = Some(show_line_numbers);
17992        cx.notify();
17993    }
17994
17995    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17996        self.disable_expand_excerpt_buttons = true;
17997        cx.notify();
17998    }
17999
18000    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18001        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18002        cx.notify();
18003    }
18004
18005    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18006        self.show_code_actions = Some(show_code_actions);
18007        cx.notify();
18008    }
18009
18010    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18011        self.show_runnables = Some(show_runnables);
18012        cx.notify();
18013    }
18014
18015    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18016        self.show_breakpoints = Some(show_breakpoints);
18017        cx.notify();
18018    }
18019
18020    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18021        if self.display_map.read(cx).masked != masked {
18022            self.display_map.update(cx, |map, _| map.masked = masked);
18023        }
18024        cx.notify()
18025    }
18026
18027    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18028        self.show_wrap_guides = Some(show_wrap_guides);
18029        cx.notify();
18030    }
18031
18032    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18033        self.show_indent_guides = Some(show_indent_guides);
18034        cx.notify();
18035    }
18036
18037    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18038        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18039            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18040                if let Some(dir) = file.abs_path(cx).parent() {
18041                    return Some(dir.to_owned());
18042                }
18043            }
18044
18045            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18046                return Some(project_path.path.to_path_buf());
18047            }
18048        }
18049
18050        None
18051    }
18052
18053    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18054        self.active_excerpt(cx)?
18055            .1
18056            .read(cx)
18057            .file()
18058            .and_then(|f| f.as_local())
18059    }
18060
18061    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18062        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18063            let buffer = buffer.read(cx);
18064            if let Some(project_path) = buffer.project_path(cx) {
18065                let project = self.project.as_ref()?.read(cx);
18066                project.absolute_path(&project_path, cx)
18067            } else {
18068                buffer
18069                    .file()
18070                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18071            }
18072        })
18073    }
18074
18075    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18076        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18077            let project_path = buffer.read(cx).project_path(cx)?;
18078            let project = self.project.as_ref()?.read(cx);
18079            let entry = project.entry_for_path(&project_path, cx)?;
18080            let path = entry.path.to_path_buf();
18081            Some(path)
18082        })
18083    }
18084
18085    pub fn reveal_in_finder(
18086        &mut self,
18087        _: &RevealInFileManager,
18088        _window: &mut Window,
18089        cx: &mut Context<Self>,
18090    ) {
18091        if let Some(target) = self.target_file(cx) {
18092            cx.reveal_path(&target.abs_path(cx));
18093        }
18094    }
18095
18096    pub fn copy_path(
18097        &mut self,
18098        _: &zed_actions::workspace::CopyPath,
18099        _window: &mut Window,
18100        cx: &mut Context<Self>,
18101    ) {
18102        if let Some(path) = self.target_file_abs_path(cx) {
18103            if let Some(path) = path.to_str() {
18104                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18105            }
18106        }
18107    }
18108
18109    pub fn copy_relative_path(
18110        &mut self,
18111        _: &zed_actions::workspace::CopyRelativePath,
18112        _window: &mut Window,
18113        cx: &mut Context<Self>,
18114    ) {
18115        if let Some(path) = self.target_file_path(cx) {
18116            if let Some(path) = path.to_str() {
18117                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18118            }
18119        }
18120    }
18121
18122    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18123        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18124            buffer.read(cx).project_path(cx)
18125        } else {
18126            None
18127        }
18128    }
18129
18130    // Returns true if the editor handled a go-to-line request
18131    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18132        maybe!({
18133            let breakpoint_store = self.breakpoint_store.as_ref()?;
18134
18135            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18136            else {
18137                self.clear_row_highlights::<ActiveDebugLine>();
18138                return None;
18139            };
18140
18141            let position = active_stack_frame.position;
18142            let buffer_id = position.buffer_id?;
18143            let snapshot = self
18144                .project
18145                .as_ref()?
18146                .read(cx)
18147                .buffer_for_id(buffer_id, cx)?
18148                .read(cx)
18149                .snapshot();
18150
18151            let mut handled = false;
18152            for (id, ExcerptRange { context, .. }) in
18153                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18154            {
18155                if context.start.cmp(&position, &snapshot).is_ge()
18156                    || context.end.cmp(&position, &snapshot).is_lt()
18157                {
18158                    continue;
18159                }
18160                let snapshot = self.buffer.read(cx).snapshot(cx);
18161                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18162
18163                handled = true;
18164                self.clear_row_highlights::<ActiveDebugLine>();
18165
18166                self.go_to_line::<ActiveDebugLine>(
18167                    multibuffer_anchor,
18168                    Some(cx.theme().colors().editor_debugger_active_line_background),
18169                    window,
18170                    cx,
18171                );
18172
18173                cx.notify();
18174            }
18175
18176            handled.then_some(())
18177        })
18178        .is_some()
18179    }
18180
18181    pub fn copy_file_name_without_extension(
18182        &mut self,
18183        _: &CopyFileNameWithoutExtension,
18184        _: &mut Window,
18185        cx: &mut Context<Self>,
18186    ) {
18187        if let Some(file) = self.target_file(cx) {
18188            if let Some(file_stem) = file.path().file_stem() {
18189                if let Some(name) = file_stem.to_str() {
18190                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18191                }
18192            }
18193        }
18194    }
18195
18196    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18197        if let Some(file) = self.target_file(cx) {
18198            if let Some(file_name) = file.path().file_name() {
18199                if let Some(name) = file_name.to_str() {
18200                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18201                }
18202            }
18203        }
18204    }
18205
18206    pub fn toggle_git_blame(
18207        &mut self,
18208        _: &::git::Blame,
18209        window: &mut Window,
18210        cx: &mut Context<Self>,
18211    ) {
18212        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18213
18214        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18215            self.start_git_blame(true, window, cx);
18216        }
18217
18218        cx.notify();
18219    }
18220
18221    pub fn toggle_git_blame_inline(
18222        &mut self,
18223        _: &ToggleGitBlameInline,
18224        window: &mut Window,
18225        cx: &mut Context<Self>,
18226    ) {
18227        self.toggle_git_blame_inline_internal(true, window, cx);
18228        cx.notify();
18229    }
18230
18231    pub fn open_git_blame_commit(
18232        &mut self,
18233        _: &OpenGitBlameCommit,
18234        window: &mut Window,
18235        cx: &mut Context<Self>,
18236    ) {
18237        self.open_git_blame_commit_internal(window, cx);
18238    }
18239
18240    fn open_git_blame_commit_internal(
18241        &mut self,
18242        window: &mut Window,
18243        cx: &mut Context<Self>,
18244    ) -> Option<()> {
18245        let blame = self.blame.as_ref()?;
18246        let snapshot = self.snapshot(window, cx);
18247        let cursor = self.selections.newest::<Point>(cx).head();
18248        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18249        let blame_entry = blame
18250            .update(cx, |blame, cx| {
18251                blame
18252                    .blame_for_rows(
18253                        &[RowInfo {
18254                            buffer_id: Some(buffer.remote_id()),
18255                            buffer_row: Some(point.row),
18256                            ..Default::default()
18257                        }],
18258                        cx,
18259                    )
18260                    .next()
18261            })
18262            .flatten()?;
18263        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18264        let repo = blame.read(cx).repository(cx)?;
18265        let workspace = self.workspace()?.downgrade();
18266        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18267        None
18268    }
18269
18270    pub fn git_blame_inline_enabled(&self) -> bool {
18271        self.git_blame_inline_enabled
18272    }
18273
18274    pub fn toggle_selection_menu(
18275        &mut self,
18276        _: &ToggleSelectionMenu,
18277        _: &mut Window,
18278        cx: &mut Context<Self>,
18279    ) {
18280        self.show_selection_menu = self
18281            .show_selection_menu
18282            .map(|show_selections_menu| !show_selections_menu)
18283            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18284
18285        cx.notify();
18286    }
18287
18288    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18289        self.show_selection_menu
18290            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18291    }
18292
18293    fn start_git_blame(
18294        &mut self,
18295        user_triggered: bool,
18296        window: &mut Window,
18297        cx: &mut Context<Self>,
18298    ) {
18299        if let Some(project) = self.project.as_ref() {
18300            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18301                return;
18302            };
18303
18304            if buffer.read(cx).file().is_none() {
18305                return;
18306            }
18307
18308            let focused = self.focus_handle(cx).contains_focused(window, cx);
18309
18310            let project = project.clone();
18311            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18312            self.blame_subscription =
18313                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18314            self.blame = Some(blame);
18315        }
18316    }
18317
18318    fn toggle_git_blame_inline_internal(
18319        &mut self,
18320        user_triggered: bool,
18321        window: &mut Window,
18322        cx: &mut Context<Self>,
18323    ) {
18324        if self.git_blame_inline_enabled {
18325            self.git_blame_inline_enabled = false;
18326            self.show_git_blame_inline = false;
18327            self.show_git_blame_inline_delay_task.take();
18328        } else {
18329            self.git_blame_inline_enabled = true;
18330            self.start_git_blame_inline(user_triggered, window, cx);
18331        }
18332
18333        cx.notify();
18334    }
18335
18336    fn start_git_blame_inline(
18337        &mut self,
18338        user_triggered: bool,
18339        window: &mut Window,
18340        cx: &mut Context<Self>,
18341    ) {
18342        self.start_git_blame(user_triggered, window, cx);
18343
18344        if ProjectSettings::get_global(cx)
18345            .git
18346            .inline_blame_delay()
18347            .is_some()
18348        {
18349            self.start_inline_blame_timer(window, cx);
18350        } else {
18351            self.show_git_blame_inline = true
18352        }
18353    }
18354
18355    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18356        self.blame.as_ref()
18357    }
18358
18359    pub fn show_git_blame_gutter(&self) -> bool {
18360        self.show_git_blame_gutter
18361    }
18362
18363    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18364        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18365    }
18366
18367    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18368        self.show_git_blame_inline
18369            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18370            && !self.newest_selection_head_on_empty_line(cx)
18371            && self.has_blame_entries(cx)
18372    }
18373
18374    fn has_blame_entries(&self, cx: &App) -> bool {
18375        self.blame()
18376            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18377    }
18378
18379    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18380        let cursor_anchor = self.selections.newest_anchor().head();
18381
18382        let snapshot = self.buffer.read(cx).snapshot(cx);
18383        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
18384
18385        snapshot.line_len(buffer_row) == 0
18386    }
18387
18388    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
18389        let buffer_and_selection = maybe!({
18390            let selection = self.selections.newest::<Point>(cx);
18391            let selection_range = selection.range();
18392
18393            let multi_buffer = self.buffer().read(cx);
18394            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18395            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
18396
18397            let (buffer, range, _) = if selection.reversed {
18398                buffer_ranges.first()
18399            } else {
18400                buffer_ranges.last()
18401            }?;
18402
18403            let selection = text::ToPoint::to_point(&range.start, &buffer).row
18404                ..text::ToPoint::to_point(&range.end, &buffer).row;
18405            Some((
18406                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
18407                selection,
18408            ))
18409        });
18410
18411        let Some((buffer, selection)) = buffer_and_selection else {
18412            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
18413        };
18414
18415        let Some(project) = self.project.as_ref() else {
18416            return Task::ready(Err(anyhow!("editor does not have project")));
18417        };
18418
18419        project.update(cx, |project, cx| {
18420            project.get_permalink_to_line(&buffer, selection, cx)
18421        })
18422    }
18423
18424    pub fn copy_permalink_to_line(
18425        &mut self,
18426        _: &CopyPermalinkToLine,
18427        window: &mut Window,
18428        cx: &mut Context<Self>,
18429    ) {
18430        let permalink_task = self.get_permalink_to_line(cx);
18431        let workspace = self.workspace();
18432
18433        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18434            Ok(permalink) => {
18435                cx.update(|_, cx| {
18436                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
18437                })
18438                .ok();
18439            }
18440            Err(err) => {
18441                let message = format!("Failed to copy permalink: {err}");
18442
18443                anyhow::Result::<()>::Err(err).log_err();
18444
18445                if let Some(workspace) = workspace {
18446                    workspace
18447                        .update_in(cx, |workspace, _, cx| {
18448                            struct CopyPermalinkToLine;
18449
18450                            workspace.show_toast(
18451                                Toast::new(
18452                                    NotificationId::unique::<CopyPermalinkToLine>(),
18453                                    message,
18454                                ),
18455                                cx,
18456                            )
18457                        })
18458                        .ok();
18459                }
18460            }
18461        })
18462        .detach();
18463    }
18464
18465    pub fn copy_file_location(
18466        &mut self,
18467        _: &CopyFileLocation,
18468        _: &mut Window,
18469        cx: &mut Context<Self>,
18470    ) {
18471        let selection = self.selections.newest::<Point>(cx).start.row + 1;
18472        if let Some(file) = self.target_file(cx) {
18473            if let Some(path) = file.path().to_str() {
18474                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
18475            }
18476        }
18477    }
18478
18479    pub fn open_permalink_to_line(
18480        &mut self,
18481        _: &OpenPermalinkToLine,
18482        window: &mut Window,
18483        cx: &mut Context<Self>,
18484    ) {
18485        let permalink_task = self.get_permalink_to_line(cx);
18486        let workspace = self.workspace();
18487
18488        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
18489            Ok(permalink) => {
18490                cx.update(|_, cx| {
18491                    cx.open_url(permalink.as_ref());
18492                })
18493                .ok();
18494            }
18495            Err(err) => {
18496                let message = format!("Failed to open permalink: {err}");
18497
18498                anyhow::Result::<()>::Err(err).log_err();
18499
18500                if let Some(workspace) = workspace {
18501                    workspace
18502                        .update(cx, |workspace, cx| {
18503                            struct OpenPermalinkToLine;
18504
18505                            workspace.show_toast(
18506                                Toast::new(
18507                                    NotificationId::unique::<OpenPermalinkToLine>(),
18508                                    message,
18509                                ),
18510                                cx,
18511                            )
18512                        })
18513                        .ok();
18514                }
18515            }
18516        })
18517        .detach();
18518    }
18519
18520    pub fn insert_uuid_v4(
18521        &mut self,
18522        _: &InsertUuidV4,
18523        window: &mut Window,
18524        cx: &mut Context<Self>,
18525    ) {
18526        self.insert_uuid(UuidVersion::V4, window, cx);
18527    }
18528
18529    pub fn insert_uuid_v7(
18530        &mut self,
18531        _: &InsertUuidV7,
18532        window: &mut Window,
18533        cx: &mut Context<Self>,
18534    ) {
18535        self.insert_uuid(UuidVersion::V7, window, cx);
18536    }
18537
18538    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
18539        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18540        self.transact(window, cx, |this, window, cx| {
18541            let edits = this
18542                .selections
18543                .all::<Point>(cx)
18544                .into_iter()
18545                .map(|selection| {
18546                    let uuid = match version {
18547                        UuidVersion::V4 => uuid::Uuid::new_v4(),
18548                        UuidVersion::V7 => uuid::Uuid::now_v7(),
18549                    };
18550
18551                    (selection.range(), uuid.to_string())
18552                });
18553            this.edit(edits, cx);
18554            this.refresh_inline_completion(true, false, window, cx);
18555        });
18556    }
18557
18558    pub fn open_selections_in_multibuffer(
18559        &mut self,
18560        _: &OpenSelectionsInMultibuffer,
18561        window: &mut Window,
18562        cx: &mut Context<Self>,
18563    ) {
18564        let multibuffer = self.buffer.read(cx);
18565
18566        let Some(buffer) = multibuffer.as_singleton() else {
18567            return;
18568        };
18569
18570        let Some(workspace) = self.workspace() else {
18571            return;
18572        };
18573
18574        let title = multibuffer.title(cx).to_string();
18575
18576        let locations = self
18577            .selections
18578            .all_anchors(cx)
18579            .into_iter()
18580            .map(|selection| Location {
18581                buffer: buffer.clone(),
18582                range: selection.start.text_anchor..selection.end.text_anchor,
18583            })
18584            .collect::<Vec<_>>();
18585
18586        cx.spawn_in(window, async move |_, cx| {
18587            workspace.update_in(cx, |workspace, window, cx| {
18588                Self::open_locations_in_multibuffer(
18589                    workspace,
18590                    locations,
18591                    format!("Selections for '{title}'"),
18592                    false,
18593                    MultibufferSelectionMode::All,
18594                    window,
18595                    cx,
18596                );
18597            })
18598        })
18599        .detach();
18600    }
18601
18602    /// Adds a row highlight for the given range. If a row has multiple highlights, the
18603    /// last highlight added will be used.
18604    ///
18605    /// If the range ends at the beginning of a line, then that line will not be highlighted.
18606    pub fn highlight_rows<T: 'static>(
18607        &mut self,
18608        range: Range<Anchor>,
18609        color: Hsla,
18610        options: RowHighlightOptions,
18611        cx: &mut Context<Self>,
18612    ) {
18613        let snapshot = self.buffer().read(cx).snapshot(cx);
18614        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18615        let ix = row_highlights.binary_search_by(|highlight| {
18616            Ordering::Equal
18617                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
18618                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
18619        });
18620
18621        if let Err(mut ix) = ix {
18622            let index = post_inc(&mut self.highlight_order);
18623
18624            // If this range intersects with the preceding highlight, then merge it with
18625            // the preceding highlight. Otherwise insert a new highlight.
18626            let mut merged = false;
18627            if ix > 0 {
18628                let prev_highlight = &mut row_highlights[ix - 1];
18629                if prev_highlight
18630                    .range
18631                    .end
18632                    .cmp(&range.start, &snapshot)
18633                    .is_ge()
18634                {
18635                    ix -= 1;
18636                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
18637                        prev_highlight.range.end = range.end;
18638                    }
18639                    merged = true;
18640                    prev_highlight.index = index;
18641                    prev_highlight.color = color;
18642                    prev_highlight.options = options;
18643                }
18644            }
18645
18646            if !merged {
18647                row_highlights.insert(
18648                    ix,
18649                    RowHighlight {
18650                        range: range.clone(),
18651                        index,
18652                        color,
18653                        options,
18654                        type_id: TypeId::of::<T>(),
18655                    },
18656                );
18657            }
18658
18659            // If any of the following highlights intersect with this one, merge them.
18660            while let Some(next_highlight) = row_highlights.get(ix + 1) {
18661                let highlight = &row_highlights[ix];
18662                if next_highlight
18663                    .range
18664                    .start
18665                    .cmp(&highlight.range.end, &snapshot)
18666                    .is_le()
18667                {
18668                    if next_highlight
18669                        .range
18670                        .end
18671                        .cmp(&highlight.range.end, &snapshot)
18672                        .is_gt()
18673                    {
18674                        row_highlights[ix].range.end = next_highlight.range.end;
18675                    }
18676                    row_highlights.remove(ix + 1);
18677                } else {
18678                    break;
18679                }
18680            }
18681        }
18682    }
18683
18684    /// Remove any highlighted row ranges of the given type that intersect the
18685    /// given ranges.
18686    pub fn remove_highlighted_rows<T: 'static>(
18687        &mut self,
18688        ranges_to_remove: Vec<Range<Anchor>>,
18689        cx: &mut Context<Self>,
18690    ) {
18691        let snapshot = self.buffer().read(cx).snapshot(cx);
18692        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
18693        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18694        row_highlights.retain(|highlight| {
18695            while let Some(range_to_remove) = ranges_to_remove.peek() {
18696                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
18697                    Ordering::Less | Ordering::Equal => {
18698                        ranges_to_remove.next();
18699                    }
18700                    Ordering::Greater => {
18701                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
18702                            Ordering::Less | Ordering::Equal => {
18703                                return false;
18704                            }
18705                            Ordering::Greater => break,
18706                        }
18707                    }
18708                }
18709            }
18710
18711            true
18712        })
18713    }
18714
18715    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18716    pub fn clear_row_highlights<T: 'static>(&mut self) {
18717        self.highlighted_rows.remove(&TypeId::of::<T>());
18718    }
18719
18720    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18721    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18722        self.highlighted_rows
18723            .get(&TypeId::of::<T>())
18724            .map_or(&[] as &[_], |vec| vec.as_slice())
18725            .iter()
18726            .map(|highlight| (highlight.range.clone(), highlight.color))
18727    }
18728
18729    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18730    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18731    /// Allows to ignore certain kinds of highlights.
18732    pub fn highlighted_display_rows(
18733        &self,
18734        window: &mut Window,
18735        cx: &mut App,
18736    ) -> BTreeMap<DisplayRow, LineHighlight> {
18737        let snapshot = self.snapshot(window, cx);
18738        let mut used_highlight_orders = HashMap::default();
18739        self.highlighted_rows
18740            .iter()
18741            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18742            .fold(
18743                BTreeMap::<DisplayRow, LineHighlight>::new(),
18744                |mut unique_rows, highlight| {
18745                    let start = highlight.range.start.to_display_point(&snapshot);
18746                    let end = highlight.range.end.to_display_point(&snapshot);
18747                    let start_row = start.row().0;
18748                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18749                        && end.column() == 0
18750                    {
18751                        end.row().0.saturating_sub(1)
18752                    } else {
18753                        end.row().0
18754                    };
18755                    for row in start_row..=end_row {
18756                        let used_index =
18757                            used_highlight_orders.entry(row).or_insert(highlight.index);
18758                        if highlight.index >= *used_index {
18759                            *used_index = highlight.index;
18760                            unique_rows.insert(
18761                                DisplayRow(row),
18762                                LineHighlight {
18763                                    include_gutter: highlight.options.include_gutter,
18764                                    border: None,
18765                                    background: highlight.color.into(),
18766                                    type_id: Some(highlight.type_id),
18767                                },
18768                            );
18769                        }
18770                    }
18771                    unique_rows
18772                },
18773            )
18774    }
18775
18776    pub fn highlighted_display_row_for_autoscroll(
18777        &self,
18778        snapshot: &DisplaySnapshot,
18779    ) -> Option<DisplayRow> {
18780        self.highlighted_rows
18781            .values()
18782            .flat_map(|highlighted_rows| highlighted_rows.iter())
18783            .filter_map(|highlight| {
18784                if highlight.options.autoscroll {
18785                    Some(highlight.range.start.to_display_point(snapshot).row())
18786                } else {
18787                    None
18788                }
18789            })
18790            .min()
18791    }
18792
18793    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18794        self.highlight_background::<SearchWithinRange>(
18795            ranges,
18796            |colors| colors.colors().editor_document_highlight_read_background,
18797            cx,
18798        )
18799    }
18800
18801    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18802        self.breadcrumb_header = Some(new_header);
18803    }
18804
18805    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18806        self.clear_background_highlights::<SearchWithinRange>(cx);
18807    }
18808
18809    pub fn highlight_background<T: 'static>(
18810        &mut self,
18811        ranges: &[Range<Anchor>],
18812        color_fetcher: fn(&Theme) -> Hsla,
18813        cx: &mut Context<Self>,
18814    ) {
18815        self.background_highlights.insert(
18816            HighlightKey::Type(TypeId::of::<T>()),
18817            (color_fetcher, Arc::from(ranges)),
18818        );
18819        self.scrollbar_marker_state.dirty = true;
18820        cx.notify();
18821    }
18822
18823    pub fn highlight_background_key<T: 'static>(
18824        &mut self,
18825        key: usize,
18826        ranges: &[Range<Anchor>],
18827        color_fetcher: fn(&Theme) -> Hsla,
18828        cx: &mut Context<Self>,
18829    ) {
18830        self.background_highlights.insert(
18831            HighlightKey::TypePlus(TypeId::of::<T>(), key),
18832            (color_fetcher, Arc::from(ranges)),
18833        );
18834        self.scrollbar_marker_state.dirty = true;
18835        cx.notify();
18836    }
18837
18838    pub fn clear_background_highlights<T: 'static>(
18839        &mut self,
18840        cx: &mut Context<Self>,
18841    ) -> Option<BackgroundHighlight> {
18842        let text_highlights = self
18843            .background_highlights
18844            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
18845        if !text_highlights.1.is_empty() {
18846            self.scrollbar_marker_state.dirty = true;
18847            cx.notify();
18848        }
18849        Some(text_highlights)
18850    }
18851
18852    pub fn highlight_gutter<T: 'static>(
18853        &mut self,
18854        ranges: impl Into<Vec<Range<Anchor>>>,
18855        color_fetcher: fn(&App) -> Hsla,
18856        cx: &mut Context<Self>,
18857    ) {
18858        self.gutter_highlights
18859            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
18860        cx.notify();
18861    }
18862
18863    pub fn clear_gutter_highlights<T: 'static>(
18864        &mut self,
18865        cx: &mut Context<Self>,
18866    ) -> Option<GutterHighlight> {
18867        cx.notify();
18868        self.gutter_highlights.remove(&TypeId::of::<T>())
18869    }
18870
18871    pub fn insert_gutter_highlight<T: 'static>(
18872        &mut self,
18873        range: Range<Anchor>,
18874        color_fetcher: fn(&App) -> Hsla,
18875        cx: &mut Context<Self>,
18876    ) {
18877        let snapshot = self.buffer().read(cx).snapshot(cx);
18878        let mut highlights = self
18879            .gutter_highlights
18880            .remove(&TypeId::of::<T>())
18881            .map(|(_, highlights)| highlights)
18882            .unwrap_or_default();
18883        let ix = highlights.binary_search_by(|highlight| {
18884            Ordering::Equal
18885                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
18886                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
18887        });
18888        if let Err(ix) = ix {
18889            highlights.insert(ix, range);
18890        }
18891        self.gutter_highlights
18892            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
18893    }
18894
18895    pub fn remove_gutter_highlights<T: 'static>(
18896        &mut self,
18897        ranges_to_remove: Vec<Range<Anchor>>,
18898        cx: &mut Context<Self>,
18899    ) {
18900        let snapshot = self.buffer().read(cx).snapshot(cx);
18901        let Some((color_fetcher, mut gutter_highlights)) =
18902            self.gutter_highlights.remove(&TypeId::of::<T>())
18903        else {
18904            return;
18905        };
18906        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
18907        gutter_highlights.retain(|highlight| {
18908            while let Some(range_to_remove) = ranges_to_remove.peek() {
18909                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
18910                    Ordering::Less | Ordering::Equal => {
18911                        ranges_to_remove.next();
18912                    }
18913                    Ordering::Greater => {
18914                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
18915                            Ordering::Less | Ordering::Equal => {
18916                                return false;
18917                            }
18918                            Ordering::Greater => break,
18919                        }
18920                    }
18921                }
18922            }
18923
18924            true
18925        });
18926        self.gutter_highlights
18927            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
18928    }
18929
18930    #[cfg(feature = "test-support")]
18931    pub fn all_text_highlights(
18932        &self,
18933        window: &mut Window,
18934        cx: &mut Context<Self>,
18935    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
18936        let snapshot = self.snapshot(window, cx);
18937        self.display_map.update(cx, |display_map, _| {
18938            display_map
18939                .all_text_highlights()
18940                .map(|highlight| {
18941                    let (style, ranges) = highlight.as_ref();
18942                    (
18943                        *style,
18944                        ranges
18945                            .iter()
18946                            .map(|range| range.clone().to_display_points(&snapshot))
18947                            .collect(),
18948                    )
18949                })
18950                .collect()
18951        })
18952    }
18953
18954    #[cfg(feature = "test-support")]
18955    pub fn all_text_background_highlights(
18956        &self,
18957        window: &mut Window,
18958        cx: &mut Context<Self>,
18959    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18960        let snapshot = self.snapshot(window, cx);
18961        let buffer = &snapshot.buffer_snapshot;
18962        let start = buffer.anchor_before(0);
18963        let end = buffer.anchor_after(buffer.len());
18964        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
18965    }
18966
18967    #[cfg(feature = "test-support")]
18968    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18969        let snapshot = self.buffer().read(cx).snapshot(cx);
18970
18971        let highlights = self
18972            .background_highlights
18973            .get(&HighlightKey::Type(TypeId::of::<
18974                items::BufferSearchHighlights,
18975            >()));
18976
18977        if let Some((_color, ranges)) = highlights {
18978            ranges
18979                .iter()
18980                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18981                .collect_vec()
18982        } else {
18983            vec![]
18984        }
18985    }
18986
18987    fn document_highlights_for_position<'a>(
18988        &'a self,
18989        position: Anchor,
18990        buffer: &'a MultiBufferSnapshot,
18991    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18992        let read_highlights = self
18993            .background_highlights
18994            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
18995            .map(|h| &h.1);
18996        let write_highlights = self
18997            .background_highlights
18998            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
18999            .map(|h| &h.1);
19000        let left_position = position.bias_left(buffer);
19001        let right_position = position.bias_right(buffer);
19002        read_highlights
19003            .into_iter()
19004            .chain(write_highlights)
19005            .flat_map(move |ranges| {
19006                let start_ix = match ranges.binary_search_by(|probe| {
19007                    let cmp = probe.end.cmp(&left_position, buffer);
19008                    if cmp.is_ge() {
19009                        Ordering::Greater
19010                    } else {
19011                        Ordering::Less
19012                    }
19013                }) {
19014                    Ok(i) | Err(i) => i,
19015                };
19016
19017                ranges[start_ix..]
19018                    .iter()
19019                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19020            })
19021    }
19022
19023    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19024        self.background_highlights
19025            .get(&HighlightKey::Type(TypeId::of::<T>()))
19026            .map_or(false, |(_, highlights)| !highlights.is_empty())
19027    }
19028
19029    pub fn background_highlights_in_range(
19030        &self,
19031        search_range: Range<Anchor>,
19032        display_snapshot: &DisplaySnapshot,
19033        theme: &Theme,
19034    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19035        let mut results = Vec::new();
19036        for (color_fetcher, ranges) in self.background_highlights.values() {
19037            let color = color_fetcher(theme);
19038            let start_ix = match ranges.binary_search_by(|probe| {
19039                let cmp = probe
19040                    .end
19041                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19042                if cmp.is_gt() {
19043                    Ordering::Greater
19044                } else {
19045                    Ordering::Less
19046                }
19047            }) {
19048                Ok(i) | Err(i) => i,
19049            };
19050            for range in &ranges[start_ix..] {
19051                if range
19052                    .start
19053                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19054                    .is_ge()
19055                {
19056                    break;
19057                }
19058
19059                let start = range.start.to_display_point(display_snapshot);
19060                let end = range.end.to_display_point(display_snapshot);
19061                results.push((start..end, color))
19062            }
19063        }
19064        results
19065    }
19066
19067    pub fn background_highlight_row_ranges<T: 'static>(
19068        &self,
19069        search_range: Range<Anchor>,
19070        display_snapshot: &DisplaySnapshot,
19071        count: usize,
19072    ) -> Vec<RangeInclusive<DisplayPoint>> {
19073        let mut results = Vec::new();
19074        let Some((_, ranges)) = self
19075            .background_highlights
19076            .get(&HighlightKey::Type(TypeId::of::<T>()))
19077        else {
19078            return vec![];
19079        };
19080
19081        let start_ix = match ranges.binary_search_by(|probe| {
19082            let cmp = probe
19083                .end
19084                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19085            if cmp.is_gt() {
19086                Ordering::Greater
19087            } else {
19088                Ordering::Less
19089            }
19090        }) {
19091            Ok(i) | Err(i) => i,
19092        };
19093        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19094            if let (Some(start_display), Some(end_display)) = (start, end) {
19095                results.push(
19096                    start_display.to_display_point(display_snapshot)
19097                        ..=end_display.to_display_point(display_snapshot),
19098                );
19099            }
19100        };
19101        let mut start_row: Option<Point> = None;
19102        let mut end_row: Option<Point> = None;
19103        if ranges.len() > count {
19104            return Vec::new();
19105        }
19106        for range in &ranges[start_ix..] {
19107            if range
19108                .start
19109                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19110                .is_ge()
19111            {
19112                break;
19113            }
19114            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19115            if let Some(current_row) = &end_row {
19116                if end.row == current_row.row {
19117                    continue;
19118                }
19119            }
19120            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19121            if start_row.is_none() {
19122                assert_eq!(end_row, None);
19123                start_row = Some(start);
19124                end_row = Some(end);
19125                continue;
19126            }
19127            if let Some(current_end) = end_row.as_mut() {
19128                if start.row > current_end.row + 1 {
19129                    push_region(start_row, end_row);
19130                    start_row = Some(start);
19131                    end_row = Some(end);
19132                } else {
19133                    // Merge two hunks.
19134                    *current_end = end;
19135                }
19136            } else {
19137                unreachable!();
19138            }
19139        }
19140        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19141        push_region(start_row, end_row);
19142        results
19143    }
19144
19145    pub fn gutter_highlights_in_range(
19146        &self,
19147        search_range: Range<Anchor>,
19148        display_snapshot: &DisplaySnapshot,
19149        cx: &App,
19150    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19151        let mut results = Vec::new();
19152        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19153            let color = color_fetcher(cx);
19154            let start_ix = match ranges.binary_search_by(|probe| {
19155                let cmp = probe
19156                    .end
19157                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19158                if cmp.is_gt() {
19159                    Ordering::Greater
19160                } else {
19161                    Ordering::Less
19162                }
19163            }) {
19164                Ok(i) | Err(i) => i,
19165            };
19166            for range in &ranges[start_ix..] {
19167                if range
19168                    .start
19169                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19170                    .is_ge()
19171                {
19172                    break;
19173                }
19174
19175                let start = range.start.to_display_point(display_snapshot);
19176                let end = range.end.to_display_point(display_snapshot);
19177                results.push((start..end, color))
19178            }
19179        }
19180        results
19181    }
19182
19183    /// Get the text ranges corresponding to the redaction query
19184    pub fn redacted_ranges(
19185        &self,
19186        search_range: Range<Anchor>,
19187        display_snapshot: &DisplaySnapshot,
19188        cx: &App,
19189    ) -> Vec<Range<DisplayPoint>> {
19190        display_snapshot
19191            .buffer_snapshot
19192            .redacted_ranges(search_range, |file| {
19193                if let Some(file) = file {
19194                    file.is_private()
19195                        && EditorSettings::get(
19196                            Some(SettingsLocation {
19197                                worktree_id: file.worktree_id(cx),
19198                                path: file.path().as_ref(),
19199                            }),
19200                            cx,
19201                        )
19202                        .redact_private_values
19203                } else {
19204                    false
19205                }
19206            })
19207            .map(|range| {
19208                range.start.to_display_point(display_snapshot)
19209                    ..range.end.to_display_point(display_snapshot)
19210            })
19211            .collect()
19212    }
19213
19214    pub fn highlight_text_key<T: 'static>(
19215        &mut self,
19216        key: usize,
19217        ranges: Vec<Range<Anchor>>,
19218        style: HighlightStyle,
19219        cx: &mut Context<Self>,
19220    ) {
19221        self.display_map.update(cx, |map, _| {
19222            map.highlight_text(
19223                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19224                ranges,
19225                style,
19226            );
19227        });
19228        cx.notify();
19229    }
19230
19231    pub fn highlight_text<T: 'static>(
19232        &mut self,
19233        ranges: Vec<Range<Anchor>>,
19234        style: HighlightStyle,
19235        cx: &mut Context<Self>,
19236    ) {
19237        self.display_map.update(cx, |map, _| {
19238            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19239        });
19240        cx.notify();
19241    }
19242
19243    pub(crate) fn highlight_inlays<T: 'static>(
19244        &mut self,
19245        highlights: Vec<InlayHighlight>,
19246        style: HighlightStyle,
19247        cx: &mut Context<Self>,
19248    ) {
19249        self.display_map.update(cx, |map, _| {
19250            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19251        });
19252        cx.notify();
19253    }
19254
19255    pub fn text_highlights<'a, T: 'static>(
19256        &'a self,
19257        cx: &'a App,
19258    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19259        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19260    }
19261
19262    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19263        let cleared = self
19264            .display_map
19265            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19266        if cleared {
19267            cx.notify();
19268        }
19269    }
19270
19271    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19272        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19273            && self.focus_handle.is_focused(window)
19274    }
19275
19276    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19277        self.show_cursor_when_unfocused = is_enabled;
19278        cx.notify();
19279    }
19280
19281    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19282        cx.notify();
19283    }
19284
19285    fn on_debug_session_event(
19286        &mut self,
19287        _session: Entity<Session>,
19288        event: &SessionEvent,
19289        cx: &mut Context<Self>,
19290    ) {
19291        match event {
19292            SessionEvent::InvalidateInlineValue => {
19293                self.refresh_inline_values(cx);
19294            }
19295            _ => {}
19296        }
19297    }
19298
19299    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19300        let Some(project) = self.project.clone() else {
19301            return;
19302        };
19303
19304        if !self.inline_value_cache.enabled {
19305            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19306            self.splice_inlays(&inlays, Vec::new(), cx);
19307            return;
19308        }
19309
19310        let current_execution_position = self
19311            .highlighted_rows
19312            .get(&TypeId::of::<ActiveDebugLine>())
19313            .and_then(|lines| lines.last().map(|line| line.range.end));
19314
19315        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19316            let inline_values = editor
19317                .update(cx, |editor, cx| {
19318                    let Some(current_execution_position) = current_execution_position else {
19319                        return Some(Task::ready(Ok(Vec::new())));
19320                    };
19321
19322                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19323                        let snapshot = buffer.snapshot(cx);
19324
19325                        let excerpt = snapshot.excerpt_containing(
19326                            current_execution_position..current_execution_position,
19327                        )?;
19328
19329                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19330                    })?;
19331
19332                    let range =
19333                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19334
19335                    project.inline_values(buffer, range, cx)
19336                })
19337                .ok()
19338                .flatten()?
19339                .await
19340                .context("refreshing debugger inlays")
19341                .log_err()?;
19342
19343            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19344
19345            for (buffer_id, inline_value) in inline_values
19346                .into_iter()
19347                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19348            {
19349                buffer_inline_values
19350                    .entry(buffer_id)
19351                    .or_default()
19352                    .push(inline_value);
19353            }
19354
19355            editor
19356                .update(cx, |editor, cx| {
19357                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19358                    let mut new_inlays = Vec::default();
19359
19360                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19361                        let buffer_id = buffer_snapshot.remote_id();
19362                        buffer_inline_values
19363                            .get(&buffer_id)
19364                            .into_iter()
19365                            .flatten()
19366                            .for_each(|hint| {
19367                                let inlay = Inlay::debugger(
19368                                    post_inc(&mut editor.next_inlay_id),
19369                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19370                                    hint.text(),
19371                                );
19372
19373                                new_inlays.push(inlay);
19374                            });
19375                    }
19376
19377                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19378                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19379
19380                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19381                })
19382                .ok()?;
19383            Some(())
19384        });
19385    }
19386
19387    fn on_buffer_event(
19388        &mut self,
19389        multibuffer: &Entity<MultiBuffer>,
19390        event: &multi_buffer::Event,
19391        window: &mut Window,
19392        cx: &mut Context<Self>,
19393    ) {
19394        match event {
19395            multi_buffer::Event::Edited {
19396                singleton_buffer_edited,
19397                edited_buffer,
19398            } => {
19399                self.scrollbar_marker_state.dirty = true;
19400                self.active_indent_guides_state.dirty = true;
19401                self.refresh_active_diagnostics(cx);
19402                self.refresh_code_actions(window, cx);
19403                self.refresh_selected_text_highlights(true, window, cx);
19404                refresh_matching_bracket_highlights(self, window, cx);
19405                if self.has_active_inline_completion() {
19406                    self.update_visible_inline_completion(window, cx);
19407                }
19408                if let Some(project) = self.project.as_ref() {
19409                    if let Some(edited_buffer) = edited_buffer {
19410                        project.update(cx, |project, cx| {
19411                            self.registered_buffers
19412                                .entry(edited_buffer.read(cx).remote_id())
19413                                .or_insert_with(|| {
19414                                    project
19415                                        .register_buffer_with_language_servers(&edited_buffer, cx)
19416                                });
19417                        });
19418                    }
19419                }
19420                cx.emit(EditorEvent::BufferEdited);
19421                cx.emit(SearchEvent::MatchesInvalidated);
19422
19423                if let Some(buffer) = edited_buffer {
19424                    self.update_lsp_data(None, Some(buffer.read(cx).remote_id()), window, cx);
19425                }
19426
19427                if *singleton_buffer_edited {
19428                    if let Some(buffer) = edited_buffer {
19429                        if buffer.read(cx).file().is_none() {
19430                            cx.emit(EditorEvent::TitleChanged);
19431                        }
19432                    }
19433                    if let Some(project) = &self.project {
19434                        #[allow(clippy::mutable_key_type)]
19435                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
19436                            multibuffer
19437                                .all_buffers()
19438                                .into_iter()
19439                                .filter_map(|buffer| {
19440                                    buffer.update(cx, |buffer, cx| {
19441                                        let language = buffer.language()?;
19442                                        let should_discard = project.update(cx, |project, cx| {
19443                                            project.is_local()
19444                                                && !project.has_language_servers_for(buffer, cx)
19445                                        });
19446                                        should_discard.not().then_some(language.clone())
19447                                    })
19448                                })
19449                                .collect::<HashSet<_>>()
19450                        });
19451                        if !languages_affected.is_empty() {
19452                            self.refresh_inlay_hints(
19453                                InlayHintRefreshReason::BufferEdited(languages_affected),
19454                                cx,
19455                            );
19456                        }
19457                    }
19458                }
19459
19460                let Some(project) = &self.project else { return };
19461                let (telemetry, is_via_ssh) = {
19462                    let project = project.read(cx);
19463                    let telemetry = project.client().telemetry().clone();
19464                    let is_via_ssh = project.is_via_ssh();
19465                    (telemetry, is_via_ssh)
19466                };
19467                refresh_linked_ranges(self, window, cx);
19468                telemetry.log_edit_event("editor", is_via_ssh);
19469            }
19470            multi_buffer::Event::ExcerptsAdded {
19471                buffer,
19472                predecessor,
19473                excerpts,
19474            } => {
19475                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19476                let buffer_id = buffer.read(cx).remote_id();
19477                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
19478                    if let Some(project) = &self.project {
19479                        update_uncommitted_diff_for_buffer(
19480                            cx.entity(),
19481                            project,
19482                            [buffer.clone()],
19483                            self.buffer.clone(),
19484                            cx,
19485                        )
19486                        .detach();
19487                    }
19488                }
19489                self.update_lsp_data(None, Some(buffer_id), window, cx);
19490                cx.emit(EditorEvent::ExcerptsAdded {
19491                    buffer: buffer.clone(),
19492                    predecessor: *predecessor,
19493                    excerpts: excerpts.clone(),
19494                });
19495                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19496            }
19497            multi_buffer::Event::ExcerptsRemoved {
19498                ids,
19499                removed_buffer_ids,
19500            } => {
19501                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
19502                let buffer = self.buffer.read(cx);
19503                self.registered_buffers
19504                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
19505                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19506                cx.emit(EditorEvent::ExcerptsRemoved {
19507                    ids: ids.clone(),
19508                    removed_buffer_ids: removed_buffer_ids.clone(),
19509                });
19510            }
19511            multi_buffer::Event::ExcerptsEdited {
19512                excerpt_ids,
19513                buffer_ids,
19514            } => {
19515                self.display_map.update(cx, |map, cx| {
19516                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
19517                });
19518                cx.emit(EditorEvent::ExcerptsEdited {
19519                    ids: excerpt_ids.clone(),
19520                });
19521            }
19522            multi_buffer::Event::ExcerptsExpanded { ids } => {
19523                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
19524                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
19525            }
19526            multi_buffer::Event::Reparsed(buffer_id) => {
19527                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19528                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19529
19530                cx.emit(EditorEvent::Reparsed(*buffer_id));
19531            }
19532            multi_buffer::Event::DiffHunksToggled => {
19533                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19534            }
19535            multi_buffer::Event::LanguageChanged(buffer_id) => {
19536                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
19537                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
19538                cx.emit(EditorEvent::Reparsed(*buffer_id));
19539                cx.notify();
19540            }
19541            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
19542            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
19543            multi_buffer::Event::FileHandleChanged
19544            | multi_buffer::Event::Reloaded
19545            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
19546            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
19547            multi_buffer::Event::DiagnosticsUpdated => {
19548                self.update_diagnostics_state(window, cx);
19549            }
19550            _ => {}
19551        };
19552    }
19553
19554    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
19555        if !self.diagnostics_enabled() {
19556            return;
19557        }
19558        self.refresh_active_diagnostics(cx);
19559        self.refresh_inline_diagnostics(true, window, cx);
19560        self.scrollbar_marker_state.dirty = true;
19561        cx.notify();
19562    }
19563
19564    pub fn start_temporary_diff_override(&mut self) {
19565        self.load_diff_task.take();
19566        self.temporary_diff_override = true;
19567    }
19568
19569    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
19570        self.temporary_diff_override = false;
19571        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
19572        self.buffer.update(cx, |buffer, cx| {
19573            buffer.set_all_diff_hunks_collapsed(cx);
19574        });
19575
19576        if let Some(project) = self.project.clone() {
19577            self.load_diff_task = Some(
19578                update_uncommitted_diff_for_buffer(
19579                    cx.entity(),
19580                    &project,
19581                    self.buffer.read(cx).all_buffers(),
19582                    self.buffer.clone(),
19583                    cx,
19584                )
19585                .shared(),
19586            );
19587        }
19588    }
19589
19590    fn on_display_map_changed(
19591        &mut self,
19592        _: Entity<DisplayMap>,
19593        _: &mut Window,
19594        cx: &mut Context<Self>,
19595    ) {
19596        cx.notify();
19597    }
19598
19599    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19600        let new_severity = if self.diagnostics_enabled() {
19601            EditorSettings::get_global(cx)
19602                .diagnostics_max_severity
19603                .unwrap_or(DiagnosticSeverity::Hint)
19604        } else {
19605            DiagnosticSeverity::Off
19606        };
19607        self.set_max_diagnostics_severity(new_severity, cx);
19608        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
19609        self.update_edit_prediction_settings(cx);
19610        self.refresh_inline_completion(true, false, window, cx);
19611        self.refresh_inlay_hints(
19612            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
19613                self.selections.newest_anchor().head(),
19614                &self.buffer.read(cx).snapshot(cx),
19615                cx,
19616            )),
19617            cx,
19618        );
19619
19620        let old_cursor_shape = self.cursor_shape;
19621
19622        {
19623            let editor_settings = EditorSettings::get_global(cx);
19624            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
19625            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
19626            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
19627            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
19628            self.drag_and_drop_selection_enabled = editor_settings.drag_and_drop_selection;
19629        }
19630
19631        if old_cursor_shape != self.cursor_shape {
19632            cx.emit(EditorEvent::CursorShapeChanged);
19633        }
19634
19635        let project_settings = ProjectSettings::get_global(cx);
19636        self.serialize_dirty_buffers =
19637            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
19638
19639        if self.mode.is_full() {
19640            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
19641            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
19642            if self.show_inline_diagnostics != show_inline_diagnostics {
19643                self.show_inline_diagnostics = show_inline_diagnostics;
19644                self.refresh_inline_diagnostics(false, window, cx);
19645            }
19646
19647            if self.git_blame_inline_enabled != inline_blame_enabled {
19648                self.toggle_git_blame_inline_internal(false, window, cx);
19649            }
19650
19651            let minimap_settings = EditorSettings::get_global(cx).minimap;
19652            if self.minimap_visibility != MinimapVisibility::Disabled {
19653                if self.minimap_visibility.settings_visibility()
19654                    != minimap_settings.minimap_enabled()
19655                {
19656                    self.set_minimap_visibility(
19657                        MinimapVisibility::for_mode(self.mode(), cx),
19658                        window,
19659                        cx,
19660                    );
19661                } else if let Some(minimap_entity) = self.minimap.as_ref() {
19662                    minimap_entity.update(cx, |minimap_editor, cx| {
19663                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
19664                    })
19665                }
19666            }
19667        }
19668
19669        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
19670            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
19671        }) {
19672            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
19673                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
19674            }
19675            self.refresh_colors(None, None, window, cx);
19676        }
19677
19678        cx.notify();
19679    }
19680
19681    pub fn set_searchable(&mut self, searchable: bool) {
19682        self.searchable = searchable;
19683    }
19684
19685    pub fn searchable(&self) -> bool {
19686        self.searchable
19687    }
19688
19689    fn open_proposed_changes_editor(
19690        &mut self,
19691        _: &OpenProposedChangesEditor,
19692        window: &mut Window,
19693        cx: &mut Context<Self>,
19694    ) {
19695        let Some(workspace) = self.workspace() else {
19696            cx.propagate();
19697            return;
19698        };
19699
19700        let selections = self.selections.all::<usize>(cx);
19701        let multi_buffer = self.buffer.read(cx);
19702        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19703        let mut new_selections_by_buffer = HashMap::default();
19704        for selection in selections {
19705            for (buffer, range, _) in
19706                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
19707            {
19708                let mut range = range.to_point(buffer);
19709                range.start.column = 0;
19710                range.end.column = buffer.line_len(range.end.row);
19711                new_selections_by_buffer
19712                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
19713                    .or_insert(Vec::new())
19714                    .push(range)
19715            }
19716        }
19717
19718        let proposed_changes_buffers = new_selections_by_buffer
19719            .into_iter()
19720            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
19721            .collect::<Vec<_>>();
19722        let proposed_changes_editor = cx.new(|cx| {
19723            ProposedChangesEditor::new(
19724                "Proposed changes",
19725                proposed_changes_buffers,
19726                self.project.clone(),
19727                window,
19728                cx,
19729            )
19730        });
19731
19732        window.defer(cx, move |window, cx| {
19733            workspace.update(cx, |workspace, cx| {
19734                workspace.active_pane().update(cx, |pane, cx| {
19735                    pane.add_item(
19736                        Box::new(proposed_changes_editor),
19737                        true,
19738                        true,
19739                        None,
19740                        window,
19741                        cx,
19742                    );
19743                });
19744            });
19745        });
19746    }
19747
19748    pub fn open_excerpts_in_split(
19749        &mut self,
19750        _: &OpenExcerptsSplit,
19751        window: &mut Window,
19752        cx: &mut Context<Self>,
19753    ) {
19754        self.open_excerpts_common(None, true, window, cx)
19755    }
19756
19757    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
19758        self.open_excerpts_common(None, false, window, cx)
19759    }
19760
19761    fn open_excerpts_common(
19762        &mut self,
19763        jump_data: Option<JumpData>,
19764        split: bool,
19765        window: &mut Window,
19766        cx: &mut Context<Self>,
19767    ) {
19768        let Some(workspace) = self.workspace() else {
19769            cx.propagate();
19770            return;
19771        };
19772
19773        if self.buffer.read(cx).is_singleton() {
19774            cx.propagate();
19775            return;
19776        }
19777
19778        let mut new_selections_by_buffer = HashMap::default();
19779        match &jump_data {
19780            Some(JumpData::MultiBufferPoint {
19781                excerpt_id,
19782                position,
19783                anchor,
19784                line_offset_from_top,
19785            }) => {
19786                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19787                if let Some(buffer) = multi_buffer_snapshot
19788                    .buffer_id_for_excerpt(*excerpt_id)
19789                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
19790                {
19791                    let buffer_snapshot = buffer.read(cx).snapshot();
19792                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
19793                        language::ToPoint::to_point(anchor, &buffer_snapshot)
19794                    } else {
19795                        buffer_snapshot.clip_point(*position, Bias::Left)
19796                    };
19797                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
19798                    new_selections_by_buffer.insert(
19799                        buffer,
19800                        (
19801                            vec![jump_to_offset..jump_to_offset],
19802                            Some(*line_offset_from_top),
19803                        ),
19804                    );
19805                }
19806            }
19807            Some(JumpData::MultiBufferRow {
19808                row,
19809                line_offset_from_top,
19810            }) => {
19811                let point = MultiBufferPoint::new(row.0, 0);
19812                if let Some((buffer, buffer_point, _)) =
19813                    self.buffer.read(cx).point_to_buffer_point(point, cx)
19814                {
19815                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
19816                    new_selections_by_buffer
19817                        .entry(buffer)
19818                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
19819                        .0
19820                        .push(buffer_offset..buffer_offset)
19821                }
19822            }
19823            None => {
19824                let selections = self.selections.all::<usize>(cx);
19825                let multi_buffer = self.buffer.read(cx);
19826                for selection in selections {
19827                    for (snapshot, range, _, anchor) in multi_buffer
19828                        .snapshot(cx)
19829                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
19830                    {
19831                        if let Some(anchor) = anchor {
19832                            // selection is in a deleted hunk
19833                            let Some(buffer_id) = anchor.buffer_id else {
19834                                continue;
19835                            };
19836                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
19837                                continue;
19838                            };
19839                            let offset = text::ToOffset::to_offset(
19840                                &anchor.text_anchor,
19841                                &buffer_handle.read(cx).snapshot(),
19842                            );
19843                            let range = offset..offset;
19844                            new_selections_by_buffer
19845                                .entry(buffer_handle)
19846                                .or_insert((Vec::new(), None))
19847                                .0
19848                                .push(range)
19849                        } else {
19850                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
19851                            else {
19852                                continue;
19853                            };
19854                            new_selections_by_buffer
19855                                .entry(buffer_handle)
19856                                .or_insert((Vec::new(), None))
19857                                .0
19858                                .push(range)
19859                        }
19860                    }
19861                }
19862            }
19863        }
19864
19865        new_selections_by_buffer
19866            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19867
19868        if new_selections_by_buffer.is_empty() {
19869            return;
19870        }
19871
19872        // We defer the pane interaction because we ourselves are a workspace item
19873        // and activating a new item causes the pane to call a method on us reentrantly,
19874        // which panics if we're on the stack.
19875        window.defer(cx, move |window, cx| {
19876            workspace.update(cx, |workspace, cx| {
19877                let pane = if split {
19878                    workspace.adjacent_pane(window, cx)
19879                } else {
19880                    workspace.active_pane().clone()
19881                };
19882
19883                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19884                    let editor = buffer
19885                        .read(cx)
19886                        .file()
19887                        .is_none()
19888                        .then(|| {
19889                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19890                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19891                            // Instead, we try to activate the existing editor in the pane first.
19892                            let (editor, pane_item_index) =
19893                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19894                                    let editor = item.downcast::<Editor>()?;
19895                                    let singleton_buffer =
19896                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19897                                    if singleton_buffer == buffer {
19898                                        Some((editor, i))
19899                                    } else {
19900                                        None
19901                                    }
19902                                })?;
19903                            pane.update(cx, |pane, cx| {
19904                                pane.activate_item(pane_item_index, true, true, window, cx)
19905                            });
19906                            Some(editor)
19907                        })
19908                        .flatten()
19909                        .unwrap_or_else(|| {
19910                            workspace.open_project_item::<Self>(
19911                                pane.clone(),
19912                                buffer,
19913                                true,
19914                                true,
19915                                window,
19916                                cx,
19917                            )
19918                        });
19919
19920                    editor.update(cx, |editor, cx| {
19921                        let autoscroll = match scroll_offset {
19922                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19923                            None => Autoscroll::newest(),
19924                        };
19925                        let nav_history = editor.nav_history.take();
19926                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19927                            s.select_ranges(ranges);
19928                        });
19929                        editor.nav_history = nav_history;
19930                    });
19931                }
19932            })
19933        });
19934    }
19935
19936    // For now, don't allow opening excerpts in buffers that aren't backed by
19937    // regular project files.
19938    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19939        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19940    }
19941
19942    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19943        let snapshot = self.buffer.read(cx).read(cx);
19944        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19945        Some(
19946            ranges
19947                .iter()
19948                .map(move |range| {
19949                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19950                })
19951                .collect(),
19952        )
19953    }
19954
19955    fn selection_replacement_ranges(
19956        &self,
19957        range: Range<OffsetUtf16>,
19958        cx: &mut App,
19959    ) -> Vec<Range<OffsetUtf16>> {
19960        let selections = self.selections.all::<OffsetUtf16>(cx);
19961        let newest_selection = selections
19962            .iter()
19963            .max_by_key(|selection| selection.id)
19964            .unwrap();
19965        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19966        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19967        let snapshot = self.buffer.read(cx).read(cx);
19968        selections
19969            .into_iter()
19970            .map(|mut selection| {
19971                selection.start.0 =
19972                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19973                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19974                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19975                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19976            })
19977            .collect()
19978    }
19979
19980    fn report_editor_event(
19981        &self,
19982        event_type: &'static str,
19983        file_extension: Option<String>,
19984        cx: &App,
19985    ) {
19986        if cfg!(any(test, feature = "test-support")) {
19987            return;
19988        }
19989
19990        let Some(project) = &self.project else { return };
19991
19992        // If None, we are in a file without an extension
19993        let file = self
19994            .buffer
19995            .read(cx)
19996            .as_singleton()
19997            .and_then(|b| b.read(cx).file());
19998        let file_extension = file_extension.or(file
19999            .as_ref()
20000            .and_then(|file| Path::new(file.file_name(cx)).extension())
20001            .and_then(|e| e.to_str())
20002            .map(|a| a.to_string()));
20003
20004        let vim_mode = vim_enabled(cx);
20005
20006        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20007        let copilot_enabled = edit_predictions_provider
20008            == language::language_settings::EditPredictionProvider::Copilot;
20009        let copilot_enabled_for_language = self
20010            .buffer
20011            .read(cx)
20012            .language_settings(cx)
20013            .show_edit_predictions;
20014
20015        let project = project.read(cx);
20016        telemetry::event!(
20017            event_type,
20018            file_extension,
20019            vim_mode,
20020            copilot_enabled,
20021            copilot_enabled_for_language,
20022            edit_predictions_provider,
20023            is_via_ssh = project.is_via_ssh(),
20024        );
20025    }
20026
20027    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20028    /// with each line being an array of {text, highlight} objects.
20029    fn copy_highlight_json(
20030        &mut self,
20031        _: &CopyHighlightJson,
20032        window: &mut Window,
20033        cx: &mut Context<Self>,
20034    ) {
20035        #[derive(Serialize)]
20036        struct Chunk<'a> {
20037            text: String,
20038            highlight: Option<&'a str>,
20039        }
20040
20041        let snapshot = self.buffer.read(cx).snapshot(cx);
20042        let range = self
20043            .selected_text_range(false, window, cx)
20044            .and_then(|selection| {
20045                if selection.range.is_empty() {
20046                    None
20047                } else {
20048                    Some(selection.range)
20049                }
20050            })
20051            .unwrap_or_else(|| 0..snapshot.len());
20052
20053        let chunks = snapshot.chunks(range, true);
20054        let mut lines = Vec::new();
20055        let mut line: VecDeque<Chunk> = VecDeque::new();
20056
20057        let Some(style) = self.style.as_ref() else {
20058            return;
20059        };
20060
20061        for chunk in chunks {
20062            let highlight = chunk
20063                .syntax_highlight_id
20064                .and_then(|id| id.name(&style.syntax));
20065            let mut chunk_lines = chunk.text.split('\n').peekable();
20066            while let Some(text) = chunk_lines.next() {
20067                let mut merged_with_last_token = false;
20068                if let Some(last_token) = line.back_mut() {
20069                    if last_token.highlight == highlight {
20070                        last_token.text.push_str(text);
20071                        merged_with_last_token = true;
20072                    }
20073                }
20074
20075                if !merged_with_last_token {
20076                    line.push_back(Chunk {
20077                        text: text.into(),
20078                        highlight,
20079                    });
20080                }
20081
20082                if chunk_lines.peek().is_some() {
20083                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20084                        line.pop_front();
20085                    }
20086                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20087                        line.pop_back();
20088                    }
20089
20090                    lines.push(mem::take(&mut line));
20091                }
20092            }
20093        }
20094
20095        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20096            return;
20097        };
20098        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20099    }
20100
20101    pub fn open_context_menu(
20102        &mut self,
20103        _: &OpenContextMenu,
20104        window: &mut Window,
20105        cx: &mut Context<Self>,
20106    ) {
20107        self.request_autoscroll(Autoscroll::newest(), cx);
20108        let position = self.selections.newest_display(cx).start;
20109        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20110    }
20111
20112    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20113        &self.inlay_hint_cache
20114    }
20115
20116    pub fn replay_insert_event(
20117        &mut self,
20118        text: &str,
20119        relative_utf16_range: Option<Range<isize>>,
20120        window: &mut Window,
20121        cx: &mut Context<Self>,
20122    ) {
20123        if !self.input_enabled {
20124            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20125            return;
20126        }
20127        if let Some(relative_utf16_range) = relative_utf16_range {
20128            let selections = self.selections.all::<OffsetUtf16>(cx);
20129            self.change_selections(None, window, cx, |s| {
20130                let new_ranges = selections.into_iter().map(|range| {
20131                    let start = OffsetUtf16(
20132                        range
20133                            .head()
20134                            .0
20135                            .saturating_add_signed(relative_utf16_range.start),
20136                    );
20137                    let end = OffsetUtf16(
20138                        range
20139                            .head()
20140                            .0
20141                            .saturating_add_signed(relative_utf16_range.end),
20142                    );
20143                    start..end
20144                });
20145                s.select_ranges(new_ranges);
20146            });
20147        }
20148
20149        self.handle_input(text, window, cx);
20150    }
20151
20152    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20153        let Some(provider) = self.semantics_provider.as_ref() else {
20154            return false;
20155        };
20156
20157        let mut supports = false;
20158        self.buffer().update(cx, |this, cx| {
20159            this.for_each_buffer(|buffer| {
20160                supports |= provider.supports_inlay_hints(buffer, cx);
20161            });
20162        });
20163
20164        supports
20165    }
20166
20167    pub fn is_focused(&self, window: &Window) -> bool {
20168        self.focus_handle.is_focused(window)
20169    }
20170
20171    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20172        cx.emit(EditorEvent::Focused);
20173
20174        if let Some(descendant) = self
20175            .last_focused_descendant
20176            .take()
20177            .and_then(|descendant| descendant.upgrade())
20178        {
20179            window.focus(&descendant);
20180        } else {
20181            if let Some(blame) = self.blame.as_ref() {
20182                blame.update(cx, GitBlame::focus)
20183            }
20184
20185            self.blink_manager.update(cx, BlinkManager::enable);
20186            self.show_cursor_names(window, cx);
20187            self.buffer.update(cx, |buffer, cx| {
20188                buffer.finalize_last_transaction(cx);
20189                if self.leader_id.is_none() {
20190                    buffer.set_active_selections(
20191                        &self.selections.disjoint_anchors(),
20192                        self.selections.line_mode,
20193                        self.cursor_shape,
20194                        cx,
20195                    );
20196                }
20197            });
20198        }
20199    }
20200
20201    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20202        cx.emit(EditorEvent::FocusedIn)
20203    }
20204
20205    fn handle_focus_out(
20206        &mut self,
20207        event: FocusOutEvent,
20208        _window: &mut Window,
20209        cx: &mut Context<Self>,
20210    ) {
20211        if event.blurred != self.focus_handle {
20212            self.last_focused_descendant = Some(event.blurred);
20213        }
20214        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20215    }
20216
20217    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20218        self.blink_manager.update(cx, BlinkManager::disable);
20219        self.buffer
20220            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20221
20222        if let Some(blame) = self.blame.as_ref() {
20223            blame.update(cx, GitBlame::blur)
20224        }
20225        if !self.hover_state.focused(window, cx) {
20226            hide_hover(self, cx);
20227        }
20228        if !self
20229            .context_menu
20230            .borrow()
20231            .as_ref()
20232            .is_some_and(|context_menu| context_menu.focused(window, cx))
20233        {
20234            self.hide_context_menu(window, cx);
20235        }
20236        self.discard_inline_completion(false, cx);
20237        cx.emit(EditorEvent::Blurred);
20238        cx.notify();
20239    }
20240
20241    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20242        let mut pending: String = window
20243            .pending_input_keystrokes()
20244            .into_iter()
20245            .flatten()
20246            .filter_map(|keystroke| {
20247                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20248                    keystroke.key_char.clone()
20249                } else {
20250                    None
20251                }
20252            })
20253            .collect();
20254
20255        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20256            pending = "".to_string();
20257        }
20258
20259        let existing_pending = self
20260            .text_highlights::<PendingInput>(cx)
20261            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20262        if existing_pending.is_none() && pending.is_empty() {
20263            return;
20264        }
20265        let transaction =
20266            self.transact(window, cx, |this, window, cx| {
20267                let selections = this.selections.all::<usize>(cx);
20268                let edits = selections
20269                    .iter()
20270                    .map(|selection| (selection.end..selection.end, pending.clone()));
20271                this.edit(edits, cx);
20272                this.change_selections(None, window, cx, |s| {
20273                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20274                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20275                    }));
20276                });
20277                if let Some(existing_ranges) = existing_pending {
20278                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20279                    this.edit(edits, cx);
20280                }
20281            });
20282
20283        let snapshot = self.snapshot(window, cx);
20284        let ranges = self
20285            .selections
20286            .all::<usize>(cx)
20287            .into_iter()
20288            .map(|selection| {
20289                snapshot.buffer_snapshot.anchor_after(selection.end)
20290                    ..snapshot
20291                        .buffer_snapshot
20292                        .anchor_before(selection.end + pending.len())
20293            })
20294            .collect();
20295
20296        if pending.is_empty() {
20297            self.clear_highlights::<PendingInput>(cx);
20298        } else {
20299            self.highlight_text::<PendingInput>(
20300                ranges,
20301                HighlightStyle {
20302                    underline: Some(UnderlineStyle {
20303                        thickness: px(1.),
20304                        color: None,
20305                        wavy: false,
20306                    }),
20307                    ..Default::default()
20308                },
20309                cx,
20310            );
20311        }
20312
20313        self.ime_transaction = self.ime_transaction.or(transaction);
20314        if let Some(transaction) = self.ime_transaction {
20315            self.buffer.update(cx, |buffer, cx| {
20316                buffer.group_until_transaction(transaction, cx);
20317            });
20318        }
20319
20320        if self.text_highlights::<PendingInput>(cx).is_none() {
20321            self.ime_transaction.take();
20322        }
20323    }
20324
20325    pub fn register_action_renderer(
20326        &mut self,
20327        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20328    ) -> Subscription {
20329        let id = self.next_editor_action_id.post_inc();
20330        self.editor_actions
20331            .borrow_mut()
20332            .insert(id, Box::new(listener));
20333
20334        let editor_actions = self.editor_actions.clone();
20335        Subscription::new(move || {
20336            editor_actions.borrow_mut().remove(&id);
20337        })
20338    }
20339
20340    pub fn register_action<A: Action>(
20341        &mut self,
20342        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20343    ) -> Subscription {
20344        let id = self.next_editor_action_id.post_inc();
20345        let listener = Arc::new(listener);
20346        self.editor_actions.borrow_mut().insert(
20347            id,
20348            Box::new(move |_, window, _| {
20349                let listener = listener.clone();
20350                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20351                    let action = action.downcast_ref().unwrap();
20352                    if phase == DispatchPhase::Bubble {
20353                        listener(action, window, cx)
20354                    }
20355                })
20356            }),
20357        );
20358
20359        let editor_actions = self.editor_actions.clone();
20360        Subscription::new(move || {
20361            editor_actions.borrow_mut().remove(&id);
20362        })
20363    }
20364
20365    pub fn file_header_size(&self) -> u32 {
20366        FILE_HEADER_HEIGHT
20367    }
20368
20369    pub fn restore(
20370        &mut self,
20371        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
20372        window: &mut Window,
20373        cx: &mut Context<Self>,
20374    ) {
20375        let workspace = self.workspace();
20376        let project = self.project.as_ref();
20377        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
20378            let mut tasks = Vec::new();
20379            for (buffer_id, changes) in revert_changes {
20380                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
20381                    buffer.update(cx, |buffer, cx| {
20382                        buffer.edit(
20383                            changes
20384                                .into_iter()
20385                                .map(|(range, text)| (range, text.to_string())),
20386                            None,
20387                            cx,
20388                        );
20389                    });
20390
20391                    if let Some(project) =
20392                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
20393                    {
20394                        project.update(cx, |project, cx| {
20395                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
20396                        })
20397                    }
20398                }
20399            }
20400            tasks
20401        });
20402        cx.spawn_in(window, async move |_, cx| {
20403            for (buffer, task) in save_tasks {
20404                let result = task.await;
20405                if result.is_err() {
20406                    let Some(path) = buffer
20407                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
20408                        .ok()
20409                    else {
20410                        continue;
20411                    };
20412                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
20413                        let Some(task) = cx
20414                            .update_window_entity(&workspace, |workspace, window, cx| {
20415                                workspace
20416                                    .open_path_preview(path, None, false, false, false, window, cx)
20417                            })
20418                            .ok()
20419                        else {
20420                            continue;
20421                        };
20422                        task.await.log_err();
20423                    }
20424                }
20425            }
20426        })
20427        .detach();
20428        self.change_selections(None, window, cx, |selections| selections.refresh());
20429    }
20430
20431    pub fn to_pixel_point(
20432        &self,
20433        source: multi_buffer::Anchor,
20434        editor_snapshot: &EditorSnapshot,
20435        window: &mut Window,
20436    ) -> Option<gpui::Point<Pixels>> {
20437        let source_point = source.to_display_point(editor_snapshot);
20438        self.display_to_pixel_point(source_point, editor_snapshot, window)
20439    }
20440
20441    pub fn display_to_pixel_point(
20442        &self,
20443        source: DisplayPoint,
20444        editor_snapshot: &EditorSnapshot,
20445        window: &mut Window,
20446    ) -> Option<gpui::Point<Pixels>> {
20447        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
20448        let text_layout_details = self.text_layout_details(window);
20449        let scroll_top = text_layout_details
20450            .scroll_anchor
20451            .scroll_position(editor_snapshot)
20452            .y;
20453
20454        if source.row().as_f32() < scroll_top.floor() {
20455            return None;
20456        }
20457        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
20458        let source_y = line_height * (source.row().as_f32() - scroll_top);
20459        Some(gpui::Point::new(source_x, source_y))
20460    }
20461
20462    pub fn has_visible_completions_menu(&self) -> bool {
20463        !self.edit_prediction_preview_is_active()
20464            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
20465                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
20466            })
20467    }
20468
20469    pub fn register_addon<T: Addon>(&mut self, instance: T) {
20470        if self.mode.is_minimap() {
20471            return;
20472        }
20473        self.addons
20474            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
20475    }
20476
20477    pub fn unregister_addon<T: Addon>(&mut self) {
20478        self.addons.remove(&std::any::TypeId::of::<T>());
20479    }
20480
20481    pub fn addon<T: Addon>(&self) -> Option<&T> {
20482        let type_id = std::any::TypeId::of::<T>();
20483        self.addons
20484            .get(&type_id)
20485            .and_then(|item| item.to_any().downcast_ref::<T>())
20486    }
20487
20488    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
20489        let type_id = std::any::TypeId::of::<T>();
20490        self.addons
20491            .get_mut(&type_id)
20492            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
20493    }
20494
20495    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
20496        let text_layout_details = self.text_layout_details(window);
20497        let style = &text_layout_details.editor_style;
20498        let font_id = window.text_system().resolve_font(&style.text.font());
20499        let font_size = style.text.font_size.to_pixels(window.rem_size());
20500        let line_height = style.text.line_height_in_pixels(window.rem_size());
20501        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
20502
20503        gpui::Size::new(em_width, line_height)
20504    }
20505
20506    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
20507        self.load_diff_task.clone()
20508    }
20509
20510    fn read_metadata_from_db(
20511        &mut self,
20512        item_id: u64,
20513        workspace_id: WorkspaceId,
20514        window: &mut Window,
20515        cx: &mut Context<Editor>,
20516    ) {
20517        if self.is_singleton(cx)
20518            && !self.mode.is_minimap()
20519            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
20520        {
20521            let buffer_snapshot = OnceCell::new();
20522
20523            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
20524                if !folds.is_empty() {
20525                    let snapshot =
20526                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20527                    self.fold_ranges(
20528                        folds
20529                            .into_iter()
20530                            .map(|(start, end)| {
20531                                snapshot.clip_offset(start, Bias::Left)
20532                                    ..snapshot.clip_offset(end, Bias::Right)
20533                            })
20534                            .collect(),
20535                        false,
20536                        window,
20537                        cx,
20538                    );
20539                }
20540            }
20541
20542            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
20543                if !selections.is_empty() {
20544                    let snapshot =
20545                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
20546                    // skip adding the initial selection to selection history
20547                    self.selection_history.mode = SelectionHistoryMode::Skipping;
20548                    self.change_selections(None, window, cx, |s| {
20549                        s.select_ranges(selections.into_iter().map(|(start, end)| {
20550                            snapshot.clip_offset(start, Bias::Left)
20551                                ..snapshot.clip_offset(end, Bias::Right)
20552                        }));
20553                    });
20554                    self.selection_history.mode = SelectionHistoryMode::Normal;
20555                }
20556            };
20557        }
20558
20559        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
20560    }
20561
20562    fn update_lsp_data(
20563        &mut self,
20564        for_server_id: Option<LanguageServerId>,
20565        for_buffer: Option<BufferId>,
20566        window: &mut Window,
20567        cx: &mut Context<'_, Self>,
20568    ) {
20569        self.pull_diagnostics(for_buffer, window, cx);
20570        self.refresh_colors(for_server_id, for_buffer, window, cx);
20571    }
20572}
20573
20574fn vim_enabled(cx: &App) -> bool {
20575    cx.global::<SettingsStore>()
20576        .raw_user_settings()
20577        .get("vim_mode")
20578        == Some(&serde_json::Value::Bool(true))
20579}
20580
20581fn process_completion_for_edit(
20582    completion: &Completion,
20583    intent: CompletionIntent,
20584    buffer: &Entity<Buffer>,
20585    cursor_position: &text::Anchor,
20586    cx: &mut Context<Editor>,
20587) -> CompletionEdit {
20588    let buffer = buffer.read(cx);
20589    let buffer_snapshot = buffer.snapshot();
20590    let (snippet, new_text) = if completion.is_snippet() {
20591        // Workaround for typescript language server issues so that methods don't expand within
20592        // strings and functions with type expressions. The previous point is used because the query
20593        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
20594        let mut snippet_source = completion.new_text.clone();
20595        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
20596        previous_point.column = previous_point.column.saturating_sub(1);
20597        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
20598            if scope.prefers_label_for_snippet_in_completion() {
20599                if let Some(label) = completion.label() {
20600                    if matches!(
20601                        completion.kind(),
20602                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
20603                    ) {
20604                        snippet_source = label;
20605                    }
20606                }
20607            }
20608        }
20609        match Snippet::parse(&snippet_source).log_err() {
20610            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
20611            None => (None, completion.new_text.clone()),
20612        }
20613    } else {
20614        (None, completion.new_text.clone())
20615    };
20616
20617    let mut range_to_replace = {
20618        let replace_range = &completion.replace_range;
20619        if let CompletionSource::Lsp {
20620            insert_range: Some(insert_range),
20621            ..
20622        } = &completion.source
20623        {
20624            debug_assert_eq!(
20625                insert_range.start, replace_range.start,
20626                "insert_range and replace_range should start at the same position"
20627            );
20628            debug_assert!(
20629                insert_range
20630                    .start
20631                    .cmp(&cursor_position, &buffer_snapshot)
20632                    .is_le(),
20633                "insert_range should start before or at cursor position"
20634            );
20635            debug_assert!(
20636                replace_range
20637                    .start
20638                    .cmp(&cursor_position, &buffer_snapshot)
20639                    .is_le(),
20640                "replace_range should start before or at cursor position"
20641            );
20642            debug_assert!(
20643                insert_range
20644                    .end
20645                    .cmp(&cursor_position, &buffer_snapshot)
20646                    .is_le(),
20647                "insert_range should end before or at cursor position"
20648            );
20649
20650            let should_replace = match intent {
20651                CompletionIntent::CompleteWithInsert => false,
20652                CompletionIntent::CompleteWithReplace => true,
20653                CompletionIntent::Complete | CompletionIntent::Compose => {
20654                    let insert_mode =
20655                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
20656                            .completions
20657                            .lsp_insert_mode;
20658                    match insert_mode {
20659                        LspInsertMode::Insert => false,
20660                        LspInsertMode::Replace => true,
20661                        LspInsertMode::ReplaceSubsequence => {
20662                            let mut text_to_replace = buffer.chars_for_range(
20663                                buffer.anchor_before(replace_range.start)
20664                                    ..buffer.anchor_after(replace_range.end),
20665                            );
20666                            let mut current_needle = text_to_replace.next();
20667                            for haystack_ch in completion.label.text.chars() {
20668                                if let Some(needle_ch) = current_needle {
20669                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
20670                                        current_needle = text_to_replace.next();
20671                                    }
20672                                }
20673                            }
20674                            current_needle.is_none()
20675                        }
20676                        LspInsertMode::ReplaceSuffix => {
20677                            if replace_range
20678                                .end
20679                                .cmp(&cursor_position, &buffer_snapshot)
20680                                .is_gt()
20681                            {
20682                                let range_after_cursor = *cursor_position..replace_range.end;
20683                                let text_after_cursor = buffer
20684                                    .text_for_range(
20685                                        buffer.anchor_before(range_after_cursor.start)
20686                                            ..buffer.anchor_after(range_after_cursor.end),
20687                                    )
20688                                    .collect::<String>()
20689                                    .to_ascii_lowercase();
20690                                completion
20691                                    .label
20692                                    .text
20693                                    .to_ascii_lowercase()
20694                                    .ends_with(&text_after_cursor)
20695                            } else {
20696                                true
20697                            }
20698                        }
20699                    }
20700                }
20701            };
20702
20703            if should_replace {
20704                replace_range.clone()
20705            } else {
20706                insert_range.clone()
20707            }
20708        } else {
20709            replace_range.clone()
20710        }
20711    };
20712
20713    if range_to_replace
20714        .end
20715        .cmp(&cursor_position, &buffer_snapshot)
20716        .is_lt()
20717    {
20718        range_to_replace.end = *cursor_position;
20719    }
20720
20721    CompletionEdit {
20722        new_text,
20723        replace_range: range_to_replace.to_offset(&buffer),
20724        snippet,
20725    }
20726}
20727
20728struct CompletionEdit {
20729    new_text: String,
20730    replace_range: Range<usize>,
20731    snippet: Option<Snippet>,
20732}
20733
20734fn insert_extra_newline_brackets(
20735    buffer: &MultiBufferSnapshot,
20736    range: Range<usize>,
20737    language: &language::LanguageScope,
20738) -> bool {
20739    let leading_whitespace_len = buffer
20740        .reversed_chars_at(range.start)
20741        .take_while(|c| c.is_whitespace() && *c != '\n')
20742        .map(|c| c.len_utf8())
20743        .sum::<usize>();
20744    let trailing_whitespace_len = buffer
20745        .chars_at(range.end)
20746        .take_while(|c| c.is_whitespace() && *c != '\n')
20747        .map(|c| c.len_utf8())
20748        .sum::<usize>();
20749    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
20750
20751    language.brackets().any(|(pair, enabled)| {
20752        let pair_start = pair.start.trim_end();
20753        let pair_end = pair.end.trim_start();
20754
20755        enabled
20756            && pair.newline
20757            && buffer.contains_str_at(range.end, pair_end)
20758            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
20759    })
20760}
20761
20762fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
20763    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
20764        [(buffer, range, _)] => (*buffer, range.clone()),
20765        _ => return false,
20766    };
20767    let pair = {
20768        let mut result: Option<BracketMatch> = None;
20769
20770        for pair in buffer
20771            .all_bracket_ranges(range.clone())
20772            .filter(move |pair| {
20773                pair.open_range.start <= range.start && pair.close_range.end >= range.end
20774            })
20775        {
20776            let len = pair.close_range.end - pair.open_range.start;
20777
20778            if let Some(existing) = &result {
20779                let existing_len = existing.close_range.end - existing.open_range.start;
20780                if len > existing_len {
20781                    continue;
20782                }
20783            }
20784
20785            result = Some(pair);
20786        }
20787
20788        result
20789    };
20790    let Some(pair) = pair else {
20791        return false;
20792    };
20793    pair.newline_only
20794        && buffer
20795            .chars_for_range(pair.open_range.end..range.start)
20796            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
20797            .all(|c| c.is_whitespace() && c != '\n')
20798}
20799
20800fn update_uncommitted_diff_for_buffer(
20801    editor: Entity<Editor>,
20802    project: &Entity<Project>,
20803    buffers: impl IntoIterator<Item = Entity<Buffer>>,
20804    buffer: Entity<MultiBuffer>,
20805    cx: &mut App,
20806) -> Task<()> {
20807    let mut tasks = Vec::new();
20808    project.update(cx, |project, cx| {
20809        for buffer in buffers {
20810            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
20811                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
20812            }
20813        }
20814    });
20815    cx.spawn(async move |cx| {
20816        let diffs = future::join_all(tasks).await;
20817        if editor
20818            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
20819            .unwrap_or(false)
20820        {
20821            return;
20822        }
20823
20824        buffer
20825            .update(cx, |buffer, cx| {
20826                for diff in diffs.into_iter().flatten() {
20827                    buffer.add_diff(diff, cx);
20828                }
20829            })
20830            .ok();
20831    })
20832}
20833
20834fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
20835    let tab_size = tab_size.get() as usize;
20836    let mut width = offset;
20837
20838    for ch in text.chars() {
20839        width += if ch == '\t' {
20840            tab_size - (width % tab_size)
20841        } else {
20842            1
20843        };
20844    }
20845
20846    width - offset
20847}
20848
20849#[cfg(test)]
20850mod tests {
20851    use super::*;
20852
20853    #[test]
20854    fn test_string_size_with_expanded_tabs() {
20855        let nz = |val| NonZeroU32::new(val).unwrap();
20856        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
20857        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
20858        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
20859        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
20860        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
20861        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
20862        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
20863        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
20864    }
20865}
20866
20867/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
20868struct WordBreakingTokenizer<'a> {
20869    input: &'a str,
20870}
20871
20872impl<'a> WordBreakingTokenizer<'a> {
20873    fn new(input: &'a str) -> Self {
20874        Self { input }
20875    }
20876}
20877
20878fn is_char_ideographic(ch: char) -> bool {
20879    use unicode_script::Script::*;
20880    use unicode_script::UnicodeScript;
20881    matches!(ch.script(), Han | Tangut | Yi)
20882}
20883
20884fn is_grapheme_ideographic(text: &str) -> bool {
20885    text.chars().any(is_char_ideographic)
20886}
20887
20888fn is_grapheme_whitespace(text: &str) -> bool {
20889    text.chars().any(|x| x.is_whitespace())
20890}
20891
20892fn should_stay_with_preceding_ideograph(text: &str) -> bool {
20893    text.chars().next().map_or(false, |ch| {
20894        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
20895    })
20896}
20897
20898#[derive(PartialEq, Eq, Debug, Clone, Copy)]
20899enum WordBreakToken<'a> {
20900    Word { token: &'a str, grapheme_len: usize },
20901    InlineWhitespace { token: &'a str, grapheme_len: usize },
20902    Newline,
20903}
20904
20905impl<'a> Iterator for WordBreakingTokenizer<'a> {
20906    /// Yields a span, the count of graphemes in the token, and whether it was
20907    /// whitespace. Note that it also breaks at word boundaries.
20908    type Item = WordBreakToken<'a>;
20909
20910    fn next(&mut self) -> Option<Self::Item> {
20911        use unicode_segmentation::UnicodeSegmentation;
20912        if self.input.is_empty() {
20913            return None;
20914        }
20915
20916        let mut iter = self.input.graphemes(true).peekable();
20917        let mut offset = 0;
20918        let mut grapheme_len = 0;
20919        if let Some(first_grapheme) = iter.next() {
20920            let is_newline = first_grapheme == "\n";
20921            let is_whitespace = is_grapheme_whitespace(first_grapheme);
20922            offset += first_grapheme.len();
20923            grapheme_len += 1;
20924            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
20925                if let Some(grapheme) = iter.peek().copied() {
20926                    if should_stay_with_preceding_ideograph(grapheme) {
20927                        offset += grapheme.len();
20928                        grapheme_len += 1;
20929                    }
20930                }
20931            } else {
20932                let mut words = self.input[offset..].split_word_bound_indices().peekable();
20933                let mut next_word_bound = words.peek().copied();
20934                if next_word_bound.map_or(false, |(i, _)| i == 0) {
20935                    next_word_bound = words.next();
20936                }
20937                while let Some(grapheme) = iter.peek().copied() {
20938                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
20939                        break;
20940                    };
20941                    if is_grapheme_whitespace(grapheme) != is_whitespace
20942                        || (grapheme == "\n") != is_newline
20943                    {
20944                        break;
20945                    };
20946                    offset += grapheme.len();
20947                    grapheme_len += 1;
20948                    iter.next();
20949                }
20950            }
20951            let token = &self.input[..offset];
20952            self.input = &self.input[offset..];
20953            if token == "\n" {
20954                Some(WordBreakToken::Newline)
20955            } else if is_whitespace {
20956                Some(WordBreakToken::InlineWhitespace {
20957                    token,
20958                    grapheme_len,
20959                })
20960            } else {
20961                Some(WordBreakToken::Word {
20962                    token,
20963                    grapheme_len,
20964                })
20965            }
20966        } else {
20967            None
20968        }
20969    }
20970}
20971
20972#[test]
20973fn test_word_breaking_tokenizer() {
20974    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20975        ("", &[]),
20976        ("  ", &[whitespace("  ", 2)]),
20977        ("Ʒ", &[word("Ʒ", 1)]),
20978        ("Ǽ", &[word("Ǽ", 1)]),
20979        ("", &[word("", 1)]),
20980        ("⋑⋑", &[word("⋑⋑", 2)]),
20981        (
20982            "原理,进而",
20983            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20984        ),
20985        (
20986            "hello world",
20987            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20988        ),
20989        (
20990            "hello, world",
20991            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20992        ),
20993        (
20994            "  hello world",
20995            &[
20996                whitespace("  ", 2),
20997                word("hello", 5),
20998                whitespace(" ", 1),
20999                word("world", 5),
21000            ],
21001        ),
21002        (
21003            "这是什么 \n 钢笔",
21004            &[
21005                word("", 1),
21006                word("", 1),
21007                word("", 1),
21008                word("", 1),
21009                whitespace(" ", 1),
21010                newline(),
21011                whitespace(" ", 1),
21012                word("", 1),
21013                word("", 1),
21014            ],
21015        ),
21016        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21017    ];
21018
21019    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21020        WordBreakToken::Word {
21021            token,
21022            grapheme_len,
21023        }
21024    }
21025
21026    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21027        WordBreakToken::InlineWhitespace {
21028            token,
21029            grapheme_len,
21030        }
21031    }
21032
21033    fn newline() -> WordBreakToken<'static> {
21034        WordBreakToken::Newline
21035    }
21036
21037    for (input, result) in tests {
21038        assert_eq!(
21039            WordBreakingTokenizer::new(input)
21040                .collect::<Vec<_>>()
21041                .as_slice(),
21042            *result,
21043        );
21044    }
21045}
21046
21047fn wrap_with_prefix(
21048    line_prefix: String,
21049    unwrapped_text: String,
21050    wrap_column: usize,
21051    tab_size: NonZeroU32,
21052    preserve_existing_whitespace: bool,
21053) -> String {
21054    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
21055    let mut wrapped_text = String::new();
21056    let mut current_line = line_prefix.clone();
21057
21058    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21059    let mut current_line_len = line_prefix_len;
21060    let mut in_whitespace = false;
21061    for token in tokenizer {
21062        let have_preceding_whitespace = in_whitespace;
21063        match token {
21064            WordBreakToken::Word {
21065                token,
21066                grapheme_len,
21067            } => {
21068                in_whitespace = false;
21069                if current_line_len + grapheme_len > wrap_column
21070                    && current_line_len != line_prefix_len
21071                {
21072                    wrapped_text.push_str(current_line.trim_end());
21073                    wrapped_text.push('\n');
21074                    current_line.truncate(line_prefix.len());
21075                    current_line_len = line_prefix_len;
21076                }
21077                current_line.push_str(token);
21078                current_line_len += grapheme_len;
21079            }
21080            WordBreakToken::InlineWhitespace {
21081                mut token,
21082                mut grapheme_len,
21083            } => {
21084                in_whitespace = true;
21085                if have_preceding_whitespace && !preserve_existing_whitespace {
21086                    continue;
21087                }
21088                if !preserve_existing_whitespace {
21089                    token = " ";
21090                    grapheme_len = 1;
21091                }
21092                if current_line_len + grapheme_len > wrap_column {
21093                    wrapped_text.push_str(current_line.trim_end());
21094                    wrapped_text.push('\n');
21095                    current_line.truncate(line_prefix.len());
21096                    current_line_len = line_prefix_len;
21097                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
21098                    current_line.push_str(token);
21099                    current_line_len += grapheme_len;
21100                }
21101            }
21102            WordBreakToken::Newline => {
21103                in_whitespace = true;
21104                if preserve_existing_whitespace {
21105                    wrapped_text.push_str(current_line.trim_end());
21106                    wrapped_text.push('\n');
21107                    current_line.truncate(line_prefix.len());
21108                    current_line_len = line_prefix_len;
21109                } else if have_preceding_whitespace {
21110                    continue;
21111                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
21112                {
21113                    wrapped_text.push_str(current_line.trim_end());
21114                    wrapped_text.push('\n');
21115                    current_line.truncate(line_prefix.len());
21116                    current_line_len = line_prefix_len;
21117                } else if current_line_len != line_prefix_len {
21118                    current_line.push(' ');
21119                    current_line_len += 1;
21120                }
21121            }
21122        }
21123    }
21124
21125    if !current_line.is_empty() {
21126        wrapped_text.push_str(&current_line);
21127    }
21128    wrapped_text
21129}
21130
21131#[test]
21132fn test_wrap_with_prefix() {
21133    assert_eq!(
21134        wrap_with_prefix(
21135            "# ".to_string(),
21136            "abcdefg".to_string(),
21137            4,
21138            NonZeroU32::new(4).unwrap(),
21139            false,
21140        ),
21141        "# abcdefg"
21142    );
21143    assert_eq!(
21144        wrap_with_prefix(
21145            "".to_string(),
21146            "\thello world".to_string(),
21147            8,
21148            NonZeroU32::new(4).unwrap(),
21149            false,
21150        ),
21151        "hello\nworld"
21152    );
21153    assert_eq!(
21154        wrap_with_prefix(
21155            "// ".to_string(),
21156            "xx \nyy zz aa bb cc".to_string(),
21157            12,
21158            NonZeroU32::new(4).unwrap(),
21159            false,
21160        ),
21161        "// xx yy zz\n// aa bb cc"
21162    );
21163    assert_eq!(
21164        wrap_with_prefix(
21165            String::new(),
21166            "这是什么 \n 钢笔".to_string(),
21167            3,
21168            NonZeroU32::new(4).unwrap(),
21169            false,
21170        ),
21171        "这是什\n么 钢\n"
21172    );
21173}
21174
21175pub trait CollaborationHub {
21176    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21177    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21178    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21179}
21180
21181impl CollaborationHub for Entity<Project> {
21182    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21183        self.read(cx).collaborators()
21184    }
21185
21186    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21187        self.read(cx).user_store().read(cx).participant_indices()
21188    }
21189
21190    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21191        let this = self.read(cx);
21192        let user_ids = this.collaborators().values().map(|c| c.user_id);
21193        this.user_store().read(cx).participant_names(user_ids, cx)
21194    }
21195}
21196
21197pub trait SemanticsProvider {
21198    fn hover(
21199        &self,
21200        buffer: &Entity<Buffer>,
21201        position: text::Anchor,
21202        cx: &mut App,
21203    ) -> Option<Task<Vec<project::Hover>>>;
21204
21205    fn inline_values(
21206        &self,
21207        buffer_handle: Entity<Buffer>,
21208        range: Range<text::Anchor>,
21209        cx: &mut App,
21210    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21211
21212    fn inlay_hints(
21213        &self,
21214        buffer_handle: Entity<Buffer>,
21215        range: Range<text::Anchor>,
21216        cx: &mut App,
21217    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21218
21219    fn resolve_inlay_hint(
21220        &self,
21221        hint: InlayHint,
21222        buffer_handle: Entity<Buffer>,
21223        server_id: LanguageServerId,
21224        cx: &mut App,
21225    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21226
21227    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21228
21229    fn document_highlights(
21230        &self,
21231        buffer: &Entity<Buffer>,
21232        position: text::Anchor,
21233        cx: &mut App,
21234    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21235
21236    fn definitions(
21237        &self,
21238        buffer: &Entity<Buffer>,
21239        position: text::Anchor,
21240        kind: GotoDefinitionKind,
21241        cx: &mut App,
21242    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21243
21244    fn range_for_rename(
21245        &self,
21246        buffer: &Entity<Buffer>,
21247        position: text::Anchor,
21248        cx: &mut App,
21249    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21250
21251    fn perform_rename(
21252        &self,
21253        buffer: &Entity<Buffer>,
21254        position: text::Anchor,
21255        new_name: String,
21256        cx: &mut App,
21257    ) -> Option<Task<Result<ProjectTransaction>>>;
21258}
21259
21260pub trait CompletionProvider {
21261    fn completions(
21262        &self,
21263        excerpt_id: ExcerptId,
21264        buffer: &Entity<Buffer>,
21265        buffer_position: text::Anchor,
21266        trigger: CompletionContext,
21267        window: &mut Window,
21268        cx: &mut Context<Editor>,
21269    ) -> Task<Result<Vec<CompletionResponse>>>;
21270
21271    fn resolve_completions(
21272        &self,
21273        _buffer: Entity<Buffer>,
21274        _completion_indices: Vec<usize>,
21275        _completions: Rc<RefCell<Box<[Completion]>>>,
21276        _cx: &mut Context<Editor>,
21277    ) -> Task<Result<bool>> {
21278        Task::ready(Ok(false))
21279    }
21280
21281    fn apply_additional_edits_for_completion(
21282        &self,
21283        _buffer: Entity<Buffer>,
21284        _completions: Rc<RefCell<Box<[Completion]>>>,
21285        _completion_index: usize,
21286        _push_to_history: bool,
21287        _cx: &mut Context<Editor>,
21288    ) -> Task<Result<Option<language::Transaction>>> {
21289        Task::ready(Ok(None))
21290    }
21291
21292    fn is_completion_trigger(
21293        &self,
21294        buffer: &Entity<Buffer>,
21295        position: language::Anchor,
21296        text: &str,
21297        trigger_in_words: bool,
21298        menu_is_open: bool,
21299        cx: &mut Context<Editor>,
21300    ) -> bool;
21301
21302    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21303
21304    fn sort_completions(&self) -> bool {
21305        true
21306    }
21307
21308    fn filter_completions(&self) -> bool {
21309        true
21310    }
21311}
21312
21313pub trait CodeActionProvider {
21314    fn id(&self) -> Arc<str>;
21315
21316    fn code_actions(
21317        &self,
21318        buffer: &Entity<Buffer>,
21319        range: Range<text::Anchor>,
21320        window: &mut Window,
21321        cx: &mut App,
21322    ) -> Task<Result<Vec<CodeAction>>>;
21323
21324    fn apply_code_action(
21325        &self,
21326        buffer_handle: Entity<Buffer>,
21327        action: CodeAction,
21328        excerpt_id: ExcerptId,
21329        push_to_history: bool,
21330        window: &mut Window,
21331        cx: &mut App,
21332    ) -> Task<Result<ProjectTransaction>>;
21333}
21334
21335impl CodeActionProvider for Entity<Project> {
21336    fn id(&self) -> Arc<str> {
21337        "project".into()
21338    }
21339
21340    fn code_actions(
21341        &self,
21342        buffer: &Entity<Buffer>,
21343        range: Range<text::Anchor>,
21344        _window: &mut Window,
21345        cx: &mut App,
21346    ) -> Task<Result<Vec<CodeAction>>> {
21347        self.update(cx, |project, cx| {
21348            let code_lens = project.code_lens(buffer, range.clone(), cx);
21349            let code_actions = project.code_actions(buffer, range, None, cx);
21350            cx.background_spawn(async move {
21351                let (code_lens, code_actions) = join(code_lens, code_actions).await;
21352                Ok(code_lens
21353                    .context("code lens fetch")?
21354                    .into_iter()
21355                    .chain(code_actions.context("code action fetch")?)
21356                    .collect())
21357            })
21358        })
21359    }
21360
21361    fn apply_code_action(
21362        &self,
21363        buffer_handle: Entity<Buffer>,
21364        action: CodeAction,
21365        _excerpt_id: ExcerptId,
21366        push_to_history: bool,
21367        _window: &mut Window,
21368        cx: &mut App,
21369    ) -> Task<Result<ProjectTransaction>> {
21370        self.update(cx, |project, cx| {
21371            project.apply_code_action(buffer_handle, action, push_to_history, cx)
21372        })
21373    }
21374}
21375
21376fn snippet_completions(
21377    project: &Project,
21378    buffer: &Entity<Buffer>,
21379    buffer_position: text::Anchor,
21380    cx: &mut App,
21381) -> Task<Result<CompletionResponse>> {
21382    let languages = buffer.read(cx).languages_at(buffer_position);
21383    let snippet_store = project.snippets().read(cx);
21384
21385    let scopes: Vec<_> = languages
21386        .iter()
21387        .filter_map(|language| {
21388            let language_name = language.lsp_id();
21389            let snippets = snippet_store.snippets_for(Some(language_name), cx);
21390
21391            if snippets.is_empty() {
21392                None
21393            } else {
21394                Some((language.default_scope(), snippets))
21395            }
21396        })
21397        .collect();
21398
21399    if scopes.is_empty() {
21400        return Task::ready(Ok(CompletionResponse {
21401            completions: vec![],
21402            is_incomplete: false,
21403        }));
21404    }
21405
21406    let snapshot = buffer.read(cx).text_snapshot();
21407    let chars: String = snapshot
21408        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
21409        .collect();
21410    let executor = cx.background_executor().clone();
21411
21412    cx.background_spawn(async move {
21413        let mut is_incomplete = false;
21414        let mut completions: Vec<Completion> = Vec::new();
21415        for (scope, snippets) in scopes.into_iter() {
21416            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
21417            let mut last_word = chars
21418                .chars()
21419                .take_while(|c| classifier.is_word(*c))
21420                .collect::<String>();
21421            last_word = last_word.chars().rev().collect();
21422
21423            if last_word.is_empty() {
21424                return Ok(CompletionResponse {
21425                    completions: vec![],
21426                    is_incomplete: true,
21427                });
21428            }
21429
21430            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
21431            let to_lsp = |point: &text::Anchor| {
21432                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
21433                point_to_lsp(end)
21434            };
21435            let lsp_end = to_lsp(&buffer_position);
21436
21437            let candidates = snippets
21438                .iter()
21439                .enumerate()
21440                .flat_map(|(ix, snippet)| {
21441                    snippet
21442                        .prefix
21443                        .iter()
21444                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
21445                })
21446                .collect::<Vec<StringMatchCandidate>>();
21447
21448            const MAX_RESULTS: usize = 100;
21449            let mut matches = fuzzy::match_strings(
21450                &candidates,
21451                &last_word,
21452                last_word.chars().any(|c| c.is_uppercase()),
21453                true,
21454                MAX_RESULTS,
21455                &Default::default(),
21456                executor.clone(),
21457            )
21458            .await;
21459
21460            if matches.len() >= MAX_RESULTS {
21461                is_incomplete = true;
21462            }
21463
21464            // Remove all candidates where the query's start does not match the start of any word in the candidate
21465            if let Some(query_start) = last_word.chars().next() {
21466                matches.retain(|string_match| {
21467                    split_words(&string_match.string).any(|word| {
21468                        // Check that the first codepoint of the word as lowercase matches the first
21469                        // codepoint of the query as lowercase
21470                        word.chars()
21471                            .flat_map(|codepoint| codepoint.to_lowercase())
21472                            .zip(query_start.to_lowercase())
21473                            .all(|(word_cp, query_cp)| word_cp == query_cp)
21474                    })
21475                });
21476            }
21477
21478            let matched_strings = matches
21479                .into_iter()
21480                .map(|m| m.string)
21481                .collect::<HashSet<_>>();
21482
21483            completions.extend(snippets.iter().filter_map(|snippet| {
21484                let matching_prefix = snippet
21485                    .prefix
21486                    .iter()
21487                    .find(|prefix| matched_strings.contains(*prefix))?;
21488                let start = as_offset - last_word.len();
21489                let start = snapshot.anchor_before(start);
21490                let range = start..buffer_position;
21491                let lsp_start = to_lsp(&start);
21492                let lsp_range = lsp::Range {
21493                    start: lsp_start,
21494                    end: lsp_end,
21495                };
21496                Some(Completion {
21497                    replace_range: range,
21498                    new_text: snippet.body.clone(),
21499                    source: CompletionSource::Lsp {
21500                        insert_range: None,
21501                        server_id: LanguageServerId(usize::MAX),
21502                        resolved: true,
21503                        lsp_completion: Box::new(lsp::CompletionItem {
21504                            label: snippet.prefix.first().unwrap().clone(),
21505                            kind: Some(CompletionItemKind::SNIPPET),
21506                            label_details: snippet.description.as_ref().map(|description| {
21507                                lsp::CompletionItemLabelDetails {
21508                                    detail: Some(description.clone()),
21509                                    description: None,
21510                                }
21511                            }),
21512                            insert_text_format: Some(InsertTextFormat::SNIPPET),
21513                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
21514                                lsp::InsertReplaceEdit {
21515                                    new_text: snippet.body.clone(),
21516                                    insert: lsp_range,
21517                                    replace: lsp_range,
21518                                },
21519                            )),
21520                            filter_text: Some(snippet.body.clone()),
21521                            sort_text: Some(char::MAX.to_string()),
21522                            ..lsp::CompletionItem::default()
21523                        }),
21524                        lsp_defaults: None,
21525                    },
21526                    label: CodeLabel {
21527                        text: matching_prefix.clone(),
21528                        runs: Vec::new(),
21529                        filter_range: 0..matching_prefix.len(),
21530                    },
21531                    icon_path: None,
21532                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
21533                        single_line: snippet.name.clone().into(),
21534                        plain_text: snippet
21535                            .description
21536                            .clone()
21537                            .map(|description| description.into()),
21538                    }),
21539                    insert_text_mode: None,
21540                    confirm: None,
21541                })
21542            }))
21543        }
21544
21545        Ok(CompletionResponse {
21546            completions,
21547            is_incomplete,
21548        })
21549    })
21550}
21551
21552impl CompletionProvider for Entity<Project> {
21553    fn completions(
21554        &self,
21555        _excerpt_id: ExcerptId,
21556        buffer: &Entity<Buffer>,
21557        buffer_position: text::Anchor,
21558        options: CompletionContext,
21559        _window: &mut Window,
21560        cx: &mut Context<Editor>,
21561    ) -> Task<Result<Vec<CompletionResponse>>> {
21562        self.update(cx, |project, cx| {
21563            let snippets = snippet_completions(project, buffer, buffer_position, cx);
21564            let project_completions = project.completions(buffer, buffer_position, options, cx);
21565            cx.background_spawn(async move {
21566                let mut responses = project_completions.await?;
21567                let snippets = snippets.await?;
21568                if !snippets.completions.is_empty() {
21569                    responses.push(snippets);
21570                }
21571                Ok(responses)
21572            })
21573        })
21574    }
21575
21576    fn resolve_completions(
21577        &self,
21578        buffer: Entity<Buffer>,
21579        completion_indices: Vec<usize>,
21580        completions: Rc<RefCell<Box<[Completion]>>>,
21581        cx: &mut Context<Editor>,
21582    ) -> Task<Result<bool>> {
21583        self.update(cx, |project, cx| {
21584            project.lsp_store().update(cx, |lsp_store, cx| {
21585                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
21586            })
21587        })
21588    }
21589
21590    fn apply_additional_edits_for_completion(
21591        &self,
21592        buffer: Entity<Buffer>,
21593        completions: Rc<RefCell<Box<[Completion]>>>,
21594        completion_index: usize,
21595        push_to_history: bool,
21596        cx: &mut Context<Editor>,
21597    ) -> Task<Result<Option<language::Transaction>>> {
21598        self.update(cx, |project, cx| {
21599            project.lsp_store().update(cx, |lsp_store, cx| {
21600                lsp_store.apply_additional_edits_for_completion(
21601                    buffer,
21602                    completions,
21603                    completion_index,
21604                    push_to_history,
21605                    cx,
21606                )
21607            })
21608        })
21609    }
21610
21611    fn is_completion_trigger(
21612        &self,
21613        buffer: &Entity<Buffer>,
21614        position: language::Anchor,
21615        text: &str,
21616        trigger_in_words: bool,
21617        menu_is_open: bool,
21618        cx: &mut Context<Editor>,
21619    ) -> bool {
21620        let mut chars = text.chars();
21621        let char = if let Some(char) = chars.next() {
21622            char
21623        } else {
21624            return false;
21625        };
21626        if chars.next().is_some() {
21627            return false;
21628        }
21629
21630        let buffer = buffer.read(cx);
21631        let snapshot = buffer.snapshot();
21632        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
21633            return false;
21634        }
21635        let classifier = snapshot.char_classifier_at(position).for_completion(true);
21636        if trigger_in_words && classifier.is_word(char) {
21637            return true;
21638        }
21639
21640        buffer.completion_triggers().contains(text)
21641    }
21642}
21643
21644impl SemanticsProvider for Entity<Project> {
21645    fn hover(
21646        &self,
21647        buffer: &Entity<Buffer>,
21648        position: text::Anchor,
21649        cx: &mut App,
21650    ) -> Option<Task<Vec<project::Hover>>> {
21651        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
21652    }
21653
21654    fn document_highlights(
21655        &self,
21656        buffer: &Entity<Buffer>,
21657        position: text::Anchor,
21658        cx: &mut App,
21659    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
21660        Some(self.update(cx, |project, cx| {
21661            project.document_highlights(buffer, position, cx)
21662        }))
21663    }
21664
21665    fn definitions(
21666        &self,
21667        buffer: &Entity<Buffer>,
21668        position: text::Anchor,
21669        kind: GotoDefinitionKind,
21670        cx: &mut App,
21671    ) -> Option<Task<Result<Vec<LocationLink>>>> {
21672        Some(self.update(cx, |project, cx| match kind {
21673            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
21674            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
21675            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
21676            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
21677        }))
21678    }
21679
21680    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
21681        // TODO: make this work for remote projects
21682        self.update(cx, |project, cx| {
21683            if project
21684                .active_debug_session(cx)
21685                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
21686            {
21687                return true;
21688            }
21689
21690            buffer.update(cx, |buffer, cx| {
21691                project.any_language_server_supports_inlay_hints(buffer, cx)
21692            })
21693        })
21694    }
21695
21696    fn inline_values(
21697        &self,
21698        buffer_handle: Entity<Buffer>,
21699        range: Range<text::Anchor>,
21700        cx: &mut App,
21701    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21702        self.update(cx, |project, cx| {
21703            let (session, active_stack_frame) = project.active_debug_session(cx)?;
21704
21705            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
21706        })
21707    }
21708
21709    fn inlay_hints(
21710        &self,
21711        buffer_handle: Entity<Buffer>,
21712        range: Range<text::Anchor>,
21713        cx: &mut App,
21714    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
21715        Some(self.update(cx, |project, cx| {
21716            project.inlay_hints(buffer_handle, range, cx)
21717        }))
21718    }
21719
21720    fn resolve_inlay_hint(
21721        &self,
21722        hint: InlayHint,
21723        buffer_handle: Entity<Buffer>,
21724        server_id: LanguageServerId,
21725        cx: &mut App,
21726    ) -> Option<Task<anyhow::Result<InlayHint>>> {
21727        Some(self.update(cx, |project, cx| {
21728            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
21729        }))
21730    }
21731
21732    fn range_for_rename(
21733        &self,
21734        buffer: &Entity<Buffer>,
21735        position: text::Anchor,
21736        cx: &mut App,
21737    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
21738        Some(self.update(cx, |project, cx| {
21739            let buffer = buffer.clone();
21740            let task = project.prepare_rename(buffer.clone(), position, cx);
21741            cx.spawn(async move |_, cx| {
21742                Ok(match task.await? {
21743                    PrepareRenameResponse::Success(range) => Some(range),
21744                    PrepareRenameResponse::InvalidPosition => None,
21745                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
21746                        // Fallback on using TreeSitter info to determine identifier range
21747                        buffer.read_with(cx, |buffer, _| {
21748                            let snapshot = buffer.snapshot();
21749                            let (range, kind) = snapshot.surrounding_word(position);
21750                            if kind != Some(CharKind::Word) {
21751                                return None;
21752                            }
21753                            Some(
21754                                snapshot.anchor_before(range.start)
21755                                    ..snapshot.anchor_after(range.end),
21756                            )
21757                        })?
21758                    }
21759                })
21760            })
21761        }))
21762    }
21763
21764    fn perform_rename(
21765        &self,
21766        buffer: &Entity<Buffer>,
21767        position: text::Anchor,
21768        new_name: String,
21769        cx: &mut App,
21770    ) -> Option<Task<Result<ProjectTransaction>>> {
21771        Some(self.update(cx, |project, cx| {
21772            project.perform_rename(buffer.clone(), position, new_name, cx)
21773        }))
21774    }
21775}
21776
21777fn inlay_hint_settings(
21778    location: Anchor,
21779    snapshot: &MultiBufferSnapshot,
21780    cx: &mut Context<Editor>,
21781) -> InlayHintSettings {
21782    let file = snapshot.file_at(location);
21783    let language = snapshot.language_at(location).map(|l| l.name());
21784    language_settings(language, file, cx).inlay_hints
21785}
21786
21787fn consume_contiguous_rows(
21788    contiguous_row_selections: &mut Vec<Selection<Point>>,
21789    selection: &Selection<Point>,
21790    display_map: &DisplaySnapshot,
21791    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
21792) -> (MultiBufferRow, MultiBufferRow) {
21793    contiguous_row_selections.push(selection.clone());
21794    let start_row = MultiBufferRow(selection.start.row);
21795    let mut end_row = ending_row(selection, display_map);
21796
21797    while let Some(next_selection) = selections.peek() {
21798        if next_selection.start.row <= end_row.0 {
21799            end_row = ending_row(next_selection, display_map);
21800            contiguous_row_selections.push(selections.next().unwrap().clone());
21801        } else {
21802            break;
21803        }
21804    }
21805    (start_row, end_row)
21806}
21807
21808fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
21809    if next_selection.end.column > 0 || next_selection.is_empty() {
21810        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
21811    } else {
21812        MultiBufferRow(next_selection.end.row)
21813    }
21814}
21815
21816impl EditorSnapshot {
21817    pub fn remote_selections_in_range<'a>(
21818        &'a self,
21819        range: &'a Range<Anchor>,
21820        collaboration_hub: &dyn CollaborationHub,
21821        cx: &'a App,
21822    ) -> impl 'a + Iterator<Item = RemoteSelection> {
21823        let participant_names = collaboration_hub.user_names(cx);
21824        let participant_indices = collaboration_hub.user_participant_indices(cx);
21825        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
21826        let collaborators_by_replica_id = collaborators_by_peer_id
21827            .values()
21828            .map(|collaborator| (collaborator.replica_id, collaborator))
21829            .collect::<HashMap<_, _>>();
21830        self.buffer_snapshot
21831            .selections_in_range(range, false)
21832            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
21833                if replica_id == AGENT_REPLICA_ID {
21834                    Some(RemoteSelection {
21835                        replica_id,
21836                        selection,
21837                        cursor_shape,
21838                        line_mode,
21839                        collaborator_id: CollaboratorId::Agent,
21840                        user_name: Some("Agent".into()),
21841                        color: cx.theme().players().agent(),
21842                    })
21843                } else {
21844                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
21845                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
21846                    let user_name = participant_names.get(&collaborator.user_id).cloned();
21847                    Some(RemoteSelection {
21848                        replica_id,
21849                        selection,
21850                        cursor_shape,
21851                        line_mode,
21852                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
21853                        user_name,
21854                        color: if let Some(index) = participant_index {
21855                            cx.theme().players().color_for_participant(index.0)
21856                        } else {
21857                            cx.theme().players().absent()
21858                        },
21859                    })
21860                }
21861            })
21862    }
21863
21864    pub fn hunks_for_ranges(
21865        &self,
21866        ranges: impl IntoIterator<Item = Range<Point>>,
21867    ) -> Vec<MultiBufferDiffHunk> {
21868        let mut hunks = Vec::new();
21869        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
21870            HashMap::default();
21871        for query_range in ranges {
21872            let query_rows =
21873                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
21874            for hunk in self.buffer_snapshot.diff_hunks_in_range(
21875                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
21876            ) {
21877                // Include deleted hunks that are adjacent to the query range, because
21878                // otherwise they would be missed.
21879                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
21880                if hunk.status().is_deleted() {
21881                    intersects_range |= hunk.row_range.start == query_rows.end;
21882                    intersects_range |= hunk.row_range.end == query_rows.start;
21883                }
21884                if intersects_range {
21885                    if !processed_buffer_rows
21886                        .entry(hunk.buffer_id)
21887                        .or_default()
21888                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
21889                    {
21890                        continue;
21891                    }
21892                    hunks.push(hunk);
21893                }
21894            }
21895        }
21896
21897        hunks
21898    }
21899
21900    fn display_diff_hunks_for_rows<'a>(
21901        &'a self,
21902        display_rows: Range<DisplayRow>,
21903        folded_buffers: &'a HashSet<BufferId>,
21904    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
21905        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
21906        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
21907
21908        self.buffer_snapshot
21909            .diff_hunks_in_range(buffer_start..buffer_end)
21910            .filter_map(|hunk| {
21911                if folded_buffers.contains(&hunk.buffer_id) {
21912                    return None;
21913                }
21914
21915                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
21916                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
21917
21918                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
21919                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
21920
21921                let display_hunk = if hunk_display_start.column() != 0 {
21922                    DisplayDiffHunk::Folded {
21923                        display_row: hunk_display_start.row(),
21924                    }
21925                } else {
21926                    let mut end_row = hunk_display_end.row();
21927                    if hunk_display_end.column() > 0 {
21928                        end_row.0 += 1;
21929                    }
21930                    let is_created_file = hunk.is_created_file();
21931                    DisplayDiffHunk::Unfolded {
21932                        status: hunk.status(),
21933                        diff_base_byte_range: hunk.diff_base_byte_range,
21934                        display_row_range: hunk_display_start.row()..end_row,
21935                        multi_buffer_range: Anchor::range_in_buffer(
21936                            hunk.excerpt_id,
21937                            hunk.buffer_id,
21938                            hunk.buffer_range,
21939                        ),
21940                        is_created_file,
21941                    }
21942                };
21943
21944                Some(display_hunk)
21945            })
21946    }
21947
21948    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
21949        self.display_snapshot.buffer_snapshot.language_at(position)
21950    }
21951
21952    pub fn is_focused(&self) -> bool {
21953        self.is_focused
21954    }
21955
21956    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
21957        self.placeholder_text.as_ref()
21958    }
21959
21960    pub fn scroll_position(&self) -> gpui::Point<f32> {
21961        self.scroll_anchor.scroll_position(&self.display_snapshot)
21962    }
21963
21964    fn gutter_dimensions(
21965        &self,
21966        font_id: FontId,
21967        font_size: Pixels,
21968        max_line_number_width: Pixels,
21969        cx: &App,
21970    ) -> Option<GutterDimensions> {
21971        if !self.show_gutter {
21972            return None;
21973        }
21974
21975        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
21976        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
21977
21978        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21979            matches!(
21980                ProjectSettings::get_global(cx).git.git_gutter,
21981                Some(GitGutterSetting::TrackedFiles)
21982            )
21983        });
21984        let gutter_settings = EditorSettings::get_global(cx).gutter;
21985        let show_line_numbers = self
21986            .show_line_numbers
21987            .unwrap_or(gutter_settings.line_numbers);
21988        let line_gutter_width = if show_line_numbers {
21989            // Avoid flicker-like gutter resizes when the line number gains another digit by
21990            // only resizing the gutter on files with > 10**min_line_number_digits lines.
21991            let min_width_for_number_on_gutter =
21992                ch_advance * gutter_settings.min_line_number_digits as f32;
21993            max_line_number_width.max(min_width_for_number_on_gutter)
21994        } else {
21995            0.0.into()
21996        };
21997
21998        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21999        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22000
22001        let git_blame_entries_width =
22002            self.git_blame_gutter_max_author_length
22003                .map(|max_author_length| {
22004                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22005                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22006
22007                    /// The number of characters to dedicate to gaps and margins.
22008                    const SPACING_WIDTH: usize = 4;
22009
22010                    let max_char_count = max_author_length.min(renderer.max_author_length())
22011                        + ::git::SHORT_SHA_LENGTH
22012                        + MAX_RELATIVE_TIMESTAMP.len()
22013                        + SPACING_WIDTH;
22014
22015                    ch_advance * max_char_count
22016                });
22017
22018        let is_singleton = self.buffer_snapshot.is_singleton();
22019
22020        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22021        left_padding += if !is_singleton {
22022            ch_width * 4.0
22023        } else if show_runnables || show_breakpoints {
22024            ch_width * 3.0
22025        } else if show_git_gutter && show_line_numbers {
22026            ch_width * 2.0
22027        } else if show_git_gutter || show_line_numbers {
22028            ch_width
22029        } else {
22030            px(0.)
22031        };
22032
22033        let shows_folds = is_singleton && gutter_settings.folds;
22034
22035        let right_padding = if shows_folds && show_line_numbers {
22036            ch_width * 4.0
22037        } else if shows_folds || (!is_singleton && show_line_numbers) {
22038            ch_width * 3.0
22039        } else if show_line_numbers {
22040            ch_width
22041        } else {
22042            px(0.)
22043        };
22044
22045        Some(GutterDimensions {
22046            left_padding,
22047            right_padding,
22048            width: line_gutter_width + left_padding + right_padding,
22049            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22050            git_blame_entries_width,
22051        })
22052    }
22053
22054    pub fn render_crease_toggle(
22055        &self,
22056        buffer_row: MultiBufferRow,
22057        row_contains_cursor: bool,
22058        editor: Entity<Editor>,
22059        window: &mut Window,
22060        cx: &mut App,
22061    ) -> Option<AnyElement> {
22062        let folded = self.is_line_folded(buffer_row);
22063        let mut is_foldable = false;
22064
22065        if let Some(crease) = self
22066            .crease_snapshot
22067            .query_row(buffer_row, &self.buffer_snapshot)
22068        {
22069            is_foldable = true;
22070            match crease {
22071                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22072                    if let Some(render_toggle) = render_toggle {
22073                        let toggle_callback =
22074                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22075                                if folded {
22076                                    editor.update(cx, |editor, cx| {
22077                                        editor.fold_at(buffer_row, window, cx)
22078                                    });
22079                                } else {
22080                                    editor.update(cx, |editor, cx| {
22081                                        editor.unfold_at(buffer_row, window, cx)
22082                                    });
22083                                }
22084                            });
22085                        return Some((render_toggle)(
22086                            buffer_row,
22087                            folded,
22088                            toggle_callback,
22089                            window,
22090                            cx,
22091                        ));
22092                    }
22093                }
22094            }
22095        }
22096
22097        is_foldable |= self.starts_indent(buffer_row);
22098
22099        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22100            Some(
22101                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22102                    .toggle_state(folded)
22103                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22104                        if folded {
22105                            this.unfold_at(buffer_row, window, cx);
22106                        } else {
22107                            this.fold_at(buffer_row, window, cx);
22108                        }
22109                    }))
22110                    .into_any_element(),
22111            )
22112        } else {
22113            None
22114        }
22115    }
22116
22117    pub fn render_crease_trailer(
22118        &self,
22119        buffer_row: MultiBufferRow,
22120        window: &mut Window,
22121        cx: &mut App,
22122    ) -> Option<AnyElement> {
22123        let folded = self.is_line_folded(buffer_row);
22124        if let Crease::Inline { render_trailer, .. } = self
22125            .crease_snapshot
22126            .query_row(buffer_row, &self.buffer_snapshot)?
22127        {
22128            let render_trailer = render_trailer.as_ref()?;
22129            Some(render_trailer(buffer_row, folded, window, cx))
22130        } else {
22131            None
22132        }
22133    }
22134}
22135
22136impl Deref for EditorSnapshot {
22137    type Target = DisplaySnapshot;
22138
22139    fn deref(&self) -> &Self::Target {
22140        &self.display_snapshot
22141    }
22142}
22143
22144#[derive(Clone, Debug, PartialEq, Eq)]
22145pub enum EditorEvent {
22146    InputIgnored {
22147        text: Arc<str>,
22148    },
22149    InputHandled {
22150        utf16_range_to_replace: Option<Range<isize>>,
22151        text: Arc<str>,
22152    },
22153    ExcerptsAdded {
22154        buffer: Entity<Buffer>,
22155        predecessor: ExcerptId,
22156        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22157    },
22158    ExcerptsRemoved {
22159        ids: Vec<ExcerptId>,
22160        removed_buffer_ids: Vec<BufferId>,
22161    },
22162    BufferFoldToggled {
22163        ids: Vec<ExcerptId>,
22164        folded: bool,
22165    },
22166    ExcerptsEdited {
22167        ids: Vec<ExcerptId>,
22168    },
22169    ExcerptsExpanded {
22170        ids: Vec<ExcerptId>,
22171    },
22172    BufferEdited,
22173    Edited {
22174        transaction_id: clock::Lamport,
22175    },
22176    Reparsed(BufferId),
22177    Focused,
22178    FocusedIn,
22179    Blurred,
22180    DirtyChanged,
22181    Saved,
22182    TitleChanged,
22183    DiffBaseChanged,
22184    SelectionsChanged {
22185        local: bool,
22186    },
22187    ScrollPositionChanged {
22188        local: bool,
22189        autoscroll: bool,
22190    },
22191    Closed,
22192    TransactionUndone {
22193        transaction_id: clock::Lamport,
22194    },
22195    TransactionBegun {
22196        transaction_id: clock::Lamport,
22197    },
22198    Reloaded,
22199    CursorShapeChanged,
22200    PushedToNavHistory {
22201        anchor: Anchor,
22202        is_deactivate: bool,
22203    },
22204}
22205
22206impl EventEmitter<EditorEvent> for Editor {}
22207
22208impl Focusable for Editor {
22209    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22210        self.focus_handle.clone()
22211    }
22212}
22213
22214impl Render for Editor {
22215    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22216        let settings = ThemeSettings::get_global(cx);
22217
22218        let mut text_style = match self.mode {
22219            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22220                color: cx.theme().colors().editor_foreground,
22221                font_family: settings.ui_font.family.clone(),
22222                font_features: settings.ui_font.features.clone(),
22223                font_fallbacks: settings.ui_font.fallbacks.clone(),
22224                font_size: rems(0.875).into(),
22225                font_weight: settings.ui_font.weight,
22226                line_height: relative(settings.buffer_line_height.value()),
22227                ..Default::default()
22228            },
22229            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22230                color: cx.theme().colors().editor_foreground,
22231                font_family: settings.buffer_font.family.clone(),
22232                font_features: settings.buffer_font.features.clone(),
22233                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22234                font_size: settings.buffer_font_size(cx).into(),
22235                font_weight: settings.buffer_font.weight,
22236                line_height: relative(settings.buffer_line_height.value()),
22237                ..Default::default()
22238            },
22239        };
22240        if let Some(text_style_refinement) = &self.text_style_refinement {
22241            text_style.refine(text_style_refinement)
22242        }
22243
22244        let background = match self.mode {
22245            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22246            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22247            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22248            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22249        };
22250
22251        EditorElement::new(
22252            &cx.entity(),
22253            EditorStyle {
22254                background,
22255                local_player: cx.theme().players().local(),
22256                text: text_style,
22257                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22258                syntax: cx.theme().syntax().clone(),
22259                status: cx.theme().status().clone(),
22260                inlay_hints_style: make_inlay_hints_style(cx),
22261                inline_completion_styles: make_suggestion_styles(cx),
22262                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22263                show_underlines: self.diagnostics_enabled(),
22264            },
22265        )
22266    }
22267}
22268
22269impl EntityInputHandler for Editor {
22270    fn text_for_range(
22271        &mut self,
22272        range_utf16: Range<usize>,
22273        adjusted_range: &mut Option<Range<usize>>,
22274        _: &mut Window,
22275        cx: &mut Context<Self>,
22276    ) -> Option<String> {
22277        let snapshot = self.buffer.read(cx).read(cx);
22278        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22279        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22280        if (start.0..end.0) != range_utf16 {
22281            adjusted_range.replace(start.0..end.0);
22282        }
22283        Some(snapshot.text_for_range(start..end).collect())
22284    }
22285
22286    fn selected_text_range(
22287        &mut self,
22288        ignore_disabled_input: bool,
22289        _: &mut Window,
22290        cx: &mut Context<Self>,
22291    ) -> Option<UTF16Selection> {
22292        // Prevent the IME menu from appearing when holding down an alphabetic key
22293        // while input is disabled.
22294        if !ignore_disabled_input && !self.input_enabled {
22295            return None;
22296        }
22297
22298        let selection = self.selections.newest::<OffsetUtf16>(cx);
22299        let range = selection.range();
22300
22301        Some(UTF16Selection {
22302            range: range.start.0..range.end.0,
22303            reversed: selection.reversed,
22304        })
22305    }
22306
22307    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22308        let snapshot = self.buffer.read(cx).read(cx);
22309        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22310        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22311    }
22312
22313    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22314        self.clear_highlights::<InputComposition>(cx);
22315        self.ime_transaction.take();
22316    }
22317
22318    fn replace_text_in_range(
22319        &mut self,
22320        range_utf16: Option<Range<usize>>,
22321        text: &str,
22322        window: &mut Window,
22323        cx: &mut Context<Self>,
22324    ) {
22325        if !self.input_enabled {
22326            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22327            return;
22328        }
22329
22330        self.transact(window, cx, |this, window, cx| {
22331            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
22332                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22333                Some(this.selection_replacement_ranges(range_utf16, cx))
22334            } else {
22335                this.marked_text_ranges(cx)
22336            };
22337
22338            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
22339                let newest_selection_id = this.selections.newest_anchor().id;
22340                this.selections
22341                    .all::<OffsetUtf16>(cx)
22342                    .iter()
22343                    .zip(ranges_to_replace.iter())
22344                    .find_map(|(selection, range)| {
22345                        if selection.id == newest_selection_id {
22346                            Some(
22347                                (range.start.0 as isize - selection.head().0 as isize)
22348                                    ..(range.end.0 as isize - selection.head().0 as isize),
22349                            )
22350                        } else {
22351                            None
22352                        }
22353                    })
22354            });
22355
22356            cx.emit(EditorEvent::InputHandled {
22357                utf16_range_to_replace: range_to_replace,
22358                text: text.into(),
22359            });
22360
22361            if let Some(new_selected_ranges) = new_selected_ranges {
22362                this.change_selections(None, window, cx, |selections| {
22363                    selections.select_ranges(new_selected_ranges)
22364                });
22365                this.backspace(&Default::default(), window, cx);
22366            }
22367
22368            this.handle_input(text, window, cx);
22369        });
22370
22371        if let Some(transaction) = self.ime_transaction {
22372            self.buffer.update(cx, |buffer, cx| {
22373                buffer.group_until_transaction(transaction, cx);
22374            });
22375        }
22376
22377        self.unmark_text(window, cx);
22378    }
22379
22380    fn replace_and_mark_text_in_range(
22381        &mut self,
22382        range_utf16: Option<Range<usize>>,
22383        text: &str,
22384        new_selected_range_utf16: Option<Range<usize>>,
22385        window: &mut Window,
22386        cx: &mut Context<Self>,
22387    ) {
22388        if !self.input_enabled {
22389            return;
22390        }
22391
22392        let transaction = self.transact(window, cx, |this, window, cx| {
22393            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
22394                let snapshot = this.buffer.read(cx).read(cx);
22395                if let Some(relative_range_utf16) = range_utf16.as_ref() {
22396                    for marked_range in &mut marked_ranges {
22397                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
22398                        marked_range.start.0 += relative_range_utf16.start;
22399                        marked_range.start =
22400                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
22401                        marked_range.end =
22402                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
22403                    }
22404                }
22405                Some(marked_ranges)
22406            } else if let Some(range_utf16) = range_utf16 {
22407                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
22408                Some(this.selection_replacement_ranges(range_utf16, cx))
22409            } else {
22410                None
22411            };
22412
22413            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
22414                let newest_selection_id = this.selections.newest_anchor().id;
22415                this.selections
22416                    .all::<OffsetUtf16>(cx)
22417                    .iter()
22418                    .zip(ranges_to_replace.iter())
22419                    .find_map(|(selection, range)| {
22420                        if selection.id == newest_selection_id {
22421                            Some(
22422                                (range.start.0 as isize - selection.head().0 as isize)
22423                                    ..(range.end.0 as isize - selection.head().0 as isize),
22424                            )
22425                        } else {
22426                            None
22427                        }
22428                    })
22429            });
22430
22431            cx.emit(EditorEvent::InputHandled {
22432                utf16_range_to_replace: range_to_replace,
22433                text: text.into(),
22434            });
22435
22436            if let Some(ranges) = ranges_to_replace {
22437                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
22438            }
22439
22440            let marked_ranges = {
22441                let snapshot = this.buffer.read(cx).read(cx);
22442                this.selections
22443                    .disjoint_anchors()
22444                    .iter()
22445                    .map(|selection| {
22446                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
22447                    })
22448                    .collect::<Vec<_>>()
22449            };
22450
22451            if text.is_empty() {
22452                this.unmark_text(window, cx);
22453            } else {
22454                this.highlight_text::<InputComposition>(
22455                    marked_ranges.clone(),
22456                    HighlightStyle {
22457                        underline: Some(UnderlineStyle {
22458                            thickness: px(1.),
22459                            color: None,
22460                            wavy: false,
22461                        }),
22462                        ..Default::default()
22463                    },
22464                    cx,
22465                );
22466            }
22467
22468            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
22469            let use_autoclose = this.use_autoclose;
22470            let use_auto_surround = this.use_auto_surround;
22471            this.set_use_autoclose(false);
22472            this.set_use_auto_surround(false);
22473            this.handle_input(text, window, cx);
22474            this.set_use_autoclose(use_autoclose);
22475            this.set_use_auto_surround(use_auto_surround);
22476
22477            if let Some(new_selected_range) = new_selected_range_utf16 {
22478                let snapshot = this.buffer.read(cx).read(cx);
22479                let new_selected_ranges = marked_ranges
22480                    .into_iter()
22481                    .map(|marked_range| {
22482                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
22483                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
22484                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
22485                        snapshot.clip_offset_utf16(new_start, Bias::Left)
22486                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
22487                    })
22488                    .collect::<Vec<_>>();
22489
22490                drop(snapshot);
22491                this.change_selections(None, window, cx, |selections| {
22492                    selections.select_ranges(new_selected_ranges)
22493                });
22494            }
22495        });
22496
22497        self.ime_transaction = self.ime_transaction.or(transaction);
22498        if let Some(transaction) = self.ime_transaction {
22499            self.buffer.update(cx, |buffer, cx| {
22500                buffer.group_until_transaction(transaction, cx);
22501            });
22502        }
22503
22504        if self.text_highlights::<InputComposition>(cx).is_none() {
22505            self.ime_transaction.take();
22506        }
22507    }
22508
22509    fn bounds_for_range(
22510        &mut self,
22511        range_utf16: Range<usize>,
22512        element_bounds: gpui::Bounds<Pixels>,
22513        window: &mut Window,
22514        cx: &mut Context<Self>,
22515    ) -> Option<gpui::Bounds<Pixels>> {
22516        let text_layout_details = self.text_layout_details(window);
22517        let gpui::Size {
22518            width: em_width,
22519            height: line_height,
22520        } = self.character_size(window);
22521
22522        let snapshot = self.snapshot(window, cx);
22523        let scroll_position = snapshot.scroll_position();
22524        let scroll_left = scroll_position.x * em_width;
22525
22526        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
22527        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
22528            + self.gutter_dimensions.width
22529            + self.gutter_dimensions.margin;
22530        let y = line_height * (start.row().as_f32() - scroll_position.y);
22531
22532        Some(Bounds {
22533            origin: element_bounds.origin + point(x, y),
22534            size: size(em_width, line_height),
22535        })
22536    }
22537
22538    fn character_index_for_point(
22539        &mut self,
22540        point: gpui::Point<Pixels>,
22541        _window: &mut Window,
22542        _cx: &mut Context<Self>,
22543    ) -> Option<usize> {
22544        let position_map = self.last_position_map.as_ref()?;
22545        if !position_map.text_hitbox.contains(&point) {
22546            return None;
22547        }
22548        let display_point = position_map.point_for_position(point).previous_valid;
22549        let anchor = position_map
22550            .snapshot
22551            .display_point_to_anchor(display_point, Bias::Left);
22552        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
22553        Some(utf16_offset.0)
22554    }
22555}
22556
22557trait SelectionExt {
22558    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
22559    fn spanned_rows(
22560        &self,
22561        include_end_if_at_line_start: bool,
22562        map: &DisplaySnapshot,
22563    ) -> Range<MultiBufferRow>;
22564}
22565
22566impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
22567    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
22568        let start = self
22569            .start
22570            .to_point(&map.buffer_snapshot)
22571            .to_display_point(map);
22572        let end = self
22573            .end
22574            .to_point(&map.buffer_snapshot)
22575            .to_display_point(map);
22576        if self.reversed {
22577            end..start
22578        } else {
22579            start..end
22580        }
22581    }
22582
22583    fn spanned_rows(
22584        &self,
22585        include_end_if_at_line_start: bool,
22586        map: &DisplaySnapshot,
22587    ) -> Range<MultiBufferRow> {
22588        let start = self.start.to_point(&map.buffer_snapshot);
22589        let mut end = self.end.to_point(&map.buffer_snapshot);
22590        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
22591            end.row -= 1;
22592        }
22593
22594        let buffer_start = map.prev_line_boundary(start).0;
22595        let buffer_end = map.next_line_boundary(end).0;
22596        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
22597    }
22598}
22599
22600impl<T: InvalidationRegion> InvalidationStack<T> {
22601    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
22602    where
22603        S: Clone + ToOffset,
22604    {
22605        while let Some(region) = self.last() {
22606            let all_selections_inside_invalidation_ranges =
22607                if selections.len() == region.ranges().len() {
22608                    selections
22609                        .iter()
22610                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
22611                        .all(|(selection, invalidation_range)| {
22612                            let head = selection.head().to_offset(buffer);
22613                            invalidation_range.start <= head && invalidation_range.end >= head
22614                        })
22615                } else {
22616                    false
22617                };
22618
22619            if all_selections_inside_invalidation_ranges {
22620                break;
22621            } else {
22622                self.pop();
22623            }
22624        }
22625    }
22626}
22627
22628impl<T> Default for InvalidationStack<T> {
22629    fn default() -> Self {
22630        Self(Default::default())
22631    }
22632}
22633
22634impl<T> Deref for InvalidationStack<T> {
22635    type Target = Vec<T>;
22636
22637    fn deref(&self) -> &Self::Target {
22638        &self.0
22639    }
22640}
22641
22642impl<T> DerefMut for InvalidationStack<T> {
22643    fn deref_mut(&mut self) -> &mut Self::Target {
22644        &mut self.0
22645    }
22646}
22647
22648impl InvalidationRegion for SnippetState {
22649    fn ranges(&self) -> &[Range<Anchor>] {
22650        &self.ranges[self.active_index]
22651    }
22652}
22653
22654fn inline_completion_edit_text(
22655    current_snapshot: &BufferSnapshot,
22656    edits: &[(Range<Anchor>, String)],
22657    edit_preview: &EditPreview,
22658    include_deletions: bool,
22659    cx: &App,
22660) -> HighlightedText {
22661    let edits = edits
22662        .iter()
22663        .map(|(anchor, text)| {
22664            (
22665                anchor.start.text_anchor..anchor.end.text_anchor,
22666                text.clone(),
22667            )
22668        })
22669        .collect::<Vec<_>>();
22670
22671    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
22672}
22673
22674pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
22675    match severity {
22676        lsp::DiagnosticSeverity::ERROR => colors.error,
22677        lsp::DiagnosticSeverity::WARNING => colors.warning,
22678        lsp::DiagnosticSeverity::INFORMATION => colors.info,
22679        lsp::DiagnosticSeverity::HINT => colors.info,
22680        _ => colors.ignored,
22681    }
22682}
22683
22684pub fn styled_runs_for_code_label<'a>(
22685    label: &'a CodeLabel,
22686    syntax_theme: &'a theme::SyntaxTheme,
22687) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
22688    let fade_out = HighlightStyle {
22689        fade_out: Some(0.35),
22690        ..Default::default()
22691    };
22692
22693    let mut prev_end = label.filter_range.end;
22694    label
22695        .runs
22696        .iter()
22697        .enumerate()
22698        .flat_map(move |(ix, (range, highlight_id))| {
22699            let style = if let Some(style) = highlight_id.style(syntax_theme) {
22700                style
22701            } else {
22702                return Default::default();
22703            };
22704            let mut muted_style = style;
22705            muted_style.highlight(fade_out);
22706
22707            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
22708            if range.start >= label.filter_range.end {
22709                if range.start > prev_end {
22710                    runs.push((prev_end..range.start, fade_out));
22711                }
22712                runs.push((range.clone(), muted_style));
22713            } else if range.end <= label.filter_range.end {
22714                runs.push((range.clone(), style));
22715            } else {
22716                runs.push((range.start..label.filter_range.end, style));
22717                runs.push((label.filter_range.end..range.end, muted_style));
22718            }
22719            prev_end = cmp::max(prev_end, range.end);
22720
22721            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
22722                runs.push((prev_end..label.text.len(), fade_out));
22723            }
22724
22725            runs
22726        })
22727}
22728
22729pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
22730    let mut prev_index = 0;
22731    let mut prev_codepoint: Option<char> = None;
22732    text.char_indices()
22733        .chain([(text.len(), '\0')])
22734        .filter_map(move |(index, codepoint)| {
22735            let prev_codepoint = prev_codepoint.replace(codepoint)?;
22736            let is_boundary = index == text.len()
22737                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
22738                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
22739            if is_boundary {
22740                let chunk = &text[prev_index..index];
22741                prev_index = index;
22742                Some(chunk)
22743            } else {
22744                None
22745            }
22746        })
22747}
22748
22749pub trait RangeToAnchorExt: Sized {
22750    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
22751
22752    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
22753        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
22754        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
22755    }
22756}
22757
22758impl<T: ToOffset> RangeToAnchorExt for Range<T> {
22759    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
22760        let start_offset = self.start.to_offset(snapshot);
22761        let end_offset = self.end.to_offset(snapshot);
22762        if start_offset == end_offset {
22763            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
22764        } else {
22765            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
22766        }
22767    }
22768}
22769
22770pub trait RowExt {
22771    fn as_f32(&self) -> f32;
22772
22773    fn next_row(&self) -> Self;
22774
22775    fn previous_row(&self) -> Self;
22776
22777    fn minus(&self, other: Self) -> u32;
22778}
22779
22780impl RowExt for DisplayRow {
22781    fn as_f32(&self) -> f32 {
22782        self.0 as f32
22783    }
22784
22785    fn next_row(&self) -> Self {
22786        Self(self.0 + 1)
22787    }
22788
22789    fn previous_row(&self) -> Self {
22790        Self(self.0.saturating_sub(1))
22791    }
22792
22793    fn minus(&self, other: Self) -> u32 {
22794        self.0 - other.0
22795    }
22796}
22797
22798impl RowExt for MultiBufferRow {
22799    fn as_f32(&self) -> f32 {
22800        self.0 as f32
22801    }
22802
22803    fn next_row(&self) -> Self {
22804        Self(self.0 + 1)
22805    }
22806
22807    fn previous_row(&self) -> Self {
22808        Self(self.0.saturating_sub(1))
22809    }
22810
22811    fn minus(&self, other: Self) -> u32 {
22812        self.0 - other.0
22813    }
22814}
22815
22816trait RowRangeExt {
22817    type Row;
22818
22819    fn len(&self) -> usize;
22820
22821    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
22822}
22823
22824impl RowRangeExt for Range<MultiBufferRow> {
22825    type Row = MultiBufferRow;
22826
22827    fn len(&self) -> usize {
22828        (self.end.0 - self.start.0) as usize
22829    }
22830
22831    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
22832        (self.start.0..self.end.0).map(MultiBufferRow)
22833    }
22834}
22835
22836impl RowRangeExt for Range<DisplayRow> {
22837    type Row = DisplayRow;
22838
22839    fn len(&self) -> usize {
22840        (self.end.0 - self.start.0) as usize
22841    }
22842
22843    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
22844        (self.start.0..self.end.0).map(DisplayRow)
22845    }
22846}
22847
22848/// If select range has more than one line, we
22849/// just point the cursor to range.start.
22850fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
22851    if range.start.row == range.end.row {
22852        range
22853    } else {
22854        range.start..range.start
22855    }
22856}
22857pub struct KillRing(ClipboardItem);
22858impl Global for KillRing {}
22859
22860const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
22861
22862enum BreakpointPromptEditAction {
22863    Log,
22864    Condition,
22865    HitCondition,
22866}
22867
22868struct BreakpointPromptEditor {
22869    pub(crate) prompt: Entity<Editor>,
22870    editor: WeakEntity<Editor>,
22871    breakpoint_anchor: Anchor,
22872    breakpoint: Breakpoint,
22873    edit_action: BreakpointPromptEditAction,
22874    block_ids: HashSet<CustomBlockId>,
22875    editor_margins: Arc<Mutex<EditorMargins>>,
22876    _subscriptions: Vec<Subscription>,
22877}
22878
22879impl BreakpointPromptEditor {
22880    const MAX_LINES: u8 = 4;
22881
22882    fn new(
22883        editor: WeakEntity<Editor>,
22884        breakpoint_anchor: Anchor,
22885        breakpoint: Breakpoint,
22886        edit_action: BreakpointPromptEditAction,
22887        window: &mut Window,
22888        cx: &mut Context<Self>,
22889    ) -> Self {
22890        let base_text = match edit_action {
22891            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
22892            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
22893            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
22894        }
22895        .map(|msg| msg.to_string())
22896        .unwrap_or_default();
22897
22898        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
22899        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
22900
22901        let prompt = cx.new(|cx| {
22902            let mut prompt = Editor::new(
22903                EditorMode::AutoHeight {
22904                    min_lines: 1,
22905                    max_lines: Some(Self::MAX_LINES as usize),
22906                },
22907                buffer,
22908                None,
22909                window,
22910                cx,
22911            );
22912            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
22913            prompt.set_show_cursor_when_unfocused(false, cx);
22914            prompt.set_placeholder_text(
22915                match edit_action {
22916                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
22917                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
22918                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
22919                },
22920                cx,
22921            );
22922
22923            prompt
22924        });
22925
22926        Self {
22927            prompt,
22928            editor,
22929            breakpoint_anchor,
22930            breakpoint,
22931            edit_action,
22932            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
22933            block_ids: Default::default(),
22934            _subscriptions: vec![],
22935        }
22936    }
22937
22938    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
22939        self.block_ids.extend(block_ids)
22940    }
22941
22942    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
22943        if let Some(editor) = self.editor.upgrade() {
22944            let message = self
22945                .prompt
22946                .read(cx)
22947                .buffer
22948                .read(cx)
22949                .as_singleton()
22950                .expect("A multi buffer in breakpoint prompt isn't possible")
22951                .read(cx)
22952                .as_rope()
22953                .to_string();
22954
22955            editor.update(cx, |editor, cx| {
22956                editor.edit_breakpoint_at_anchor(
22957                    self.breakpoint_anchor,
22958                    self.breakpoint.clone(),
22959                    match self.edit_action {
22960                        BreakpointPromptEditAction::Log => {
22961                            BreakpointEditAction::EditLogMessage(message.into())
22962                        }
22963                        BreakpointPromptEditAction::Condition => {
22964                            BreakpointEditAction::EditCondition(message.into())
22965                        }
22966                        BreakpointPromptEditAction::HitCondition => {
22967                            BreakpointEditAction::EditHitCondition(message.into())
22968                        }
22969                    },
22970                    cx,
22971                );
22972
22973                editor.remove_blocks(self.block_ids.clone(), None, cx);
22974                cx.focus_self(window);
22975            });
22976        }
22977    }
22978
22979    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22980        self.editor
22981            .update(cx, |editor, cx| {
22982                editor.remove_blocks(self.block_ids.clone(), None, cx);
22983                window.focus(&editor.focus_handle);
22984            })
22985            .log_err();
22986    }
22987
22988    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22989        let settings = ThemeSettings::get_global(cx);
22990        let text_style = TextStyle {
22991            color: if self.prompt.read(cx).read_only(cx) {
22992                cx.theme().colors().text_disabled
22993            } else {
22994                cx.theme().colors().text
22995            },
22996            font_family: settings.buffer_font.family.clone(),
22997            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22998            font_size: settings.buffer_font_size(cx).into(),
22999            font_weight: settings.buffer_font.weight,
23000            line_height: relative(settings.buffer_line_height.value()),
23001            ..Default::default()
23002        };
23003        EditorElement::new(
23004            &self.prompt,
23005            EditorStyle {
23006                background: cx.theme().colors().editor_background,
23007                local_player: cx.theme().players().local(),
23008                text: text_style,
23009                ..Default::default()
23010            },
23011        )
23012    }
23013}
23014
23015impl Render for BreakpointPromptEditor {
23016    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23017        let editor_margins = *self.editor_margins.lock();
23018        let gutter_dimensions = editor_margins.gutter;
23019        h_flex()
23020            .key_context("Editor")
23021            .bg(cx.theme().colors().editor_background)
23022            .border_y_1()
23023            .border_color(cx.theme().status().info_border)
23024            .size_full()
23025            .py(window.line_height() / 2.5)
23026            .on_action(cx.listener(Self::confirm))
23027            .on_action(cx.listener(Self::cancel))
23028            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23029            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23030    }
23031}
23032
23033impl Focusable for BreakpointPromptEditor {
23034    fn focus_handle(&self, cx: &App) -> FocusHandle {
23035        self.prompt.focus_handle(cx)
23036    }
23037}
23038
23039fn all_edits_insertions_or_deletions(
23040    edits: &Vec<(Range<Anchor>, String)>,
23041    snapshot: &MultiBufferSnapshot,
23042) -> bool {
23043    let mut all_insertions = true;
23044    let mut all_deletions = true;
23045
23046    for (range, new_text) in edits.iter() {
23047        let range_is_empty = range.to_offset(&snapshot).is_empty();
23048        let text_is_empty = new_text.is_empty();
23049
23050        if range_is_empty != text_is_empty {
23051            if range_is_empty {
23052                all_deletions = false;
23053            } else {
23054                all_insertions = false;
23055            }
23056        } else {
23057            return false;
23058        }
23059
23060        if !all_insertions && !all_deletions {
23061            return false;
23062        }
23063    }
23064    all_insertions || all_deletions
23065}
23066
23067struct MissingEditPredictionKeybindingTooltip;
23068
23069impl Render for MissingEditPredictionKeybindingTooltip {
23070    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23071        ui::tooltip_container(window, cx, |container, _, cx| {
23072            container
23073                .flex_shrink_0()
23074                .max_w_80()
23075                .min_h(rems_from_px(124.))
23076                .justify_between()
23077                .child(
23078                    v_flex()
23079                        .flex_1()
23080                        .text_ui_sm(cx)
23081                        .child(Label::new("Conflict with Accept Keybinding"))
23082                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23083                )
23084                .child(
23085                    h_flex()
23086                        .pb_1()
23087                        .gap_1()
23088                        .items_end()
23089                        .w_full()
23090                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23091                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23092                        }))
23093                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23094                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23095                        })),
23096                )
23097        })
23098    }
23099}
23100
23101#[derive(Debug, Clone, Copy, PartialEq)]
23102pub struct LineHighlight {
23103    pub background: Background,
23104    pub border: Option<gpui::Hsla>,
23105    pub include_gutter: bool,
23106    pub type_id: Option<TypeId>,
23107}
23108
23109struct LineManipulationResult {
23110    pub new_text: String,
23111    pub line_count_before: usize,
23112    pub line_count_after: usize,
23113}
23114
23115fn render_diff_hunk_controls(
23116    row: u32,
23117    status: &DiffHunkStatus,
23118    hunk_range: Range<Anchor>,
23119    is_created_file: bool,
23120    line_height: Pixels,
23121    editor: &Entity<Editor>,
23122    _window: &mut Window,
23123    cx: &mut App,
23124) -> AnyElement {
23125    h_flex()
23126        .h(line_height)
23127        .mr_1()
23128        .gap_1()
23129        .px_0p5()
23130        .pb_1()
23131        .border_x_1()
23132        .border_b_1()
23133        .border_color(cx.theme().colors().border_variant)
23134        .rounded_b_lg()
23135        .bg(cx.theme().colors().editor_background)
23136        .gap_1()
23137        .block_mouse_except_scroll()
23138        .shadow_md()
23139        .child(if status.has_secondary_hunk() {
23140            Button::new(("stage", row as u64), "Stage")
23141                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23142                .tooltip({
23143                    let focus_handle = editor.focus_handle(cx);
23144                    move |window, cx| {
23145                        Tooltip::for_action_in(
23146                            "Stage Hunk",
23147                            &::git::ToggleStaged,
23148                            &focus_handle,
23149                            window,
23150                            cx,
23151                        )
23152                    }
23153                })
23154                .on_click({
23155                    let editor = editor.clone();
23156                    move |_event, _window, cx| {
23157                        editor.update(cx, |editor, cx| {
23158                            editor.stage_or_unstage_diff_hunks(
23159                                true,
23160                                vec![hunk_range.start..hunk_range.start],
23161                                cx,
23162                            );
23163                        });
23164                    }
23165                })
23166        } else {
23167            Button::new(("unstage", row as u64), "Unstage")
23168                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23169                .tooltip({
23170                    let focus_handle = editor.focus_handle(cx);
23171                    move |window, cx| {
23172                        Tooltip::for_action_in(
23173                            "Unstage Hunk",
23174                            &::git::ToggleStaged,
23175                            &focus_handle,
23176                            window,
23177                            cx,
23178                        )
23179                    }
23180                })
23181                .on_click({
23182                    let editor = editor.clone();
23183                    move |_event, _window, cx| {
23184                        editor.update(cx, |editor, cx| {
23185                            editor.stage_or_unstage_diff_hunks(
23186                                false,
23187                                vec![hunk_range.start..hunk_range.start],
23188                                cx,
23189                            );
23190                        });
23191                    }
23192                })
23193        })
23194        .child(
23195            Button::new(("restore", row as u64), "Restore")
23196                .tooltip({
23197                    let focus_handle = editor.focus_handle(cx);
23198                    move |window, cx| {
23199                        Tooltip::for_action_in(
23200                            "Restore Hunk",
23201                            &::git::Restore,
23202                            &focus_handle,
23203                            window,
23204                            cx,
23205                        )
23206                    }
23207                })
23208                .on_click({
23209                    let editor = editor.clone();
23210                    move |_event, window, cx| {
23211                        editor.update(cx, |editor, cx| {
23212                            let snapshot = editor.snapshot(window, cx);
23213                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23214                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23215                        });
23216                    }
23217                })
23218                .disabled(is_created_file),
23219        )
23220        .when(
23221            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23222            |el| {
23223                el.child(
23224                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23225                        .shape(IconButtonShape::Square)
23226                        .icon_size(IconSize::Small)
23227                        // .disabled(!has_multiple_hunks)
23228                        .tooltip({
23229                            let focus_handle = editor.focus_handle(cx);
23230                            move |window, cx| {
23231                                Tooltip::for_action_in(
23232                                    "Next Hunk",
23233                                    &GoToHunk,
23234                                    &focus_handle,
23235                                    window,
23236                                    cx,
23237                                )
23238                            }
23239                        })
23240                        .on_click({
23241                            let editor = editor.clone();
23242                            move |_event, window, cx| {
23243                                editor.update(cx, |editor, cx| {
23244                                    let snapshot = editor.snapshot(window, cx);
23245                                    let position =
23246                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23247                                    editor.go_to_hunk_before_or_after_position(
23248                                        &snapshot,
23249                                        position,
23250                                        Direction::Next,
23251                                        window,
23252                                        cx,
23253                                    );
23254                                    editor.expand_selected_diff_hunks(cx);
23255                                });
23256                            }
23257                        }),
23258                )
23259                .child(
23260                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23261                        .shape(IconButtonShape::Square)
23262                        .icon_size(IconSize::Small)
23263                        // .disabled(!has_multiple_hunks)
23264                        .tooltip({
23265                            let focus_handle = editor.focus_handle(cx);
23266                            move |window, cx| {
23267                                Tooltip::for_action_in(
23268                                    "Previous Hunk",
23269                                    &GoToPreviousHunk,
23270                                    &focus_handle,
23271                                    window,
23272                                    cx,
23273                                )
23274                            }
23275                        })
23276                        .on_click({
23277                            let editor = editor.clone();
23278                            move |_event, window, cx| {
23279                                editor.update(cx, |editor, cx| {
23280                                    let snapshot = editor.snapshot(window, cx);
23281                                    let point =
23282                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23283                                    editor.go_to_hunk_before_or_after_position(
23284                                        &snapshot,
23285                                        point,
23286                                        Direction::Prev,
23287                                        window,
23288                                        cx,
23289                                    );
23290                                    editor.expand_selected_diff_hunks(cx);
23291                                });
23292                            }
23293                        }),
23294                )
23295            },
23296        )
23297        .into_any_element()
23298}