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_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod proposed_changes_editor;
   37mod rust_analyzer_ext;
   38pub mod scroll;
   39mod selections_collection;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46#[cfg(test)]
   47mod inline_completion_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use actions::{AcceptEditPrediction, OpenExcerpts, OpenExcerptsSplit};
   54use aho_corasick::AhoCorasick;
   55use anyhow::{Context as _, Result, anyhow};
   56use blink_manager::BlinkManager;
   57use buffer_diff::DiffHunkStatus;
   58use client::{Collaborator, ParticipantIndex};
   59use clock::{AGENT_REPLICA_ID, ReplicaId};
   60use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   61use convert_case::{Case, Casing};
   62use dap::TelemetrySpawnLocation;
   63use display_map::*;
   64pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   65pub use editor_settings::{
   66    CurrentLineHighlight, EditorSettings, HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes,
   67    SearchSettings, ShowScrollbar,
   68};
   69use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   70pub use editor_settings_controls::*;
   71use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   72pub use element::{
   73    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   74};
   75use feature_flags::{DebuggerFeatureFlag, FeatureFlagAppExt};
   76use futures::{
   77    FutureExt,
   78    future::{self, Shared, join},
   79};
   80use fuzzy::{StringMatch, StringMatchCandidate};
   81
   82use ::git::blame::BlameEntry;
   83use ::git::{Restore, blame::ParsedCommitMessage};
   84use code_context_menus::{
   85    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   86    CompletionsMenu, ContextMenuOrigin,
   87};
   88use git::blame::{GitBlame, GlobalBlameRenderer};
   89use gpui::{
   90    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
   91    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
   92    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
   93    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
   94    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
   95    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
   96    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
   97    div, impl_actions, point, prelude::*, pulsating_between, px, relative, size,
   98};
   99use highlight_matching_bracket::refresh_matching_bracket_highlights;
  100use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  101pub use hover_popover::hover_markdown_style;
  102use hover_popover::{HoverState, hide_hover};
  103use indent_guides::ActiveIndentGuidesState;
  104use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  105pub use inline_completion::Direction;
  106use inline_completion::{EditPredictionProvider, InlineCompletionProviderHandle};
  107pub use items::MAX_TAB_TITLE_LEN;
  108use itertools::Itertools;
  109use language::{
  110    AutoindentMode, BracketMatch, BracketPair, Buffer, Capability, CharKind, CodeLabel,
  111    CursorShape, DiagnosticEntry, DiffOptions, DocumentationConfig, EditPredictionsMode,
  112    EditPreview, HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point,
  113    Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  114    language_settings::{
  115        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  116        all_language_settings, language_settings,
  117    },
  118    point_from_lsp, text_diff_with_options,
  119};
  120use language::{BufferRow, CharClassifier, Runnable, RunnableRange, point_to_lsp};
  121use linked_editing_ranges::refresh_linked_ranges;
  122use markdown::Markdown;
  123use mouse_context_menu::MouseContextMenu;
  124use persistence::DB;
  125use project::{
  126    BreakpointWithPosition, ProjectPath,
  127    debugger::{
  128        breakpoint_store::{
  129            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  130            BreakpointStoreEvent,
  131        },
  132        session::{Session, SessionEvent},
  133    },
  134    project_settings::DiagnosticSeverity,
  135};
  136
  137pub use git::blame::BlameRenderer;
  138pub use proposed_changes_editor::{
  139    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
  140};
  141use std::{cell::OnceCell, iter::Peekable, ops::Not};
  142use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  143
  144pub use lsp::CompletionContext;
  145use lsp::{
  146    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  147    LanguageServerId, LanguageServerName,
  148};
  149
  150use language::BufferSnapshot;
  151pub use lsp_ext::lsp_tasks;
  152use movement::TextLayoutDetails;
  153pub use multi_buffer::{
  154    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
  155    RowInfo, ToOffset, ToPoint,
  156};
  157use multi_buffer::{
  158    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  159    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  160};
  161use parking_lot::Mutex;
  162use project::{
  163    CodeAction, Completion, CompletionIntent, CompletionSource, DocumentHighlight, InlayHint,
  164    Location, LocationLink, PrepareRenameResponse, Project, ProjectItem, ProjectTransaction,
  165    TaskSourceKind,
  166    debugger::breakpoint_store::Breakpoint,
  167    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  168    project_settings::{GitGutterSetting, ProjectSettings},
  169};
  170use rand::prelude::*;
  171use rpc::{ErrorExt, proto::*};
  172use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  173use selections_collection::{
  174    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  175};
  176use serde::{Deserialize, Serialize};
  177use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  178use smallvec::{SmallVec, smallvec};
  179use snippet::Snippet;
  180use std::sync::Arc;
  181use std::{
  182    any::TypeId,
  183    borrow::Cow,
  184    cell::RefCell,
  185    cmp::{self, Ordering, Reverse},
  186    mem,
  187    num::NonZeroU32,
  188    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  189    path::{Path, PathBuf},
  190    rc::Rc,
  191    time::{Duration, Instant},
  192};
  193pub use sum_tree::Bias;
  194use sum_tree::TreeMap;
  195use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  196use theme::{
  197    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, ThemeColors, ThemeSettings,
  198    observe_buffer_font_size_adjustment,
  199};
  200use ui::{
  201    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  202    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  203};
  204use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  205use workspace::{
  206    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  207    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  208    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  209    item::{ItemHandle, PreviewTabsSettings},
  210    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  211    searchable::SearchEvent,
  212};
  213
  214use crate::hover_links::{find_url, find_url_from_range};
  215use crate::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
  216
  217pub const FILE_HEADER_HEIGHT: u32 = 2;
  218pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  219pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  220const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  221const MAX_LINE_LEN: usize = 1024;
  222const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  223const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  224pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  225#[doc(hidden)]
  226pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  227const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  228
  229pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  230pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  231pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  232
  233pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  234pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  235pub(crate) const MIN_LINE_NUMBER_DIGITS: u32 = 4;
  236pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  237
  238pub type RenderDiffHunkControlsFn = Arc<
  239    dyn Fn(
  240        u32,
  241        &DiffHunkStatus,
  242        Range<Anchor>,
  243        bool,
  244        Pixels,
  245        &Entity<Editor>,
  246        &mut Window,
  247        &mut App,
  248    ) -> AnyElement,
  249>;
  250
  251const COLUMNAR_SELECTION_MODIFIERS: Modifiers = Modifiers {
  252    alt: true,
  253    shift: true,
  254    control: false,
  255    platform: false,
  256    function: false,
  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    Hint(usize),
  279    DebuggerValue(usize),
  280}
  281
  282impl InlayId {
  283    fn id(&self) -> usize {
  284        match self {
  285            Self::InlineCompletion(id) => *id,
  286            Self::Hint(id) => *id,
  287            Self::DebuggerValue(id) => *id,
  288        }
  289    }
  290}
  291
  292pub enum ActiveDebugLine {}
  293pub enum DebugStackFrameLine {}
  294enum DocumentHighlightRead {}
  295enum DocumentHighlightWrite {}
  296enum InputComposition {}
  297enum SelectedTextHighlight {}
  298
  299pub enum ConflictsOuter {}
  300pub enum ConflictsOurs {}
  301pub enum ConflictsTheirs {}
  302pub enum ConflictsOursMarker {}
  303pub enum ConflictsTheirsMarker {}
  304
  305#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  306pub enum Navigated {
  307    Yes,
  308    No,
  309}
  310
  311impl Navigated {
  312    pub fn from_bool(yes: bool) -> Navigated {
  313        if yes { Navigated::Yes } else { Navigated::No }
  314    }
  315}
  316
  317#[derive(Debug, Clone, PartialEq, Eq)]
  318enum DisplayDiffHunk {
  319    Folded {
  320        display_row: DisplayRow,
  321    },
  322    Unfolded {
  323        is_created_file: bool,
  324        diff_base_byte_range: Range<usize>,
  325        display_row_range: Range<DisplayRow>,
  326        multi_buffer_range: Range<Anchor>,
  327        status: DiffHunkStatus,
  328    },
  329}
  330
  331pub enum HideMouseCursorOrigin {
  332    TypingAction,
  333    MovementAction,
  334}
  335
  336pub fn init_settings(cx: &mut App) {
  337    EditorSettings::register(cx);
  338}
  339
  340pub fn init(cx: &mut App) {
  341    init_settings(cx);
  342
  343    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  344
  345    workspace::register_project_item::<Editor>(cx);
  346    workspace::FollowableViewRegistry::register::<Editor>(cx);
  347    workspace::register_serializable_item::<Editor>(cx);
  348
  349    cx.observe_new(
  350        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  351            workspace.register_action(Editor::new_file);
  352            workspace.register_action(Editor::new_file_vertical);
  353            workspace.register_action(Editor::new_file_horizontal);
  354            workspace.register_action(Editor::cancel_language_server_work);
  355        },
  356    )
  357    .detach();
  358
  359    cx.on_action(move |_: &workspace::NewFile, cx| {
  360        let app_state = workspace::AppState::global(cx);
  361        if let Some(app_state) = app_state.upgrade() {
  362            workspace::open_new(
  363                Default::default(),
  364                app_state,
  365                cx,
  366                |workspace, window, cx| {
  367                    Editor::new_file(workspace, &Default::default(), window, cx)
  368                },
  369            )
  370            .detach();
  371        }
  372    });
  373    cx.on_action(move |_: &workspace::NewWindow, cx| {
  374        let app_state = workspace::AppState::global(cx);
  375        if let Some(app_state) = app_state.upgrade() {
  376            workspace::open_new(
  377                Default::default(),
  378                app_state,
  379                cx,
  380                |workspace, window, cx| {
  381                    cx.activate(true);
  382                    Editor::new_file(workspace, &Default::default(), window, cx)
  383                },
  384            )
  385            .detach();
  386        }
  387    });
  388}
  389
  390pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  391    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  392}
  393
  394pub trait DiagnosticRenderer {
  395    fn render_group(
  396        &self,
  397        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  398        buffer_id: BufferId,
  399        snapshot: EditorSnapshot,
  400        editor: WeakEntity<Editor>,
  401        cx: &mut App,
  402    ) -> Vec<BlockProperties<Anchor>>;
  403
  404    fn render_hover(
  405        &self,
  406        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  407        range: Range<Point>,
  408        buffer_id: BufferId,
  409        cx: &mut App,
  410    ) -> Option<Entity<markdown::Markdown>>;
  411
  412    fn open_link(
  413        &self,
  414        editor: &mut Editor,
  415        link: SharedString,
  416        window: &mut Window,
  417        cx: &mut Context<Editor>,
  418    );
  419}
  420
  421pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  422
  423impl GlobalDiagnosticRenderer {
  424    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  425        cx.try_global::<Self>().map(|g| g.0.clone())
  426    }
  427}
  428
  429impl gpui::Global for GlobalDiagnosticRenderer {}
  430pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  431    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  432}
  433
  434pub struct SearchWithinRange;
  435
  436trait InvalidationRegion {
  437    fn ranges(&self) -> &[Range<Anchor>];
  438}
  439
  440#[derive(Clone, Debug, PartialEq)]
  441pub enum SelectPhase {
  442    Begin {
  443        position: DisplayPoint,
  444        add: bool,
  445        click_count: usize,
  446    },
  447    BeginColumnar {
  448        position: DisplayPoint,
  449        reset: bool,
  450        goal_column: u32,
  451    },
  452    Extend {
  453        position: DisplayPoint,
  454        click_count: usize,
  455    },
  456    Update {
  457        position: DisplayPoint,
  458        goal_column: u32,
  459        scroll_delta: gpui::Point<f32>,
  460    },
  461    End,
  462}
  463
  464#[derive(Clone, Debug)]
  465pub enum SelectMode {
  466    Character,
  467    Word(Range<Anchor>),
  468    Line(Range<Anchor>),
  469    All,
  470}
  471
  472#[derive(Clone, PartialEq, Eq, Debug)]
  473pub enum EditorMode {
  474    SingleLine {
  475        auto_width: bool,
  476    },
  477    AutoHeight {
  478        max_lines: usize,
  479    },
  480    Full {
  481        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  482        scale_ui_elements_with_buffer_font_size: bool,
  483        /// When set to `true`, the editor will render a background for the active line.
  484        show_active_line_background: bool,
  485        /// When set to `true`, the editor's height will be determined by its content.
  486        sized_by_content: bool,
  487    },
  488    Minimap {
  489        parent: WeakEntity<Editor>,
  490    },
  491}
  492
  493impl EditorMode {
  494    pub fn full() -> Self {
  495        Self::Full {
  496            scale_ui_elements_with_buffer_font_size: true,
  497            show_active_line_background: true,
  498            sized_by_content: false,
  499        }
  500    }
  501
  502    pub fn is_full(&self) -> bool {
  503        matches!(self, Self::Full { .. })
  504    }
  505
  506    fn is_minimap(&self) -> bool {
  507        matches!(self, Self::Minimap { .. })
  508    }
  509}
  510
  511#[derive(Copy, Clone, Debug)]
  512pub enum SoftWrap {
  513    /// Prefer not to wrap at all.
  514    ///
  515    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  516    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  517    GitDiff,
  518    /// Prefer a single line generally, unless an overly long line is encountered.
  519    None,
  520    /// Soft wrap lines that exceed the editor width.
  521    EditorWidth,
  522    /// Soft wrap lines at the preferred line length.
  523    Column(u32),
  524    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  525    Bounded(u32),
  526}
  527
  528#[derive(Clone)]
  529pub struct EditorStyle {
  530    pub background: Hsla,
  531    pub local_player: PlayerColor,
  532    pub text: TextStyle,
  533    pub scrollbar_width: Pixels,
  534    pub syntax: Arc<SyntaxTheme>,
  535    pub status: StatusColors,
  536    pub inlay_hints_style: HighlightStyle,
  537    pub inline_completion_styles: InlineCompletionStyles,
  538    pub unnecessary_code_fade: f32,
  539    pub show_underlines: bool,
  540}
  541
  542impl Default for EditorStyle {
  543    fn default() -> Self {
  544        Self {
  545            background: Hsla::default(),
  546            local_player: PlayerColor::default(),
  547            text: TextStyle::default(),
  548            scrollbar_width: Pixels::default(),
  549            syntax: Default::default(),
  550            // HACK: Status colors don't have a real default.
  551            // We should look into removing the status colors from the editor
  552            // style and retrieve them directly from the theme.
  553            status: StatusColors::dark(),
  554            inlay_hints_style: HighlightStyle::default(),
  555            inline_completion_styles: InlineCompletionStyles {
  556                insertion: HighlightStyle::default(),
  557                whitespace: HighlightStyle::default(),
  558            },
  559            unnecessary_code_fade: Default::default(),
  560            show_underlines: true,
  561        }
  562    }
  563}
  564
  565pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  566    let show_background = language_settings::language_settings(None, None, cx)
  567        .inlay_hints
  568        .show_background;
  569
  570    HighlightStyle {
  571        color: Some(cx.theme().status().hint),
  572        background_color: show_background.then(|| cx.theme().status().hint_background),
  573        ..HighlightStyle::default()
  574    }
  575}
  576
  577pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  578    InlineCompletionStyles {
  579        insertion: HighlightStyle {
  580            color: Some(cx.theme().status().predictive),
  581            ..HighlightStyle::default()
  582        },
  583        whitespace: HighlightStyle {
  584            background_color: Some(cx.theme().status().created_background),
  585            ..HighlightStyle::default()
  586        },
  587    }
  588}
  589
  590type CompletionId = usize;
  591
  592pub(crate) enum EditDisplayMode {
  593    TabAccept,
  594    DiffPopover,
  595    Inline,
  596}
  597
  598enum InlineCompletion {
  599    Edit {
  600        edits: Vec<(Range<Anchor>, String)>,
  601        edit_preview: Option<EditPreview>,
  602        display_mode: EditDisplayMode,
  603        snapshot: BufferSnapshot,
  604    },
  605    Move {
  606        target: Anchor,
  607        snapshot: BufferSnapshot,
  608    },
  609}
  610
  611struct InlineCompletionState {
  612    inlay_ids: Vec<InlayId>,
  613    completion: InlineCompletion,
  614    completion_id: Option<SharedString>,
  615    invalidation_range: Range<Anchor>,
  616}
  617
  618enum EditPredictionSettings {
  619    Disabled,
  620    Enabled {
  621        show_in_menu: bool,
  622        preview_requires_modifier: bool,
  623    },
  624}
  625
  626enum InlineCompletionHighlight {}
  627
  628#[derive(Debug, Clone)]
  629struct InlineDiagnostic {
  630    message: SharedString,
  631    group_id: usize,
  632    is_primary: bool,
  633    start: Point,
  634    severity: lsp::DiagnosticSeverity,
  635}
  636
  637pub enum MenuInlineCompletionsPolicy {
  638    Never,
  639    ByProvider,
  640}
  641
  642pub enum EditPredictionPreview {
  643    /// Modifier is not pressed
  644    Inactive { released_too_fast: bool },
  645    /// Modifier pressed
  646    Active {
  647        since: Instant,
  648        previous_scroll_position: Option<ScrollAnchor>,
  649    },
  650}
  651
  652impl EditPredictionPreview {
  653    pub fn released_too_fast(&self) -> bool {
  654        match self {
  655            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  656            EditPredictionPreview::Active { .. } => false,
  657        }
  658    }
  659
  660    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  661        if let EditPredictionPreview::Active {
  662            previous_scroll_position,
  663            ..
  664        } = self
  665        {
  666            *previous_scroll_position = scroll_position;
  667        }
  668    }
  669}
  670
  671pub struct ContextMenuOptions {
  672    pub min_entries_visible: usize,
  673    pub max_entries_visible: usize,
  674    pub placement: Option<ContextMenuPlacement>,
  675}
  676
  677#[derive(Debug, Clone, PartialEq, Eq)]
  678pub enum ContextMenuPlacement {
  679    Above,
  680    Below,
  681}
  682
  683#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  684struct EditorActionId(usize);
  685
  686impl EditorActionId {
  687    pub fn post_inc(&mut self) -> Self {
  688        let answer = self.0;
  689
  690        *self = Self(answer + 1);
  691
  692        Self(answer)
  693    }
  694}
  695
  696// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  697// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  698
  699type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  700type GutterHighlight = (fn(&App) -> Hsla, Arc<[Range<Anchor>]>);
  701
  702#[derive(Default)]
  703struct ScrollbarMarkerState {
  704    scrollbar_size: Size<Pixels>,
  705    dirty: bool,
  706    markers: Arc<[PaintQuad]>,
  707    pending_refresh: Option<Task<Result<()>>>,
  708}
  709
  710impl ScrollbarMarkerState {
  711    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  712        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  713    }
  714}
  715
  716#[derive(Clone, Copy, PartialEq, Eq)]
  717pub enum MinimapVisibility {
  718    Disabled,
  719    Enabled {
  720        /// The configuration currently present in the users settings.
  721        setting_configuration: bool,
  722        /// Whether to override the currently set visibility from the users setting.
  723        toggle_override: bool,
  724    },
  725}
  726
  727impl MinimapVisibility {
  728    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  729        if mode.is_full() {
  730            Self::Enabled {
  731                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  732                toggle_override: false,
  733            }
  734        } else {
  735            Self::Disabled
  736        }
  737    }
  738
  739    fn hidden(&self) -> Self {
  740        match *self {
  741            Self::Enabled {
  742                setting_configuration,
  743                ..
  744            } => Self::Enabled {
  745                setting_configuration,
  746                toggle_override: setting_configuration,
  747            },
  748            Self::Disabled => Self::Disabled,
  749        }
  750    }
  751
  752    fn disabled(&self) -> bool {
  753        match *self {
  754            Self::Disabled => true,
  755            _ => false,
  756        }
  757    }
  758
  759    fn settings_visibility(&self) -> bool {
  760        match *self {
  761            Self::Enabled {
  762                setting_configuration,
  763                ..
  764            } => setting_configuration,
  765            _ => false,
  766        }
  767    }
  768
  769    fn visible(&self) -> bool {
  770        match *self {
  771            Self::Enabled {
  772                setting_configuration,
  773                toggle_override,
  774            } => setting_configuration ^ toggle_override,
  775            _ => false,
  776        }
  777    }
  778
  779    fn toggle_visibility(&self) -> Self {
  780        match *self {
  781            Self::Enabled {
  782                toggle_override,
  783                setting_configuration,
  784            } => Self::Enabled {
  785                setting_configuration,
  786                toggle_override: !toggle_override,
  787            },
  788            Self::Disabled => Self::Disabled,
  789        }
  790    }
  791}
  792
  793#[derive(Clone, Debug)]
  794struct RunnableTasks {
  795    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  796    offset: multi_buffer::Anchor,
  797    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  798    column: u32,
  799    // Values of all named captures, including those starting with '_'
  800    extra_variables: HashMap<String, String>,
  801    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  802    context_range: Range<BufferOffset>,
  803}
  804
  805impl RunnableTasks {
  806    fn resolve<'a>(
  807        &'a self,
  808        cx: &'a task::TaskContext,
  809    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  810        self.templates.iter().filter_map(|(kind, template)| {
  811            template
  812                .resolve_task(&kind.to_id_base(), cx)
  813                .map(|task| (kind.clone(), task))
  814        })
  815    }
  816}
  817
  818#[derive(Clone)]
  819pub struct ResolvedTasks {
  820    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  821    position: Anchor,
  822}
  823
  824#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  825struct BufferOffset(usize);
  826
  827// Addons allow storing per-editor state in other crates (e.g. Vim)
  828pub trait Addon: 'static {
  829    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  830
  831    fn render_buffer_header_controls(
  832        &self,
  833        _: &ExcerptInfo,
  834        _: &Window,
  835        _: &App,
  836    ) -> Option<AnyElement> {
  837        None
  838    }
  839
  840    fn to_any(&self) -> &dyn std::any::Any;
  841
  842    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  843        None
  844    }
  845}
  846
  847/// A set of caret positions, registered when the editor was edited.
  848pub struct ChangeList {
  849    changes: Vec<Vec<Anchor>>,
  850    /// Currently "selected" change.
  851    position: Option<usize>,
  852}
  853
  854impl ChangeList {
  855    pub fn new() -> Self {
  856        Self {
  857            changes: Vec::new(),
  858            position: None,
  859        }
  860    }
  861
  862    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  863    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  864    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  865        if self.changes.is_empty() {
  866            return None;
  867        }
  868
  869        let prev = self.position.unwrap_or(self.changes.len());
  870        let next = if direction == Direction::Prev {
  871            prev.saturating_sub(count)
  872        } else {
  873            (prev + count).min(self.changes.len() - 1)
  874        };
  875        self.position = Some(next);
  876        self.changes.get(next).map(|anchors| anchors.as_slice())
  877    }
  878
  879    /// Adds a new change to the list, resetting the change list position.
  880    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  881        self.position.take();
  882        if pop_state {
  883            self.changes.pop();
  884        }
  885        self.changes.push(new_positions.clone());
  886    }
  887
  888    pub fn last(&self) -> Option<&[Anchor]> {
  889        self.changes.last().map(|anchors| anchors.as_slice())
  890    }
  891}
  892
  893#[derive(Clone)]
  894struct InlineBlamePopoverState {
  895    scroll_handle: ScrollHandle,
  896    commit_message: Option<ParsedCommitMessage>,
  897    markdown: Entity<Markdown>,
  898}
  899
  900struct InlineBlamePopover {
  901    position: gpui::Point<Pixels>,
  902    show_task: Option<Task<()>>,
  903    hide_task: Option<Task<()>>,
  904    popover_bounds: Option<Bounds<Pixels>>,
  905    popover_state: InlineBlamePopoverState,
  906}
  907
  908/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  909/// a breakpoint on them.
  910#[derive(Clone, Copy, Debug)]
  911struct PhantomBreakpointIndicator {
  912    display_row: DisplayRow,
  913    /// There's a small debounce between hovering over the line and showing the indicator.
  914    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  915    is_active: bool,
  916    collides_with_existing_breakpoint: bool,
  917}
  918/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  919///
  920/// See the [module level documentation](self) for more information.
  921pub struct Editor {
  922    focus_handle: FocusHandle,
  923    last_focused_descendant: Option<WeakFocusHandle>,
  924    /// The text buffer being edited
  925    buffer: Entity<MultiBuffer>,
  926    /// Map of how text in the buffer should be displayed.
  927    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  928    pub display_map: Entity<DisplayMap>,
  929    pub selections: SelectionsCollection,
  930    pub scroll_manager: ScrollManager,
  931    /// When inline assist editors are linked, they all render cursors because
  932    /// typing enters text into each of them, even the ones that aren't focused.
  933    pub(crate) show_cursor_when_unfocused: bool,
  934    columnar_selection_tail: Option<Anchor>,
  935    add_selections_state: Option<AddSelectionsState>,
  936    select_next_state: Option<SelectNextState>,
  937    select_prev_state: Option<SelectNextState>,
  938    selection_history: SelectionHistory,
  939    defer_selection_effects: bool,
  940    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  941    autoclose_regions: Vec<AutocloseRegion>,
  942    snippet_stack: InvalidationStack<SnippetState>,
  943    select_syntax_node_history: SelectSyntaxNodeHistory,
  944    ime_transaction: Option<TransactionId>,
  945    pub diagnostics_max_severity: DiagnosticSeverity,
  946    active_diagnostics: ActiveDiagnostic,
  947    show_inline_diagnostics: bool,
  948    inline_diagnostics_update: Task<()>,
  949    inline_diagnostics_enabled: bool,
  950    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  951    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  952    hard_wrap: Option<usize>,
  953
  954    // TODO: make this a access method
  955    pub project: Option<Entity<Project>>,
  956    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  957    completion_provider: Option<Rc<dyn CompletionProvider>>,
  958    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  959    blink_manager: Entity<BlinkManager>,
  960    show_cursor_names: bool,
  961    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  962    pub show_local_selections: bool,
  963    mode: EditorMode,
  964    show_breadcrumbs: bool,
  965    show_gutter: bool,
  966    show_scrollbars: ScrollbarAxes,
  967    minimap_visibility: MinimapVisibility,
  968    offset_content: bool,
  969    disable_expand_excerpt_buttons: bool,
  970    show_line_numbers: Option<bool>,
  971    use_relative_line_numbers: Option<bool>,
  972    show_git_diff_gutter: Option<bool>,
  973    show_code_actions: Option<bool>,
  974    show_runnables: Option<bool>,
  975    show_breakpoints: Option<bool>,
  976    show_wrap_guides: Option<bool>,
  977    show_indent_guides: Option<bool>,
  978    placeholder_text: Option<Arc<str>>,
  979    highlight_order: usize,
  980    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  981    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  982    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  983    scrollbar_marker_state: ScrollbarMarkerState,
  984    active_indent_guides_state: ActiveIndentGuidesState,
  985    nav_history: Option<ItemNavHistory>,
  986    context_menu: RefCell<Option<CodeContextMenu>>,
  987    context_menu_options: Option<ContextMenuOptions>,
  988    mouse_context_menu: Option<MouseContextMenu>,
  989    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  990    inline_blame_popover: Option<InlineBlamePopover>,
  991    signature_help_state: SignatureHelpState,
  992    auto_signature_help: Option<bool>,
  993    find_all_references_task_sources: Vec<Anchor>,
  994    next_completion_id: CompletionId,
  995    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
  996    code_actions_task: Option<Task<Result<()>>>,
  997    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  998    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  999    document_highlights_task: Option<Task<()>>,
 1000    linked_editing_range_task: Option<Task<Option<()>>>,
 1001    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1002    pending_rename: Option<RenameState>,
 1003    searchable: bool,
 1004    cursor_shape: CursorShape,
 1005    current_line_highlight: Option<CurrentLineHighlight>,
 1006    collapse_matches: bool,
 1007    autoindent_mode: Option<AutoindentMode>,
 1008    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1009    input_enabled: bool,
 1010    use_modal_editing: bool,
 1011    read_only: bool,
 1012    leader_id: Option<CollaboratorId>,
 1013    remote_id: Option<ViewId>,
 1014    pub hover_state: HoverState,
 1015    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1016    gutter_hovered: bool,
 1017    hovered_link_state: Option<HoveredLinkState>,
 1018    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1019    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1020    active_inline_completion: Option<InlineCompletionState>,
 1021    /// Used to prevent flickering as the user types while the menu is open
 1022    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1023    edit_prediction_settings: EditPredictionSettings,
 1024    inline_completions_hidden_for_vim_mode: bool,
 1025    show_inline_completions_override: Option<bool>,
 1026    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1027    edit_prediction_preview: EditPredictionPreview,
 1028    edit_prediction_indent_conflict: bool,
 1029    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1030    inlay_hint_cache: InlayHintCache,
 1031    next_inlay_id: usize,
 1032    _subscriptions: Vec<Subscription>,
 1033    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1034    gutter_dimensions: GutterDimensions,
 1035    style: Option<EditorStyle>,
 1036    text_style_refinement: Option<TextStyleRefinement>,
 1037    next_editor_action_id: EditorActionId,
 1038    editor_actions:
 1039        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
 1040    use_autoclose: bool,
 1041    use_auto_surround: bool,
 1042    auto_replace_emoji_shortcode: bool,
 1043    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1044    show_git_blame_gutter: bool,
 1045    show_git_blame_inline: bool,
 1046    show_git_blame_inline_delay_task: Option<Task<()>>,
 1047    git_blame_inline_enabled: bool,
 1048    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1049    serialize_dirty_buffers: bool,
 1050    show_selection_menu: Option<bool>,
 1051    blame: Option<Entity<GitBlame>>,
 1052    blame_subscription: Option<Subscription>,
 1053    custom_context_menu: Option<
 1054        Box<
 1055            dyn 'static
 1056                + Fn(
 1057                    &mut Self,
 1058                    DisplayPoint,
 1059                    &mut Window,
 1060                    &mut Context<Self>,
 1061                ) -> Option<Entity<ui::ContextMenu>>,
 1062        >,
 1063    >,
 1064    last_bounds: Option<Bounds<Pixels>>,
 1065    last_position_map: Option<Rc<PositionMap>>,
 1066    expect_bounds_change: Option<Bounds<Pixels>>,
 1067    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1068    tasks_update_task: Option<Task<()>>,
 1069    breakpoint_store: Option<Entity<BreakpointStore>>,
 1070    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1071    in_project_search: bool,
 1072    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1073    breadcrumb_header: Option<String>,
 1074    focused_block: Option<FocusedBlock>,
 1075    next_scroll_position: NextScrollCursorCenterTopBottom,
 1076    addons: HashMap<TypeId, Box<dyn Addon>>,
 1077    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1078    load_diff_task: Option<Shared<Task<()>>>,
 1079    /// Whether we are temporarily displaying a diff other than git's
 1080    temporary_diff_override: bool,
 1081    selection_mark_mode: bool,
 1082    toggle_fold_multiple_buffers: Task<()>,
 1083    _scroll_cursor_center_top_bottom_task: Task<()>,
 1084    serialize_selections: Task<()>,
 1085    serialize_folds: Task<()>,
 1086    mouse_cursor_hidden: bool,
 1087    minimap: Option<Entity<Self>>,
 1088    hide_mouse_mode: HideMouseMode,
 1089    pub change_list: ChangeList,
 1090    inline_value_cache: InlineValueCache,
 1091}
 1092
 1093#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1094enum NextScrollCursorCenterTopBottom {
 1095    #[default]
 1096    Center,
 1097    Top,
 1098    Bottom,
 1099}
 1100
 1101impl NextScrollCursorCenterTopBottom {
 1102    fn next(&self) -> Self {
 1103        match self {
 1104            Self::Center => Self::Top,
 1105            Self::Top => Self::Bottom,
 1106            Self::Bottom => Self::Center,
 1107        }
 1108    }
 1109}
 1110
 1111#[derive(Clone)]
 1112pub struct EditorSnapshot {
 1113    pub mode: EditorMode,
 1114    show_gutter: bool,
 1115    show_line_numbers: Option<bool>,
 1116    show_git_diff_gutter: Option<bool>,
 1117    show_code_actions: Option<bool>,
 1118    show_runnables: Option<bool>,
 1119    show_breakpoints: Option<bool>,
 1120    git_blame_gutter_max_author_length: Option<usize>,
 1121    pub display_snapshot: DisplaySnapshot,
 1122    pub placeholder_text: Option<Arc<str>>,
 1123    is_focused: bool,
 1124    scroll_anchor: ScrollAnchor,
 1125    ongoing_scroll: OngoingScroll,
 1126    current_line_highlight: CurrentLineHighlight,
 1127    gutter_hovered: bool,
 1128}
 1129
 1130#[derive(Default, Debug, Clone, Copy)]
 1131pub struct GutterDimensions {
 1132    pub left_padding: Pixels,
 1133    pub right_padding: Pixels,
 1134    pub width: Pixels,
 1135    pub margin: Pixels,
 1136    pub git_blame_entries_width: Option<Pixels>,
 1137}
 1138
 1139impl GutterDimensions {
 1140    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1141        Self {
 1142            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1143            ..Default::default()
 1144        }
 1145    }
 1146
 1147    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1148        -cx.text_system().descent(font_id, font_size)
 1149    }
 1150    /// The full width of the space taken up by the gutter.
 1151    pub fn full_width(&self) -> Pixels {
 1152        self.margin + self.width
 1153    }
 1154
 1155    /// The width of the space reserved for the fold indicators,
 1156    /// use alongside 'justify_end' and `gutter_width` to
 1157    /// right align content with the line numbers
 1158    pub fn fold_area_width(&self) -> Pixels {
 1159        self.margin + self.right_padding
 1160    }
 1161}
 1162
 1163#[derive(Debug)]
 1164pub struct RemoteSelection {
 1165    pub replica_id: ReplicaId,
 1166    pub selection: Selection<Anchor>,
 1167    pub cursor_shape: CursorShape,
 1168    pub collaborator_id: CollaboratorId,
 1169    pub line_mode: bool,
 1170    pub user_name: Option<SharedString>,
 1171    pub color: PlayerColor,
 1172}
 1173
 1174#[derive(Clone, Debug)]
 1175struct SelectionHistoryEntry {
 1176    selections: Arc<[Selection<Anchor>]>,
 1177    select_next_state: Option<SelectNextState>,
 1178    select_prev_state: Option<SelectNextState>,
 1179    add_selections_state: Option<AddSelectionsState>,
 1180}
 1181
 1182enum SelectionHistoryMode {
 1183    Normal,
 1184    Undoing,
 1185    Redoing,
 1186}
 1187
 1188#[derive(Clone, PartialEq, Eq, Hash)]
 1189struct HoveredCursor {
 1190    replica_id: u16,
 1191    selection_id: usize,
 1192}
 1193
 1194impl Default for SelectionHistoryMode {
 1195    fn default() -> Self {
 1196        Self::Normal
 1197    }
 1198}
 1199
 1200struct DeferredSelectionEffectsState {
 1201    changed: bool,
 1202    show_completions: bool,
 1203    autoscroll: Option<Autoscroll>,
 1204    old_cursor_position: Anchor,
 1205    history_entry: SelectionHistoryEntry,
 1206}
 1207
 1208#[derive(Default)]
 1209struct SelectionHistory {
 1210    #[allow(clippy::type_complexity)]
 1211    selections_by_transaction:
 1212        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1213    mode: SelectionHistoryMode,
 1214    undo_stack: VecDeque<SelectionHistoryEntry>,
 1215    redo_stack: VecDeque<SelectionHistoryEntry>,
 1216}
 1217
 1218impl SelectionHistory {
 1219    fn insert_transaction(
 1220        &mut self,
 1221        transaction_id: TransactionId,
 1222        selections: Arc<[Selection<Anchor>]>,
 1223    ) {
 1224        self.selections_by_transaction
 1225            .insert(transaction_id, (selections, None));
 1226    }
 1227
 1228    #[allow(clippy::type_complexity)]
 1229    fn transaction(
 1230        &self,
 1231        transaction_id: TransactionId,
 1232    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1233        self.selections_by_transaction.get(&transaction_id)
 1234    }
 1235
 1236    #[allow(clippy::type_complexity)]
 1237    fn transaction_mut(
 1238        &mut self,
 1239        transaction_id: TransactionId,
 1240    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1241        self.selections_by_transaction.get_mut(&transaction_id)
 1242    }
 1243
 1244    fn push(&mut self, entry: SelectionHistoryEntry) {
 1245        if !entry.selections.is_empty() {
 1246            match self.mode {
 1247                SelectionHistoryMode::Normal => {
 1248                    self.push_undo(entry);
 1249                    self.redo_stack.clear();
 1250                }
 1251                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1252                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1253            }
 1254        }
 1255    }
 1256
 1257    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1258        if self
 1259            .undo_stack
 1260            .back()
 1261            .map_or(true, |e| e.selections != entry.selections)
 1262        {
 1263            self.undo_stack.push_back(entry);
 1264            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1265                self.undo_stack.pop_front();
 1266            }
 1267        }
 1268    }
 1269
 1270    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1271        if self
 1272            .redo_stack
 1273            .back()
 1274            .map_or(true, |e| e.selections != entry.selections)
 1275        {
 1276            self.redo_stack.push_back(entry);
 1277            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1278                self.redo_stack.pop_front();
 1279            }
 1280        }
 1281    }
 1282}
 1283
 1284#[derive(Clone, Copy)]
 1285pub struct RowHighlightOptions {
 1286    pub autoscroll: bool,
 1287    pub include_gutter: bool,
 1288}
 1289
 1290impl Default for RowHighlightOptions {
 1291    fn default() -> Self {
 1292        Self {
 1293            autoscroll: Default::default(),
 1294            include_gutter: true,
 1295        }
 1296    }
 1297}
 1298
 1299struct RowHighlight {
 1300    index: usize,
 1301    range: Range<Anchor>,
 1302    color: Hsla,
 1303    options: RowHighlightOptions,
 1304    type_id: TypeId,
 1305}
 1306
 1307#[derive(Clone, Debug)]
 1308struct AddSelectionsState {
 1309    above: bool,
 1310    stack: Vec<usize>,
 1311}
 1312
 1313#[derive(Clone)]
 1314struct SelectNextState {
 1315    query: AhoCorasick,
 1316    wordwise: bool,
 1317    done: bool,
 1318}
 1319
 1320impl std::fmt::Debug for SelectNextState {
 1321    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1322        f.debug_struct(std::any::type_name::<Self>())
 1323            .field("wordwise", &self.wordwise)
 1324            .field("done", &self.done)
 1325            .finish()
 1326    }
 1327}
 1328
 1329#[derive(Debug)]
 1330struct AutocloseRegion {
 1331    selection_id: usize,
 1332    range: Range<Anchor>,
 1333    pair: BracketPair,
 1334}
 1335
 1336#[derive(Debug)]
 1337struct SnippetState {
 1338    ranges: Vec<Vec<Range<Anchor>>>,
 1339    active_index: usize,
 1340    choices: Vec<Option<Vec<String>>>,
 1341}
 1342
 1343#[doc(hidden)]
 1344pub struct RenameState {
 1345    pub range: Range<Anchor>,
 1346    pub old_name: Arc<str>,
 1347    pub editor: Entity<Editor>,
 1348    block_id: CustomBlockId,
 1349}
 1350
 1351struct InvalidationStack<T>(Vec<T>);
 1352
 1353struct RegisteredInlineCompletionProvider {
 1354    provider: Arc<dyn InlineCompletionProviderHandle>,
 1355    _subscription: Subscription,
 1356}
 1357
 1358#[derive(Debug, PartialEq, Eq)]
 1359pub struct ActiveDiagnosticGroup {
 1360    pub active_range: Range<Anchor>,
 1361    pub active_message: String,
 1362    pub group_id: usize,
 1363    pub blocks: HashSet<CustomBlockId>,
 1364}
 1365
 1366#[derive(Debug, PartialEq, Eq)]
 1367
 1368pub(crate) enum ActiveDiagnostic {
 1369    None,
 1370    All,
 1371    Group(ActiveDiagnosticGroup),
 1372}
 1373
 1374#[derive(Serialize, Deserialize, Clone, Debug)]
 1375pub struct ClipboardSelection {
 1376    /// The number of bytes in this selection.
 1377    pub len: usize,
 1378    /// Whether this was a full-line selection.
 1379    pub is_entire_line: bool,
 1380    /// The indentation of the first line when this content was originally copied.
 1381    pub first_line_indent: u32,
 1382}
 1383
 1384// selections, scroll behavior, was newest selection reversed
 1385type SelectSyntaxNodeHistoryState = (
 1386    Box<[Selection<usize>]>,
 1387    SelectSyntaxNodeScrollBehavior,
 1388    bool,
 1389);
 1390
 1391#[derive(Default)]
 1392struct SelectSyntaxNodeHistory {
 1393    stack: Vec<SelectSyntaxNodeHistoryState>,
 1394    // disable temporarily to allow changing selections without losing the stack
 1395    pub disable_clearing: bool,
 1396}
 1397
 1398impl SelectSyntaxNodeHistory {
 1399    pub fn try_clear(&mut self) {
 1400        if !self.disable_clearing {
 1401            self.stack.clear();
 1402        }
 1403    }
 1404
 1405    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1406        self.stack.push(selection);
 1407    }
 1408
 1409    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1410        self.stack.pop()
 1411    }
 1412}
 1413
 1414enum SelectSyntaxNodeScrollBehavior {
 1415    CursorTop,
 1416    FitSelection,
 1417    CursorBottom,
 1418}
 1419
 1420#[derive(Debug)]
 1421pub(crate) struct NavigationData {
 1422    cursor_anchor: Anchor,
 1423    cursor_position: Point,
 1424    scroll_anchor: ScrollAnchor,
 1425    scroll_top_row: u32,
 1426}
 1427
 1428#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1429pub enum GotoDefinitionKind {
 1430    Symbol,
 1431    Declaration,
 1432    Type,
 1433    Implementation,
 1434}
 1435
 1436#[derive(Debug, Clone)]
 1437enum InlayHintRefreshReason {
 1438    ModifiersChanged(bool),
 1439    Toggle(bool),
 1440    SettingsChange(InlayHintSettings),
 1441    NewLinesShown,
 1442    BufferEdited(HashSet<Arc<Language>>),
 1443    RefreshRequested,
 1444    ExcerptsRemoved(Vec<ExcerptId>),
 1445}
 1446
 1447impl InlayHintRefreshReason {
 1448    fn description(&self) -> &'static str {
 1449        match self {
 1450            Self::ModifiersChanged(_) => "modifiers changed",
 1451            Self::Toggle(_) => "toggle",
 1452            Self::SettingsChange(_) => "settings change",
 1453            Self::NewLinesShown => "new lines shown",
 1454            Self::BufferEdited(_) => "buffer edited",
 1455            Self::RefreshRequested => "refresh requested",
 1456            Self::ExcerptsRemoved(_) => "excerpts removed",
 1457        }
 1458    }
 1459}
 1460
 1461pub enum FormatTarget {
 1462    Buffers,
 1463    Ranges(Vec<Range<MultiBufferPoint>>),
 1464}
 1465
 1466pub(crate) struct FocusedBlock {
 1467    id: BlockId,
 1468    focus_handle: WeakFocusHandle,
 1469}
 1470
 1471#[derive(Clone)]
 1472enum JumpData {
 1473    MultiBufferRow {
 1474        row: MultiBufferRow,
 1475        line_offset_from_top: u32,
 1476    },
 1477    MultiBufferPoint {
 1478        excerpt_id: ExcerptId,
 1479        position: Point,
 1480        anchor: text::Anchor,
 1481        line_offset_from_top: u32,
 1482    },
 1483}
 1484
 1485pub enum MultibufferSelectionMode {
 1486    First,
 1487    All,
 1488}
 1489
 1490#[derive(Clone, Copy, Debug, Default)]
 1491pub struct RewrapOptions {
 1492    pub override_language_settings: bool,
 1493    pub preserve_existing_whitespace: bool,
 1494}
 1495
 1496impl Editor {
 1497    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1498        let buffer = cx.new(|cx| Buffer::local("", cx));
 1499        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1500        Self::new(
 1501            EditorMode::SingleLine { auto_width: false },
 1502            buffer,
 1503            None,
 1504            window,
 1505            cx,
 1506        )
 1507    }
 1508
 1509    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1510        let buffer = cx.new(|cx| Buffer::local("", cx));
 1511        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1512        Self::new(EditorMode::full(), buffer, None, window, cx)
 1513    }
 1514
 1515    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1516        let buffer = cx.new(|cx| Buffer::local("", cx));
 1517        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1518        Self::new(
 1519            EditorMode::SingleLine { auto_width: true },
 1520            buffer,
 1521            None,
 1522            window,
 1523            cx,
 1524        )
 1525    }
 1526
 1527    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1528        let buffer = cx.new(|cx| Buffer::local("", cx));
 1529        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1530        Self::new(
 1531            EditorMode::AutoHeight { max_lines },
 1532            buffer,
 1533            None,
 1534            window,
 1535            cx,
 1536        )
 1537    }
 1538
 1539    pub fn for_buffer(
 1540        buffer: Entity<Buffer>,
 1541        project: Option<Entity<Project>>,
 1542        window: &mut Window,
 1543        cx: &mut Context<Self>,
 1544    ) -> Self {
 1545        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1546        Self::new(EditorMode::full(), buffer, project, window, cx)
 1547    }
 1548
 1549    pub fn for_multibuffer(
 1550        buffer: Entity<MultiBuffer>,
 1551        project: Option<Entity<Project>>,
 1552        window: &mut Window,
 1553        cx: &mut Context<Self>,
 1554    ) -> Self {
 1555        Self::new(EditorMode::full(), buffer, project, window, cx)
 1556    }
 1557
 1558    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1559        let mut clone = Self::new(
 1560            self.mode.clone(),
 1561            self.buffer.clone(),
 1562            self.project.clone(),
 1563            window,
 1564            cx,
 1565        );
 1566        self.display_map.update(cx, |display_map, cx| {
 1567            let snapshot = display_map.snapshot(cx);
 1568            clone.display_map.update(cx, |display_map, cx| {
 1569                display_map.set_state(&snapshot, cx);
 1570            });
 1571        });
 1572        clone.folds_did_change(cx);
 1573        clone.selections.clone_state(&self.selections);
 1574        clone.scroll_manager.clone_state(&self.scroll_manager);
 1575        clone.searchable = self.searchable;
 1576        clone.read_only = self.read_only;
 1577        clone
 1578    }
 1579
 1580    pub fn new(
 1581        mode: EditorMode,
 1582        buffer: Entity<MultiBuffer>,
 1583        project: Option<Entity<Project>>,
 1584        window: &mut Window,
 1585        cx: &mut Context<Self>,
 1586    ) -> Self {
 1587        Editor::new_internal(mode, buffer, project, None, window, cx)
 1588    }
 1589
 1590    fn new_internal(
 1591        mode: EditorMode,
 1592        buffer: Entity<MultiBuffer>,
 1593        project: Option<Entity<Project>>,
 1594        display_map: Option<Entity<DisplayMap>>,
 1595        window: &mut Window,
 1596        cx: &mut Context<Self>,
 1597    ) -> Self {
 1598        debug_assert!(
 1599            display_map.is_none() || mode.is_minimap(),
 1600            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1601        );
 1602
 1603        let full_mode = mode.is_full();
 1604        let diagnostics_max_severity = if full_mode {
 1605            EditorSettings::get_global(cx)
 1606                .diagnostics_max_severity
 1607                .unwrap_or(DiagnosticSeverity::Hint)
 1608        } else {
 1609            DiagnosticSeverity::Off
 1610        };
 1611        let style = window.text_style();
 1612        let font_size = style.font_size.to_pixels(window.rem_size());
 1613        let editor = cx.entity().downgrade();
 1614        let fold_placeholder = FoldPlaceholder {
 1615            constrain_width: true,
 1616            render: Arc::new(move |fold_id, fold_range, cx| {
 1617                let editor = editor.clone();
 1618                div()
 1619                    .id(fold_id)
 1620                    .bg(cx.theme().colors().ghost_element_background)
 1621                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1622                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1623                    .rounded_xs()
 1624                    .size_full()
 1625                    .cursor_pointer()
 1626                    .child("")
 1627                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1628                    .on_click(move |_, _window, cx| {
 1629                        editor
 1630                            .update(cx, |editor, cx| {
 1631                                editor.unfold_ranges(
 1632                                    &[fold_range.start..fold_range.end],
 1633                                    true,
 1634                                    false,
 1635                                    cx,
 1636                                );
 1637                                cx.stop_propagation();
 1638                            })
 1639                            .ok();
 1640                    })
 1641                    .into_any()
 1642            }),
 1643            merge_adjacent: true,
 1644            ..FoldPlaceholder::default()
 1645        };
 1646        let display_map = display_map.unwrap_or_else(|| {
 1647            cx.new(|cx| {
 1648                DisplayMap::new(
 1649                    buffer.clone(),
 1650                    style.font(),
 1651                    font_size,
 1652                    None,
 1653                    FILE_HEADER_HEIGHT,
 1654                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1655                    fold_placeholder,
 1656                    diagnostics_max_severity,
 1657                    cx,
 1658                )
 1659            })
 1660        });
 1661
 1662        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1663
 1664        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1665
 1666        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1667            .then(|| language_settings::SoftWrap::None);
 1668
 1669        let mut project_subscriptions = Vec::new();
 1670        if mode.is_full() {
 1671            if let Some(project) = project.as_ref() {
 1672                project_subscriptions.push(cx.subscribe_in(
 1673                    project,
 1674                    window,
 1675                    |editor, _, event, window, cx| match event {
 1676                        project::Event::RefreshCodeLens => {
 1677                            // we always query lens with actions, without storing them, always refreshing them
 1678                        }
 1679                        project::Event::RefreshInlayHints => {
 1680                            editor
 1681                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1682                        }
 1683                        project::Event::LanguageServerAdded(..)
 1684                        | project::Event::LanguageServerRemoved(..) => {
 1685                            if editor.tasks_update_task.is_none() {
 1686                                editor.tasks_update_task =
 1687                                    Some(editor.refresh_runnables(window, cx));
 1688                            }
 1689                        }
 1690                        project::Event::SnippetEdit(id, snippet_edits) => {
 1691                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1692                                let focus_handle = editor.focus_handle(cx);
 1693                                if focus_handle.is_focused(window) {
 1694                                    let snapshot = buffer.read(cx).snapshot();
 1695                                    for (range, snippet) in snippet_edits {
 1696                                        let editor_range =
 1697                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1698                                        editor
 1699                                            .insert_snippet(
 1700                                                &[editor_range],
 1701                                                snippet.clone(),
 1702                                                window,
 1703                                                cx,
 1704                                            )
 1705                                            .ok();
 1706                                    }
 1707                                }
 1708                            }
 1709                        }
 1710                        _ => {}
 1711                    },
 1712                ));
 1713                if let Some(task_inventory) = project
 1714                    .read(cx)
 1715                    .task_store()
 1716                    .read(cx)
 1717                    .task_inventory()
 1718                    .cloned()
 1719                {
 1720                    project_subscriptions.push(cx.observe_in(
 1721                        &task_inventory,
 1722                        window,
 1723                        |editor, _, window, cx| {
 1724                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1725                        },
 1726                    ));
 1727                };
 1728
 1729                project_subscriptions.push(cx.subscribe_in(
 1730                    &project.read(cx).breakpoint_store(),
 1731                    window,
 1732                    |editor, _, event, window, cx| match event {
 1733                        BreakpointStoreEvent::ClearDebugLines => {
 1734                            editor.clear_row_highlights::<ActiveDebugLine>();
 1735                            editor.refresh_inline_values(cx);
 1736                        }
 1737                        BreakpointStoreEvent::SetDebugLine => {
 1738                            if editor.go_to_active_debug_line(window, cx) {
 1739                                cx.stop_propagation();
 1740                            }
 1741
 1742                            editor.refresh_inline_values(cx);
 1743                        }
 1744                        _ => {}
 1745                    },
 1746                ));
 1747            }
 1748        }
 1749
 1750        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1751
 1752        let inlay_hint_settings =
 1753            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1754        let focus_handle = cx.focus_handle();
 1755        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1756            .detach();
 1757        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1758            .detach();
 1759        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1760            .detach();
 1761        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1762            .detach();
 1763
 1764        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1765            Some(false)
 1766        } else {
 1767            None
 1768        };
 1769
 1770        let breakpoint_store = match (&mode, project.as_ref()) {
 1771            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1772            _ => None,
 1773        };
 1774
 1775        let mut code_action_providers = Vec::new();
 1776        let mut load_uncommitted_diff = None;
 1777        if let Some(project) = project.clone() {
 1778            load_uncommitted_diff = Some(
 1779                update_uncommitted_diff_for_buffer(
 1780                    cx.entity(),
 1781                    &project,
 1782                    buffer.read(cx).all_buffers(),
 1783                    buffer.clone(),
 1784                    cx,
 1785                )
 1786                .shared(),
 1787            );
 1788            code_action_providers.push(Rc::new(project) as Rc<_>);
 1789        }
 1790
 1791        let mut this = Self {
 1792            focus_handle,
 1793            show_cursor_when_unfocused: false,
 1794            last_focused_descendant: None,
 1795            buffer: buffer.clone(),
 1796            display_map: display_map.clone(),
 1797            selections,
 1798            scroll_manager: ScrollManager::new(cx),
 1799            columnar_selection_tail: None,
 1800            add_selections_state: None,
 1801            select_next_state: None,
 1802            select_prev_state: None,
 1803            selection_history: SelectionHistory::default(),
 1804            defer_selection_effects: false,
 1805            deferred_selection_effects_state: None,
 1806            autoclose_regions: Vec::new(),
 1807            snippet_stack: InvalidationStack::default(),
 1808            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1809            ime_transaction: None,
 1810            active_diagnostics: ActiveDiagnostic::None,
 1811            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1812            inline_diagnostics_update: Task::ready(()),
 1813            inline_diagnostics: Vec::new(),
 1814            soft_wrap_mode_override,
 1815            diagnostics_max_severity,
 1816            hard_wrap: None,
 1817            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1818            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1819            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1820            project,
 1821            blink_manager: blink_manager.clone(),
 1822            show_local_selections: true,
 1823            show_scrollbars: ScrollbarAxes {
 1824                horizontal: full_mode,
 1825                vertical: full_mode,
 1826            },
 1827            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1828            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1829            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1830            show_gutter: mode.is_full(),
 1831            show_line_numbers: None,
 1832            use_relative_line_numbers: None,
 1833            disable_expand_excerpt_buttons: false,
 1834            show_git_diff_gutter: None,
 1835            show_code_actions: None,
 1836            show_runnables: None,
 1837            show_breakpoints: None,
 1838            show_wrap_guides: None,
 1839            show_indent_guides,
 1840            placeholder_text: None,
 1841            highlight_order: 0,
 1842            highlighted_rows: HashMap::default(),
 1843            background_highlights: TreeMap::default(),
 1844            gutter_highlights: TreeMap::default(),
 1845            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1846            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1847            nav_history: None,
 1848            context_menu: RefCell::new(None),
 1849            context_menu_options: None,
 1850            mouse_context_menu: None,
 1851            completion_tasks: Vec::new(),
 1852            inline_blame_popover: None,
 1853            signature_help_state: SignatureHelpState::default(),
 1854            auto_signature_help: None,
 1855            find_all_references_task_sources: Vec::new(),
 1856            next_completion_id: 0,
 1857            next_inlay_id: 0,
 1858            code_action_providers,
 1859            available_code_actions: None,
 1860            code_actions_task: None,
 1861            quick_selection_highlight_task: None,
 1862            debounced_selection_highlight_task: None,
 1863            document_highlights_task: None,
 1864            linked_editing_range_task: None,
 1865            pending_rename: None,
 1866            searchable: true,
 1867            cursor_shape: EditorSettings::get_global(cx)
 1868                .cursor_shape
 1869                .unwrap_or_default(),
 1870            current_line_highlight: None,
 1871            autoindent_mode: Some(AutoindentMode::EachLine),
 1872            collapse_matches: false,
 1873            workspace: None,
 1874            input_enabled: true,
 1875            use_modal_editing: mode.is_full(),
 1876            read_only: mode.is_minimap(),
 1877            use_autoclose: true,
 1878            use_auto_surround: true,
 1879            auto_replace_emoji_shortcode: false,
 1880            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1881            leader_id: None,
 1882            remote_id: None,
 1883            hover_state: HoverState::default(),
 1884            pending_mouse_down: None,
 1885            hovered_link_state: None,
 1886            edit_prediction_provider: None,
 1887            active_inline_completion: None,
 1888            stale_inline_completion_in_menu: None,
 1889            edit_prediction_preview: EditPredictionPreview::Inactive {
 1890                released_too_fast: false,
 1891            },
 1892            inline_diagnostics_enabled: mode.is_full(),
 1893            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1894            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1895
 1896            gutter_hovered: false,
 1897            pixel_position_of_newest_cursor: None,
 1898            last_bounds: None,
 1899            last_position_map: None,
 1900            expect_bounds_change: None,
 1901            gutter_dimensions: GutterDimensions::default(),
 1902            style: None,
 1903            show_cursor_names: false,
 1904            hovered_cursors: HashMap::default(),
 1905            next_editor_action_id: EditorActionId::default(),
 1906            editor_actions: Rc::default(),
 1907            inline_completions_hidden_for_vim_mode: false,
 1908            show_inline_completions_override: None,
 1909            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1910            edit_prediction_settings: EditPredictionSettings::Disabled,
 1911            edit_prediction_indent_conflict: false,
 1912            edit_prediction_requires_modifier_in_indent_conflict: true,
 1913            custom_context_menu: None,
 1914            show_git_blame_gutter: false,
 1915            show_git_blame_inline: false,
 1916            show_selection_menu: None,
 1917            show_git_blame_inline_delay_task: None,
 1918            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1919            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1920            serialize_dirty_buffers: !mode.is_minimap()
 1921                && ProjectSettings::get_global(cx)
 1922                    .session
 1923                    .restore_unsaved_buffers,
 1924            blame: None,
 1925            blame_subscription: None,
 1926            tasks: BTreeMap::default(),
 1927
 1928            breakpoint_store,
 1929            gutter_breakpoint_indicator: (None, None),
 1930            _subscriptions: vec![
 1931                cx.observe(&buffer, Self::on_buffer_changed),
 1932                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1933                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1934                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1935                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1936                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1937                cx.observe_window_activation(window, |editor, window, cx| {
 1938                    let active = window.is_window_active();
 1939                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1940                        if active {
 1941                            blink_manager.enable(cx);
 1942                        } else {
 1943                            blink_manager.disable(cx);
 1944                        }
 1945                    });
 1946                    if active {
 1947                        editor.show_mouse_cursor();
 1948                    }
 1949                }),
 1950            ],
 1951            tasks_update_task: None,
 1952            linked_edit_ranges: Default::default(),
 1953            in_project_search: false,
 1954            previous_search_ranges: None,
 1955            breadcrumb_header: None,
 1956            focused_block: None,
 1957            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1958            addons: HashMap::default(),
 1959            registered_buffers: HashMap::default(),
 1960            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1961            selection_mark_mode: false,
 1962            toggle_fold_multiple_buffers: Task::ready(()),
 1963            serialize_selections: Task::ready(()),
 1964            serialize_folds: Task::ready(()),
 1965            text_style_refinement: None,
 1966            load_diff_task: load_uncommitted_diff,
 1967            temporary_diff_override: false,
 1968            mouse_cursor_hidden: false,
 1969            minimap: None,
 1970            hide_mouse_mode: EditorSettings::get_global(cx)
 1971                .hide_mouse
 1972                .unwrap_or_default(),
 1973            change_list: ChangeList::new(),
 1974            mode,
 1975        };
 1976        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1977            this._subscriptions
 1978                .push(cx.observe(breakpoints, |_, _, cx| {
 1979                    cx.notify();
 1980                }));
 1981        }
 1982        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1983        this._subscriptions.extend(project_subscriptions);
 1984
 1985        this._subscriptions.push(cx.subscribe_in(
 1986            &cx.entity(),
 1987            window,
 1988            |editor, _, e: &EditorEvent, window, cx| match e {
 1989                EditorEvent::ScrollPositionChanged { local, .. } => {
 1990                    if *local {
 1991                        let new_anchor = editor.scroll_manager.anchor();
 1992                        let snapshot = editor.snapshot(window, cx);
 1993                        editor.update_restoration_data(cx, move |data| {
 1994                            data.scroll_position = (
 1995                                new_anchor.top_row(&snapshot.buffer_snapshot),
 1996                                new_anchor.offset,
 1997                            );
 1998                        });
 1999                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2000                        editor.inline_blame_popover.take();
 2001                    }
 2002                }
 2003                EditorEvent::Edited { .. } => {
 2004                    if !vim_enabled(cx) {
 2005                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2006                        let pop_state = editor
 2007                            .change_list
 2008                            .last()
 2009                            .map(|previous| {
 2010                                previous.len() == selections.len()
 2011                                    && previous.iter().enumerate().all(|(ix, p)| {
 2012                                        p.to_display_point(&map).row()
 2013                                            == selections[ix].head().row()
 2014                                    })
 2015                            })
 2016                            .unwrap_or(false);
 2017                        let new_positions = selections
 2018                            .into_iter()
 2019                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2020                            .collect();
 2021                        editor
 2022                            .change_list
 2023                            .push_to_change_list(pop_state, new_positions);
 2024                    }
 2025                }
 2026                _ => (),
 2027            },
 2028        ));
 2029
 2030        if let Some(dap_store) = this
 2031            .project
 2032            .as_ref()
 2033            .map(|project| project.read(cx).dap_store())
 2034        {
 2035            let weak_editor = cx.weak_entity();
 2036
 2037            this._subscriptions
 2038                .push(
 2039                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2040                        let session_entity = cx.entity();
 2041                        weak_editor
 2042                            .update(cx, |editor, cx| {
 2043                                editor._subscriptions.push(
 2044                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2045                                );
 2046                            })
 2047                            .ok();
 2048                    }),
 2049                );
 2050
 2051            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2052                this._subscriptions
 2053                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2054            }
 2055        }
 2056
 2057        this.end_selection(window, cx);
 2058        this.scroll_manager.show_scrollbars(window, cx);
 2059        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 2060
 2061        if full_mode {
 2062            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2063            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2064
 2065            if this.git_blame_inline_enabled {
 2066                this.start_git_blame_inline(false, window, cx);
 2067            }
 2068
 2069            this.go_to_active_debug_line(window, cx);
 2070
 2071            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2072                if let Some(project) = this.project.as_ref() {
 2073                    let handle = project.update(cx, |project, cx| {
 2074                        project.register_buffer_with_language_servers(&buffer, cx)
 2075                    });
 2076                    this.registered_buffers
 2077                        .insert(buffer.read(cx).remote_id(), handle);
 2078                }
 2079            }
 2080
 2081            this.minimap = this.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2082        }
 2083
 2084        this.report_editor_event("Editor Opened", None, cx);
 2085        this
 2086    }
 2087
 2088    pub fn deploy_mouse_context_menu(
 2089        &mut self,
 2090        position: gpui::Point<Pixels>,
 2091        context_menu: Entity<ContextMenu>,
 2092        window: &mut Window,
 2093        cx: &mut Context<Self>,
 2094    ) {
 2095        self.mouse_context_menu = Some(MouseContextMenu::new(
 2096            self,
 2097            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2098            context_menu,
 2099            window,
 2100            cx,
 2101        ));
 2102    }
 2103
 2104    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2105        self.mouse_context_menu
 2106            .as_ref()
 2107            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2108    }
 2109
 2110    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2111        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2112    }
 2113
 2114    fn key_context_internal(
 2115        &self,
 2116        has_active_edit_prediction: bool,
 2117        window: &Window,
 2118        cx: &App,
 2119    ) -> KeyContext {
 2120        let mut key_context = KeyContext::new_with_defaults();
 2121        key_context.add("Editor");
 2122        let mode = match self.mode {
 2123            EditorMode::SingleLine { .. } => "single_line",
 2124            EditorMode::AutoHeight { .. } => "auto_height",
 2125            EditorMode::Minimap { .. } => "minimap",
 2126            EditorMode::Full { .. } => "full",
 2127        };
 2128
 2129        if EditorSettings::jupyter_enabled(cx) {
 2130            key_context.add("jupyter");
 2131        }
 2132
 2133        key_context.set("mode", mode);
 2134        if self.pending_rename.is_some() {
 2135            key_context.add("renaming");
 2136        }
 2137
 2138        match self.context_menu.borrow().as_ref() {
 2139            Some(CodeContextMenu::Completions(_)) => {
 2140                key_context.add("menu");
 2141                key_context.add("showing_completions");
 2142            }
 2143            Some(CodeContextMenu::CodeActions(_)) => {
 2144                key_context.add("menu");
 2145                key_context.add("showing_code_actions")
 2146            }
 2147            None => {}
 2148        }
 2149
 2150        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2151        if !self.focus_handle(cx).contains_focused(window, cx)
 2152            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2153        {
 2154            for addon in self.addons.values() {
 2155                addon.extend_key_context(&mut key_context, cx)
 2156            }
 2157        }
 2158
 2159        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2160            if let Some(extension) = singleton_buffer
 2161                .read(cx)
 2162                .file()
 2163                .and_then(|file| file.path().extension()?.to_str())
 2164            {
 2165                key_context.set("extension", extension.to_string());
 2166            }
 2167        } else {
 2168            key_context.add("multibuffer");
 2169        }
 2170
 2171        if has_active_edit_prediction {
 2172            if self.edit_prediction_in_conflict() {
 2173                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2174            } else {
 2175                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2176                key_context.add("copilot_suggestion");
 2177            }
 2178        }
 2179
 2180        if self.selection_mark_mode {
 2181            key_context.add("selection_mode");
 2182        }
 2183
 2184        key_context
 2185    }
 2186
 2187    fn show_mouse_cursor(&mut self) {
 2188        self.mouse_cursor_hidden = false;
 2189    }
 2190
 2191    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2192        self.mouse_cursor_hidden = match origin {
 2193            HideMouseCursorOrigin::TypingAction => {
 2194                matches!(
 2195                    self.hide_mouse_mode,
 2196                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2197                )
 2198            }
 2199            HideMouseCursorOrigin::MovementAction => {
 2200                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2201            }
 2202        };
 2203    }
 2204
 2205    pub fn edit_prediction_in_conflict(&self) -> bool {
 2206        if !self.show_edit_predictions_in_menu() {
 2207            return false;
 2208        }
 2209
 2210        let showing_completions = self
 2211            .context_menu
 2212            .borrow()
 2213            .as_ref()
 2214            .map_or(false, |context| {
 2215                matches!(context, CodeContextMenu::Completions(_))
 2216            });
 2217
 2218        showing_completions
 2219            || self.edit_prediction_requires_modifier()
 2220            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2221            // bindings to insert tab characters.
 2222            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2223    }
 2224
 2225    pub fn accept_edit_prediction_keybind(
 2226        &self,
 2227        window: &Window,
 2228        cx: &App,
 2229    ) -> AcceptEditPredictionBinding {
 2230        let key_context = self.key_context_internal(true, window, cx);
 2231        let in_conflict = self.edit_prediction_in_conflict();
 2232
 2233        AcceptEditPredictionBinding(
 2234            window
 2235                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2236                .into_iter()
 2237                .filter(|binding| {
 2238                    !in_conflict
 2239                        || binding
 2240                            .keystrokes()
 2241                            .first()
 2242                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 2243                })
 2244                .rev()
 2245                .min_by_key(|binding| {
 2246                    binding
 2247                        .keystrokes()
 2248                        .first()
 2249                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 2250                }),
 2251        )
 2252    }
 2253
 2254    pub fn new_file(
 2255        workspace: &mut Workspace,
 2256        _: &workspace::NewFile,
 2257        window: &mut Window,
 2258        cx: &mut Context<Workspace>,
 2259    ) {
 2260        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2261            "Failed to create buffer",
 2262            window,
 2263            cx,
 2264            |e, _, _| match e.error_code() {
 2265                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2266                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2267                e.error_tag("required").unwrap_or("the latest version")
 2268            )),
 2269                _ => None,
 2270            },
 2271        );
 2272    }
 2273
 2274    pub fn new_in_workspace(
 2275        workspace: &mut Workspace,
 2276        window: &mut Window,
 2277        cx: &mut Context<Workspace>,
 2278    ) -> Task<Result<Entity<Editor>>> {
 2279        let project = workspace.project().clone();
 2280        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2281
 2282        cx.spawn_in(window, async move |workspace, cx| {
 2283            let buffer = create.await?;
 2284            workspace.update_in(cx, |workspace, window, cx| {
 2285                let editor =
 2286                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2287                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2288                editor
 2289            })
 2290        })
 2291    }
 2292
 2293    fn new_file_vertical(
 2294        workspace: &mut Workspace,
 2295        _: &workspace::NewFileSplitVertical,
 2296        window: &mut Window,
 2297        cx: &mut Context<Workspace>,
 2298    ) {
 2299        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2300    }
 2301
 2302    fn new_file_horizontal(
 2303        workspace: &mut Workspace,
 2304        _: &workspace::NewFileSplitHorizontal,
 2305        window: &mut Window,
 2306        cx: &mut Context<Workspace>,
 2307    ) {
 2308        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2309    }
 2310
 2311    fn new_file_in_direction(
 2312        workspace: &mut Workspace,
 2313        direction: SplitDirection,
 2314        window: &mut Window,
 2315        cx: &mut Context<Workspace>,
 2316    ) {
 2317        let project = workspace.project().clone();
 2318        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2319
 2320        cx.spawn_in(window, async move |workspace, cx| {
 2321            let buffer = create.await?;
 2322            workspace.update_in(cx, move |workspace, window, cx| {
 2323                workspace.split_item(
 2324                    direction,
 2325                    Box::new(
 2326                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2327                    ),
 2328                    window,
 2329                    cx,
 2330                )
 2331            })?;
 2332            anyhow::Ok(())
 2333        })
 2334        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2335            match e.error_code() {
 2336                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2337                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2338                e.error_tag("required").unwrap_or("the latest version")
 2339            )),
 2340                _ => None,
 2341            }
 2342        });
 2343    }
 2344
 2345    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2346        self.leader_id
 2347    }
 2348
 2349    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2350        &self.buffer
 2351    }
 2352
 2353    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2354        self.workspace.as_ref()?.0.upgrade()
 2355    }
 2356
 2357    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2358        self.buffer().read(cx).title(cx)
 2359    }
 2360
 2361    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2362        let git_blame_gutter_max_author_length = self
 2363            .render_git_blame_gutter(cx)
 2364            .then(|| {
 2365                if let Some(blame) = self.blame.as_ref() {
 2366                    let max_author_length =
 2367                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2368                    Some(max_author_length)
 2369                } else {
 2370                    None
 2371                }
 2372            })
 2373            .flatten();
 2374
 2375        EditorSnapshot {
 2376            mode: self.mode.clone(),
 2377            show_gutter: self.show_gutter,
 2378            show_line_numbers: self.show_line_numbers,
 2379            show_git_diff_gutter: self.show_git_diff_gutter,
 2380            show_code_actions: self.show_code_actions,
 2381            show_runnables: self.show_runnables,
 2382            show_breakpoints: self.show_breakpoints,
 2383            git_blame_gutter_max_author_length,
 2384            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2385            scroll_anchor: self.scroll_manager.anchor(),
 2386            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2387            placeholder_text: self.placeholder_text.clone(),
 2388            is_focused: self.focus_handle.is_focused(window),
 2389            current_line_highlight: self
 2390                .current_line_highlight
 2391                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2392            gutter_hovered: self.gutter_hovered,
 2393        }
 2394    }
 2395
 2396    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2397        self.buffer.read(cx).language_at(point, cx)
 2398    }
 2399
 2400    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2401        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2402    }
 2403
 2404    pub fn active_excerpt(
 2405        &self,
 2406        cx: &App,
 2407    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2408        self.buffer
 2409            .read(cx)
 2410            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2411    }
 2412
 2413    pub fn mode(&self) -> &EditorMode {
 2414        &self.mode
 2415    }
 2416
 2417    pub fn set_mode(&mut self, mode: EditorMode) {
 2418        self.mode = mode;
 2419    }
 2420
 2421    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2422        self.collaboration_hub.as_deref()
 2423    }
 2424
 2425    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2426        self.collaboration_hub = Some(hub);
 2427    }
 2428
 2429    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2430        self.in_project_search = in_project_search;
 2431    }
 2432
 2433    pub fn set_custom_context_menu(
 2434        &mut self,
 2435        f: impl 'static
 2436        + Fn(
 2437            &mut Self,
 2438            DisplayPoint,
 2439            &mut Window,
 2440            &mut Context<Self>,
 2441        ) -> Option<Entity<ui::ContextMenu>>,
 2442    ) {
 2443        self.custom_context_menu = Some(Box::new(f))
 2444    }
 2445
 2446    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2447        self.completion_provider = provider;
 2448    }
 2449
 2450    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2451        self.semantics_provider.clone()
 2452    }
 2453
 2454    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2455        self.semantics_provider = provider;
 2456    }
 2457
 2458    pub fn set_edit_prediction_provider<T>(
 2459        &mut self,
 2460        provider: Option<Entity<T>>,
 2461        window: &mut Window,
 2462        cx: &mut Context<Self>,
 2463    ) where
 2464        T: EditPredictionProvider,
 2465    {
 2466        self.edit_prediction_provider =
 2467            provider.map(|provider| RegisteredInlineCompletionProvider {
 2468                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2469                    if this.focus_handle.is_focused(window) {
 2470                        this.update_visible_inline_completion(window, cx);
 2471                    }
 2472                }),
 2473                provider: Arc::new(provider),
 2474            });
 2475        self.update_edit_prediction_settings(cx);
 2476        self.refresh_inline_completion(false, false, window, cx);
 2477    }
 2478
 2479    pub fn placeholder_text(&self) -> Option<&str> {
 2480        self.placeholder_text.as_deref()
 2481    }
 2482
 2483    pub fn set_placeholder_text(
 2484        &mut self,
 2485        placeholder_text: impl Into<Arc<str>>,
 2486        cx: &mut Context<Self>,
 2487    ) {
 2488        let placeholder_text = Some(placeholder_text.into());
 2489        if self.placeholder_text != placeholder_text {
 2490            self.placeholder_text = placeholder_text;
 2491            cx.notify();
 2492        }
 2493    }
 2494
 2495    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2496        self.cursor_shape = cursor_shape;
 2497
 2498        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2499        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2500
 2501        cx.notify();
 2502    }
 2503
 2504    pub fn set_current_line_highlight(
 2505        &mut self,
 2506        current_line_highlight: Option<CurrentLineHighlight>,
 2507    ) {
 2508        self.current_line_highlight = current_line_highlight;
 2509    }
 2510
 2511    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2512        self.collapse_matches = collapse_matches;
 2513    }
 2514
 2515    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2516        let buffers = self.buffer.read(cx).all_buffers();
 2517        let Some(project) = self.project.as_ref() else {
 2518            return;
 2519        };
 2520        project.update(cx, |project, cx| {
 2521            for buffer in buffers {
 2522                self.registered_buffers
 2523                    .entry(buffer.read(cx).remote_id())
 2524                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2525            }
 2526        })
 2527    }
 2528
 2529    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2530        if self.collapse_matches {
 2531            return range.start..range.start;
 2532        }
 2533        range.clone()
 2534    }
 2535
 2536    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2537        if self.display_map.read(cx).clip_at_line_ends != clip {
 2538            self.display_map
 2539                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2540        }
 2541    }
 2542
 2543    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2544        self.input_enabled = input_enabled;
 2545    }
 2546
 2547    pub fn set_inline_completions_hidden_for_vim_mode(
 2548        &mut self,
 2549        hidden: bool,
 2550        window: &mut Window,
 2551        cx: &mut Context<Self>,
 2552    ) {
 2553        if hidden != self.inline_completions_hidden_for_vim_mode {
 2554            self.inline_completions_hidden_for_vim_mode = hidden;
 2555            if hidden {
 2556                self.update_visible_inline_completion(window, cx);
 2557            } else {
 2558                self.refresh_inline_completion(true, false, window, cx);
 2559            }
 2560        }
 2561    }
 2562
 2563    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2564        self.menu_inline_completions_policy = value;
 2565    }
 2566
 2567    pub fn set_autoindent(&mut self, autoindent: bool) {
 2568        if autoindent {
 2569            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2570        } else {
 2571            self.autoindent_mode = None;
 2572        }
 2573    }
 2574
 2575    pub fn read_only(&self, cx: &App) -> bool {
 2576        self.read_only || self.buffer.read(cx).read_only()
 2577    }
 2578
 2579    pub fn set_read_only(&mut self, read_only: bool) {
 2580        self.read_only = read_only;
 2581    }
 2582
 2583    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2584        self.use_autoclose = autoclose;
 2585    }
 2586
 2587    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2588        self.use_auto_surround = auto_surround;
 2589    }
 2590
 2591    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2592        self.auto_replace_emoji_shortcode = auto_replace;
 2593    }
 2594
 2595    pub fn toggle_edit_predictions(
 2596        &mut self,
 2597        _: &ToggleEditPrediction,
 2598        window: &mut Window,
 2599        cx: &mut Context<Self>,
 2600    ) {
 2601        if self.show_inline_completions_override.is_some() {
 2602            self.set_show_edit_predictions(None, window, cx);
 2603        } else {
 2604            let show_edit_predictions = !self.edit_predictions_enabled();
 2605            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2606        }
 2607    }
 2608
 2609    pub fn set_show_edit_predictions(
 2610        &mut self,
 2611        show_edit_predictions: Option<bool>,
 2612        window: &mut Window,
 2613        cx: &mut Context<Self>,
 2614    ) {
 2615        self.show_inline_completions_override = show_edit_predictions;
 2616        self.update_edit_prediction_settings(cx);
 2617
 2618        if let Some(false) = show_edit_predictions {
 2619            self.discard_inline_completion(false, cx);
 2620        } else {
 2621            self.refresh_inline_completion(false, true, window, cx);
 2622        }
 2623    }
 2624
 2625    fn inline_completions_disabled_in_scope(
 2626        &self,
 2627        buffer: &Entity<Buffer>,
 2628        buffer_position: language::Anchor,
 2629        cx: &App,
 2630    ) -> bool {
 2631        let snapshot = buffer.read(cx).snapshot();
 2632        let settings = snapshot.settings_at(buffer_position, cx);
 2633
 2634        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2635            return false;
 2636        };
 2637
 2638        scope.override_name().map_or(false, |scope_name| {
 2639            settings
 2640                .edit_predictions_disabled_in
 2641                .iter()
 2642                .any(|s| s == scope_name)
 2643        })
 2644    }
 2645
 2646    pub fn set_use_modal_editing(&mut self, to: bool) {
 2647        self.use_modal_editing = to;
 2648    }
 2649
 2650    pub fn use_modal_editing(&self) -> bool {
 2651        self.use_modal_editing
 2652    }
 2653
 2654    fn selections_did_change(
 2655        &mut self,
 2656        local: bool,
 2657        old_cursor_position: &Anchor,
 2658        show_completions: bool,
 2659        window: &mut Window,
 2660        cx: &mut Context<Self>,
 2661    ) {
 2662        window.invalidate_character_coordinates();
 2663
 2664        // Copy selections to primary selection buffer
 2665        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2666        if local {
 2667            let selections = self.selections.all::<usize>(cx);
 2668            let buffer_handle = self.buffer.read(cx).read(cx);
 2669
 2670            let mut text = String::new();
 2671            for (index, selection) in selections.iter().enumerate() {
 2672                let text_for_selection = buffer_handle
 2673                    .text_for_range(selection.start..selection.end)
 2674                    .collect::<String>();
 2675
 2676                text.push_str(&text_for_selection);
 2677                if index != selections.len() - 1 {
 2678                    text.push('\n');
 2679                }
 2680            }
 2681
 2682            if !text.is_empty() {
 2683                cx.write_to_primary(ClipboardItem::new_string(text));
 2684            }
 2685        }
 2686
 2687        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2688            self.buffer.update(cx, |buffer, cx| {
 2689                buffer.set_active_selections(
 2690                    &self.selections.disjoint_anchors(),
 2691                    self.selections.line_mode,
 2692                    self.cursor_shape,
 2693                    cx,
 2694                )
 2695            });
 2696        }
 2697        let display_map = self
 2698            .display_map
 2699            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2700        let buffer = &display_map.buffer_snapshot;
 2701        self.add_selections_state = None;
 2702        self.select_next_state = None;
 2703        self.select_prev_state = None;
 2704        self.select_syntax_node_history.try_clear();
 2705        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2706        self.snippet_stack
 2707            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2708        self.take_rename(false, window, cx);
 2709
 2710        let new_cursor_position = self.selections.newest_anchor().head();
 2711
 2712        self.push_to_nav_history(
 2713            *old_cursor_position,
 2714            Some(new_cursor_position.to_point(buffer)),
 2715            false,
 2716            cx,
 2717        );
 2718
 2719        if local {
 2720            let new_cursor_position = self.selections.newest_anchor().head();
 2721            let mut context_menu = self.context_menu.borrow_mut();
 2722            let completion_menu = match context_menu.as_ref() {
 2723                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2724                _ => {
 2725                    *context_menu = None;
 2726                    None
 2727                }
 2728            };
 2729            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2730                if !self.registered_buffers.contains_key(&buffer_id) {
 2731                    if let Some(project) = self.project.as_ref() {
 2732                        project.update(cx, |project, cx| {
 2733                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2734                                return;
 2735                            };
 2736                            self.registered_buffers.insert(
 2737                                buffer_id,
 2738                                project.register_buffer_with_language_servers(&buffer, cx),
 2739                            );
 2740                        })
 2741                    }
 2742                }
 2743            }
 2744
 2745            if let Some(completion_menu) = completion_menu {
 2746                let cursor_position = new_cursor_position.to_offset(buffer);
 2747                let (word_range, kind) =
 2748                    buffer.surrounding_word(completion_menu.initial_position, true);
 2749                if kind == Some(CharKind::Word)
 2750                    && word_range.to_inclusive().contains(&cursor_position)
 2751                {
 2752                    let mut completion_menu = completion_menu.clone();
 2753                    drop(context_menu);
 2754
 2755                    let query = Self::completion_query(buffer, cursor_position);
 2756                    let completion_provider = self.completion_provider.clone();
 2757                    cx.spawn_in(window, async move |this, cx| {
 2758                        completion_menu
 2759                            .filter(query.as_deref(), completion_provider, this.clone(), cx)
 2760                            .await;
 2761
 2762                        this.update(cx, |this, cx| {
 2763                            let mut context_menu = this.context_menu.borrow_mut();
 2764                            let Some(CodeContextMenu::Completions(menu)) = context_menu.as_ref()
 2765                            else {
 2766                                return;
 2767                            };
 2768
 2769                            if menu.id > completion_menu.id {
 2770                                return;
 2771                            }
 2772
 2773                            *context_menu = Some(CodeContextMenu::Completions(completion_menu));
 2774                            drop(context_menu);
 2775                            cx.notify();
 2776                        })
 2777                    })
 2778                    .detach();
 2779
 2780                    if show_completions {
 2781                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2782                    }
 2783                } else {
 2784                    drop(context_menu);
 2785                    self.hide_context_menu(window, cx);
 2786                }
 2787            } else {
 2788                drop(context_menu);
 2789            }
 2790
 2791            hide_hover(self, cx);
 2792
 2793            if old_cursor_position.to_display_point(&display_map).row()
 2794                != new_cursor_position.to_display_point(&display_map).row()
 2795            {
 2796                self.available_code_actions.take();
 2797            }
 2798            self.refresh_code_actions(window, cx);
 2799            self.refresh_document_highlights(cx);
 2800            self.refresh_selected_text_highlights(false, window, cx);
 2801            refresh_matching_bracket_highlights(self, window, cx);
 2802            self.update_visible_inline_completion(window, cx);
 2803            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2804            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2805            self.inline_blame_popover.take();
 2806            if self.git_blame_inline_enabled {
 2807                self.start_inline_blame_timer(window, cx);
 2808            }
 2809        }
 2810
 2811        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2812        cx.emit(EditorEvent::SelectionsChanged { local });
 2813
 2814        let selections = &self.selections.disjoint;
 2815        if selections.len() == 1 {
 2816            cx.emit(SearchEvent::ActiveMatchChanged)
 2817        }
 2818        if local {
 2819            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2820                let inmemory_selections = selections
 2821                    .iter()
 2822                    .map(|s| {
 2823                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2824                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2825                    })
 2826                    .collect();
 2827                self.update_restoration_data(cx, |data| {
 2828                    data.selections = inmemory_selections;
 2829                });
 2830
 2831                if WorkspaceSettings::get(None, cx).restore_on_startup
 2832                    != RestoreOnStartupBehavior::None
 2833                {
 2834                    if let Some(workspace_id) =
 2835                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2836                    {
 2837                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2838                        let selections = selections.clone();
 2839                        let background_executor = cx.background_executor().clone();
 2840                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2841                        self.serialize_selections = cx.background_spawn(async move {
 2842                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2843                    let db_selections = selections
 2844                        .iter()
 2845                        .map(|selection| {
 2846                            (
 2847                                selection.start.to_offset(&snapshot),
 2848                                selection.end.to_offset(&snapshot),
 2849                            )
 2850                        })
 2851                        .collect();
 2852
 2853                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2854                        .await
 2855                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2856                        .log_err();
 2857                });
 2858                    }
 2859                }
 2860            }
 2861        }
 2862
 2863        cx.notify();
 2864    }
 2865
 2866    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2867        use text::ToOffset as _;
 2868        use text::ToPoint as _;
 2869
 2870        if self.mode.is_minimap()
 2871            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2872        {
 2873            return;
 2874        }
 2875
 2876        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2877            return;
 2878        };
 2879
 2880        let snapshot = singleton.read(cx).snapshot();
 2881        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2882            let display_snapshot = display_map.snapshot(cx);
 2883
 2884            display_snapshot
 2885                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2886                .map(|fold| {
 2887                    fold.range.start.text_anchor.to_point(&snapshot)
 2888                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2889                })
 2890                .collect()
 2891        });
 2892        self.update_restoration_data(cx, |data| {
 2893            data.folds = inmemory_folds;
 2894        });
 2895
 2896        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2897            return;
 2898        };
 2899        let background_executor = cx.background_executor().clone();
 2900        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2901        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2902            display_map
 2903                .snapshot(cx)
 2904                .folds_in_range(0..snapshot.len())
 2905                .map(|fold| {
 2906                    (
 2907                        fold.range.start.text_anchor.to_offset(&snapshot),
 2908                        fold.range.end.text_anchor.to_offset(&snapshot),
 2909                    )
 2910                })
 2911                .collect()
 2912        });
 2913        self.serialize_folds = cx.background_spawn(async move {
 2914            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2915            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2916                .await
 2917                .with_context(|| {
 2918                    format!(
 2919                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2920                    )
 2921                })
 2922                .log_err();
 2923        });
 2924    }
 2925
 2926    pub fn sync_selections(
 2927        &mut self,
 2928        other: Entity<Editor>,
 2929        cx: &mut Context<Self>,
 2930    ) -> gpui::Subscription {
 2931        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2932        self.selections.change_with(cx, |selections| {
 2933            selections.select_anchors(other_selections);
 2934        });
 2935
 2936        let other_subscription =
 2937            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2938                EditorEvent::SelectionsChanged { local: true } => {
 2939                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2940                    if other_selections.is_empty() {
 2941                        return;
 2942                    }
 2943                    this.selections.change_with(cx, |selections| {
 2944                        selections.select_anchors(other_selections);
 2945                    });
 2946                }
 2947                _ => {}
 2948            });
 2949
 2950        let this_subscription =
 2951            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2952                EditorEvent::SelectionsChanged { local: true } => {
 2953                    let these_selections = this.selections.disjoint.to_vec();
 2954                    if these_selections.is_empty() {
 2955                        return;
 2956                    }
 2957                    other.update(cx, |other_editor, cx| {
 2958                        other_editor.selections.change_with(cx, |selections| {
 2959                            selections.select_anchors(these_selections);
 2960                        })
 2961                    });
 2962                }
 2963                _ => {}
 2964            });
 2965
 2966        Subscription::join(other_subscription, this_subscription)
 2967    }
 2968
 2969    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 2970    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 2971    /// effects of selection change occur at the end of the transaction.
 2972    pub fn change_selections<R>(
 2973        &mut self,
 2974        autoscroll: Option<Autoscroll>,
 2975        window: &mut Window,
 2976        cx: &mut Context<Self>,
 2977        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2978    ) -> R {
 2979        self.change_selections_inner(true, autoscroll, window, cx, change)
 2980    }
 2981
 2982    pub(crate) fn change_selections_without_showing_completions<R>(
 2983        &mut self,
 2984        autoscroll: Option<Autoscroll>,
 2985        window: &mut Window,
 2986        cx: &mut Context<Self>,
 2987        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2988    ) -> R {
 2989        self.change_selections_inner(false, autoscroll, window, cx, change)
 2990    }
 2991
 2992    fn change_selections_inner<R>(
 2993        &mut self,
 2994        show_completions: bool,
 2995        autoscroll: Option<Autoscroll>,
 2996        window: &mut Window,
 2997        cx: &mut Context<Self>,
 2998        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2999    ) -> R {
 3000        if let Some(state) = &mut self.deferred_selection_effects_state {
 3001            state.autoscroll = autoscroll.or(state.autoscroll);
 3002            state.show_completions = show_completions;
 3003            let (changed, result) = self.selections.change_with(cx, change);
 3004            state.changed |= changed;
 3005            return result;
 3006        }
 3007        let mut state = DeferredSelectionEffectsState {
 3008            changed: false,
 3009            show_completions,
 3010            autoscroll,
 3011            old_cursor_position: self.selections.newest_anchor().head(),
 3012            history_entry: SelectionHistoryEntry {
 3013                selections: self.selections.disjoint_anchors(),
 3014                select_next_state: self.select_next_state.clone(),
 3015                select_prev_state: self.select_prev_state.clone(),
 3016                add_selections_state: self.add_selections_state.clone(),
 3017            },
 3018        };
 3019        let (changed, result) = self.selections.change_with(cx, change);
 3020        state.changed = state.changed || changed;
 3021        if self.defer_selection_effects {
 3022            self.deferred_selection_effects_state = Some(state);
 3023        } else {
 3024            self.apply_selection_effects(state, window, cx);
 3025        }
 3026        result
 3027    }
 3028
 3029    /// Defers the effects of selection change, so that the effects of multiple calls to
 3030    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3031    /// to selection history and the state of popovers based on selection position aren't
 3032    /// erroneously updated.
 3033    pub fn with_selection_effects_deferred<R>(
 3034        &mut self,
 3035        window: &mut Window,
 3036        cx: &mut Context<Self>,
 3037        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3038    ) -> R {
 3039        let already_deferred = self.defer_selection_effects;
 3040        self.defer_selection_effects = true;
 3041        let result = update(self, window, cx);
 3042        if !already_deferred {
 3043            self.defer_selection_effects = false;
 3044            if let Some(state) = self.deferred_selection_effects_state.take() {
 3045                self.apply_selection_effects(state, window, cx);
 3046            }
 3047        }
 3048        result
 3049    }
 3050
 3051    fn apply_selection_effects(
 3052        &mut self,
 3053        state: DeferredSelectionEffectsState,
 3054        window: &mut Window,
 3055        cx: &mut Context<Self>,
 3056    ) {
 3057        if state.changed {
 3058            self.selection_history.push(state.history_entry);
 3059
 3060            if let Some(autoscroll) = state.autoscroll {
 3061                self.request_autoscroll(autoscroll, cx);
 3062            }
 3063
 3064            let old_cursor_position = &state.old_cursor_position;
 3065
 3066            self.selections_did_change(
 3067                true,
 3068                &old_cursor_position,
 3069                state.show_completions,
 3070                window,
 3071                cx,
 3072            );
 3073
 3074            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3075                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3076            }
 3077        }
 3078    }
 3079
 3080    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3081    where
 3082        I: IntoIterator<Item = (Range<S>, T)>,
 3083        S: ToOffset,
 3084        T: Into<Arc<str>>,
 3085    {
 3086        if self.read_only(cx) {
 3087            return;
 3088        }
 3089
 3090        self.buffer
 3091            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3092    }
 3093
 3094    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3095    where
 3096        I: IntoIterator<Item = (Range<S>, T)>,
 3097        S: ToOffset,
 3098        T: Into<Arc<str>>,
 3099    {
 3100        if self.read_only(cx) {
 3101            return;
 3102        }
 3103
 3104        self.buffer.update(cx, |buffer, cx| {
 3105            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3106        });
 3107    }
 3108
 3109    pub fn edit_with_block_indent<I, S, T>(
 3110        &mut self,
 3111        edits: I,
 3112        original_indent_columns: Vec<Option<u32>>,
 3113        cx: &mut Context<Self>,
 3114    ) where
 3115        I: IntoIterator<Item = (Range<S>, T)>,
 3116        S: ToOffset,
 3117        T: Into<Arc<str>>,
 3118    {
 3119        if self.read_only(cx) {
 3120            return;
 3121        }
 3122
 3123        self.buffer.update(cx, |buffer, cx| {
 3124            buffer.edit(
 3125                edits,
 3126                Some(AutoindentMode::Block {
 3127                    original_indent_columns,
 3128                }),
 3129                cx,
 3130            )
 3131        });
 3132    }
 3133
 3134    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3135        self.hide_context_menu(window, cx);
 3136
 3137        match phase {
 3138            SelectPhase::Begin {
 3139                position,
 3140                add,
 3141                click_count,
 3142            } => self.begin_selection(position, add, click_count, window, cx),
 3143            SelectPhase::BeginColumnar {
 3144                position,
 3145                goal_column,
 3146                reset,
 3147            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3148            SelectPhase::Extend {
 3149                position,
 3150                click_count,
 3151            } => self.extend_selection(position, click_count, window, cx),
 3152            SelectPhase::Update {
 3153                position,
 3154                goal_column,
 3155                scroll_delta,
 3156            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3157            SelectPhase::End => self.end_selection(window, cx),
 3158        }
 3159    }
 3160
 3161    fn extend_selection(
 3162        &mut self,
 3163        position: DisplayPoint,
 3164        click_count: usize,
 3165        window: &mut Window,
 3166        cx: &mut Context<Self>,
 3167    ) {
 3168        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3169        let tail = self.selections.newest::<usize>(cx).tail();
 3170        self.begin_selection(position, false, click_count, window, cx);
 3171
 3172        let position = position.to_offset(&display_map, Bias::Left);
 3173        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3174
 3175        let mut pending_selection = self
 3176            .selections
 3177            .pending_anchor()
 3178            .expect("extend_selection not called with pending selection");
 3179        if position >= tail {
 3180            pending_selection.start = tail_anchor;
 3181        } else {
 3182            pending_selection.end = tail_anchor;
 3183            pending_selection.reversed = true;
 3184        }
 3185
 3186        let mut pending_mode = self.selections.pending_mode().unwrap();
 3187        match &mut pending_mode {
 3188            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3189            _ => {}
 3190        }
 3191
 3192        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3193
 3194        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3195            s.set_pending(pending_selection, pending_mode)
 3196        });
 3197    }
 3198
 3199    fn begin_selection(
 3200        &mut self,
 3201        position: DisplayPoint,
 3202        add: bool,
 3203        click_count: usize,
 3204        window: &mut Window,
 3205        cx: &mut Context<Self>,
 3206    ) {
 3207        if !self.focus_handle.is_focused(window) {
 3208            self.last_focused_descendant = None;
 3209            window.focus(&self.focus_handle);
 3210        }
 3211
 3212        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3213        let buffer = &display_map.buffer_snapshot;
 3214        let position = display_map.clip_point(position, Bias::Left);
 3215
 3216        let start;
 3217        let end;
 3218        let mode;
 3219        let mut auto_scroll;
 3220        match click_count {
 3221            1 => {
 3222                start = buffer.anchor_before(position.to_point(&display_map));
 3223                end = start;
 3224                mode = SelectMode::Character;
 3225                auto_scroll = true;
 3226            }
 3227            2 => {
 3228                let range = movement::surrounding_word(&display_map, position);
 3229                start = buffer.anchor_before(range.start.to_point(&display_map));
 3230                end = buffer.anchor_before(range.end.to_point(&display_map));
 3231                mode = SelectMode::Word(start..end);
 3232                auto_scroll = true;
 3233            }
 3234            3 => {
 3235                let position = display_map
 3236                    .clip_point(position, Bias::Left)
 3237                    .to_point(&display_map);
 3238                let line_start = display_map.prev_line_boundary(position).0;
 3239                let next_line_start = buffer.clip_point(
 3240                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3241                    Bias::Left,
 3242                );
 3243                start = buffer.anchor_before(line_start);
 3244                end = buffer.anchor_before(next_line_start);
 3245                mode = SelectMode::Line(start..end);
 3246                auto_scroll = true;
 3247            }
 3248            _ => {
 3249                start = buffer.anchor_before(0);
 3250                end = buffer.anchor_before(buffer.len());
 3251                mode = SelectMode::All;
 3252                auto_scroll = false;
 3253            }
 3254        }
 3255        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3256
 3257        let point_to_delete: Option<usize> = {
 3258            let selected_points: Vec<Selection<Point>> =
 3259                self.selections.disjoint_in_range(start..end, cx);
 3260
 3261            if !add || click_count > 1 {
 3262                None
 3263            } else if !selected_points.is_empty() {
 3264                Some(selected_points[0].id)
 3265            } else {
 3266                let clicked_point_already_selected =
 3267                    self.selections.disjoint.iter().find(|selection| {
 3268                        selection.start.to_point(buffer) == start.to_point(buffer)
 3269                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3270                    });
 3271
 3272                clicked_point_already_selected.map(|selection| selection.id)
 3273            }
 3274        };
 3275
 3276        let selections_count = self.selections.count();
 3277
 3278        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3279            if let Some(point_to_delete) = point_to_delete {
 3280                s.delete(point_to_delete);
 3281
 3282                if selections_count == 1 {
 3283                    s.set_pending_anchor_range(start..end, mode);
 3284                }
 3285            } else {
 3286                if !add {
 3287                    s.clear_disjoint();
 3288                }
 3289
 3290                s.set_pending_anchor_range(start..end, mode);
 3291            }
 3292        });
 3293    }
 3294
 3295    fn begin_columnar_selection(
 3296        &mut self,
 3297        position: DisplayPoint,
 3298        goal_column: u32,
 3299        reset: bool,
 3300        window: &mut Window,
 3301        cx: &mut Context<Self>,
 3302    ) {
 3303        if !self.focus_handle.is_focused(window) {
 3304            self.last_focused_descendant = None;
 3305            window.focus(&self.focus_handle);
 3306        }
 3307
 3308        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3309
 3310        if reset {
 3311            let pointer_position = display_map
 3312                .buffer_snapshot
 3313                .anchor_before(position.to_point(&display_map));
 3314
 3315            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3316                s.clear_disjoint();
 3317                s.set_pending_anchor_range(
 3318                    pointer_position..pointer_position,
 3319                    SelectMode::Character,
 3320                );
 3321            });
 3322        }
 3323
 3324        let tail = self.selections.newest::<Point>(cx).tail();
 3325        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3326
 3327        if !reset {
 3328            self.select_columns(
 3329                tail.to_display_point(&display_map),
 3330                position,
 3331                goal_column,
 3332                &display_map,
 3333                window,
 3334                cx,
 3335            );
 3336        }
 3337    }
 3338
 3339    fn update_selection(
 3340        &mut self,
 3341        position: DisplayPoint,
 3342        goal_column: u32,
 3343        scroll_delta: gpui::Point<f32>,
 3344        window: &mut Window,
 3345        cx: &mut Context<Self>,
 3346    ) {
 3347        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3348
 3349        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3350            let tail = tail.to_display_point(&display_map);
 3351            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3352        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3353            let buffer = self.buffer.read(cx).snapshot(cx);
 3354            let head;
 3355            let tail;
 3356            let mode = self.selections.pending_mode().unwrap();
 3357            match &mode {
 3358                SelectMode::Character => {
 3359                    head = position.to_point(&display_map);
 3360                    tail = pending.tail().to_point(&buffer);
 3361                }
 3362                SelectMode::Word(original_range) => {
 3363                    let original_display_range = original_range.start.to_display_point(&display_map)
 3364                        ..original_range.end.to_display_point(&display_map);
 3365                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3366                        ..original_display_range.end.to_point(&display_map);
 3367                    if movement::is_inside_word(&display_map, position)
 3368                        || original_display_range.contains(&position)
 3369                    {
 3370                        let word_range = movement::surrounding_word(&display_map, position);
 3371                        if word_range.start < original_display_range.start {
 3372                            head = word_range.start.to_point(&display_map);
 3373                        } else {
 3374                            head = word_range.end.to_point(&display_map);
 3375                        }
 3376                    } else {
 3377                        head = position.to_point(&display_map);
 3378                    }
 3379
 3380                    if head <= original_buffer_range.start {
 3381                        tail = original_buffer_range.end;
 3382                    } else {
 3383                        tail = original_buffer_range.start;
 3384                    }
 3385                }
 3386                SelectMode::Line(original_range) => {
 3387                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3388
 3389                    let position = display_map
 3390                        .clip_point(position, Bias::Left)
 3391                        .to_point(&display_map);
 3392                    let line_start = display_map.prev_line_boundary(position).0;
 3393                    let next_line_start = buffer.clip_point(
 3394                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3395                        Bias::Left,
 3396                    );
 3397
 3398                    if line_start < original_range.start {
 3399                        head = line_start
 3400                    } else {
 3401                        head = next_line_start
 3402                    }
 3403
 3404                    if head <= original_range.start {
 3405                        tail = original_range.end;
 3406                    } else {
 3407                        tail = original_range.start;
 3408                    }
 3409                }
 3410                SelectMode::All => {
 3411                    return;
 3412                }
 3413            };
 3414
 3415            if head < tail {
 3416                pending.start = buffer.anchor_before(head);
 3417                pending.end = buffer.anchor_before(tail);
 3418                pending.reversed = true;
 3419            } else {
 3420                pending.start = buffer.anchor_before(tail);
 3421                pending.end = buffer.anchor_before(head);
 3422                pending.reversed = false;
 3423            }
 3424
 3425            self.change_selections(None, window, cx, |s| {
 3426                s.set_pending(pending, mode);
 3427            });
 3428        } else {
 3429            log::error!("update_selection dispatched with no pending selection");
 3430            return;
 3431        }
 3432
 3433        self.apply_scroll_delta(scroll_delta, window, cx);
 3434        cx.notify();
 3435    }
 3436
 3437    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3438        self.columnar_selection_tail.take();
 3439        if self.selections.pending_anchor().is_some() {
 3440            let selections = self.selections.all::<usize>(cx);
 3441            self.change_selections(None, window, cx, |s| {
 3442                s.select(selections);
 3443                s.clear_pending();
 3444            });
 3445        }
 3446    }
 3447
 3448    fn select_columns(
 3449        &mut self,
 3450        tail: DisplayPoint,
 3451        head: DisplayPoint,
 3452        goal_column: u32,
 3453        display_map: &DisplaySnapshot,
 3454        window: &mut Window,
 3455        cx: &mut Context<Self>,
 3456    ) {
 3457        let start_row = cmp::min(tail.row(), head.row());
 3458        let end_row = cmp::max(tail.row(), head.row());
 3459        let start_column = cmp::min(tail.column(), goal_column);
 3460        let end_column = cmp::max(tail.column(), goal_column);
 3461        let reversed = start_column < tail.column();
 3462
 3463        let selection_ranges = (start_row.0..=end_row.0)
 3464            .map(DisplayRow)
 3465            .filter_map(|row| {
 3466                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 3467                    let start = display_map
 3468                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3469                        .to_point(display_map);
 3470                    let end = display_map
 3471                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3472                        .to_point(display_map);
 3473                    if reversed {
 3474                        Some(end..start)
 3475                    } else {
 3476                        Some(start..end)
 3477                    }
 3478                } else {
 3479                    None
 3480                }
 3481            })
 3482            .collect::<Vec<_>>();
 3483
 3484        self.change_selections(None, window, cx, |s| {
 3485            s.select_ranges(selection_ranges);
 3486        });
 3487        cx.notify();
 3488    }
 3489
 3490    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3491        self.selections
 3492            .all_adjusted(cx)
 3493            .iter()
 3494            .any(|selection| !selection.is_empty())
 3495    }
 3496
 3497    pub fn has_pending_nonempty_selection(&self) -> bool {
 3498        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3499            Some(Selection { start, end, .. }) => start != end,
 3500            None => false,
 3501        };
 3502
 3503        pending_nonempty_selection
 3504            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3505    }
 3506
 3507    pub fn has_pending_selection(&self) -> bool {
 3508        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3509    }
 3510
 3511    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3512        self.selection_mark_mode = false;
 3513
 3514        if self.clear_expanded_diff_hunks(cx) {
 3515            cx.notify();
 3516            return;
 3517        }
 3518        if self.dismiss_menus_and_popups(true, window, cx) {
 3519            return;
 3520        }
 3521
 3522        if self.mode.is_full()
 3523            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3524        {
 3525            return;
 3526        }
 3527
 3528        cx.propagate();
 3529    }
 3530
 3531    pub fn dismiss_menus_and_popups(
 3532        &mut self,
 3533        is_user_requested: bool,
 3534        window: &mut Window,
 3535        cx: &mut Context<Self>,
 3536    ) -> bool {
 3537        if self.take_rename(false, window, cx).is_some() {
 3538            return true;
 3539        }
 3540
 3541        if hide_hover(self, cx) {
 3542            return true;
 3543        }
 3544
 3545        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3546            return true;
 3547        }
 3548
 3549        if self.hide_context_menu(window, cx).is_some() {
 3550            return true;
 3551        }
 3552
 3553        if self.mouse_context_menu.take().is_some() {
 3554            return true;
 3555        }
 3556
 3557        if is_user_requested && self.discard_inline_completion(true, cx) {
 3558            return true;
 3559        }
 3560
 3561        if self.snippet_stack.pop().is_some() {
 3562            return true;
 3563        }
 3564
 3565        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3566            self.dismiss_diagnostics(cx);
 3567            return true;
 3568        }
 3569
 3570        false
 3571    }
 3572
 3573    fn linked_editing_ranges_for(
 3574        &self,
 3575        selection: Range<text::Anchor>,
 3576        cx: &App,
 3577    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3578        if self.linked_edit_ranges.is_empty() {
 3579            return None;
 3580        }
 3581        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3582            selection.end.buffer_id.and_then(|end_buffer_id| {
 3583                if selection.start.buffer_id != Some(end_buffer_id) {
 3584                    return None;
 3585                }
 3586                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3587                let snapshot = buffer.read(cx).snapshot();
 3588                self.linked_edit_ranges
 3589                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3590                    .map(|ranges| (ranges, snapshot, buffer))
 3591            })?;
 3592        use text::ToOffset as TO;
 3593        // find offset from the start of current range to current cursor position
 3594        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3595
 3596        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3597        let start_difference = start_offset - start_byte_offset;
 3598        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3599        let end_difference = end_offset - start_byte_offset;
 3600        // Current range has associated linked ranges.
 3601        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3602        for range in linked_ranges.iter() {
 3603            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3604            let end_offset = start_offset + end_difference;
 3605            let start_offset = start_offset + start_difference;
 3606            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3607                continue;
 3608            }
 3609            if self.selections.disjoint_anchor_ranges().any(|s| {
 3610                if s.start.buffer_id != selection.start.buffer_id
 3611                    || s.end.buffer_id != selection.end.buffer_id
 3612                {
 3613                    return false;
 3614                }
 3615                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3616                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3617            }) {
 3618                continue;
 3619            }
 3620            let start = buffer_snapshot.anchor_after(start_offset);
 3621            let end = buffer_snapshot.anchor_after(end_offset);
 3622            linked_edits
 3623                .entry(buffer.clone())
 3624                .or_default()
 3625                .push(start..end);
 3626        }
 3627        Some(linked_edits)
 3628    }
 3629
 3630    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3631        let text: Arc<str> = text.into();
 3632
 3633        if self.read_only(cx) {
 3634            return;
 3635        }
 3636
 3637        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3638
 3639        let selections = self.selections.all_adjusted(cx);
 3640        let mut bracket_inserted = false;
 3641        let mut edits = Vec::new();
 3642        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3643        let mut new_selections = Vec::with_capacity(selections.len());
 3644        let mut new_autoclose_regions = Vec::new();
 3645        let snapshot = self.buffer.read(cx).read(cx);
 3646        let mut clear_linked_edit_ranges = false;
 3647
 3648        for (selection, autoclose_region) in
 3649            self.selections_with_autoclose_regions(selections, &snapshot)
 3650        {
 3651            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3652                // Determine if the inserted text matches the opening or closing
 3653                // bracket of any of this language's bracket pairs.
 3654                let mut bracket_pair = None;
 3655                let mut is_bracket_pair_start = false;
 3656                let mut is_bracket_pair_end = false;
 3657                if !text.is_empty() {
 3658                    let mut bracket_pair_matching_end = None;
 3659                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3660                    //  and they are removing the character that triggered IME popup.
 3661                    for (pair, enabled) in scope.brackets() {
 3662                        if !pair.close && !pair.surround {
 3663                            continue;
 3664                        }
 3665
 3666                        if enabled && pair.start.ends_with(text.as_ref()) {
 3667                            let prefix_len = pair.start.len() - text.len();
 3668                            let preceding_text_matches_prefix = prefix_len == 0
 3669                                || (selection.start.column >= (prefix_len as u32)
 3670                                    && snapshot.contains_str_at(
 3671                                        Point::new(
 3672                                            selection.start.row,
 3673                                            selection.start.column - (prefix_len as u32),
 3674                                        ),
 3675                                        &pair.start[..prefix_len],
 3676                                    ));
 3677                            if preceding_text_matches_prefix {
 3678                                bracket_pair = Some(pair.clone());
 3679                                is_bracket_pair_start = true;
 3680                                break;
 3681                            }
 3682                        }
 3683                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3684                        {
 3685                            // take first bracket pair matching end, but don't break in case a later bracket
 3686                            // pair matches start
 3687                            bracket_pair_matching_end = Some(pair.clone());
 3688                        }
 3689                    }
 3690                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3691                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3692                        is_bracket_pair_end = true;
 3693                    }
 3694                }
 3695
 3696                if let Some(bracket_pair) = bracket_pair {
 3697                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3698                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3699                    let auto_surround =
 3700                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3701                    if selection.is_empty() {
 3702                        if is_bracket_pair_start {
 3703                            // If the inserted text is a suffix of an opening bracket and the
 3704                            // selection is preceded by the rest of the opening bracket, then
 3705                            // insert the closing bracket.
 3706                            let following_text_allows_autoclose = snapshot
 3707                                .chars_at(selection.start)
 3708                                .next()
 3709                                .map_or(true, |c| scope.should_autoclose_before(c));
 3710
 3711                            let preceding_text_allows_autoclose = selection.start.column == 0
 3712                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3713                                    true,
 3714                                    |c| {
 3715                                        bracket_pair.start != bracket_pair.end
 3716                                            || !snapshot
 3717                                                .char_classifier_at(selection.start)
 3718                                                .is_word(c)
 3719                                    },
 3720                                );
 3721
 3722                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3723                                && bracket_pair.start.len() == 1
 3724                            {
 3725                                let target = bracket_pair.start.chars().next().unwrap();
 3726                                let current_line_count = snapshot
 3727                                    .reversed_chars_at(selection.start)
 3728                                    .take_while(|&c| c != '\n')
 3729                                    .filter(|&c| c == target)
 3730                                    .count();
 3731                                current_line_count % 2 == 1
 3732                            } else {
 3733                                false
 3734                            };
 3735
 3736                            if autoclose
 3737                                && bracket_pair.close
 3738                                && following_text_allows_autoclose
 3739                                && preceding_text_allows_autoclose
 3740                                && !is_closing_quote
 3741                            {
 3742                                let anchor = snapshot.anchor_before(selection.end);
 3743                                new_selections.push((selection.map(|_| anchor), text.len()));
 3744                                new_autoclose_regions.push((
 3745                                    anchor,
 3746                                    text.len(),
 3747                                    selection.id,
 3748                                    bracket_pair.clone(),
 3749                                ));
 3750                                edits.push((
 3751                                    selection.range(),
 3752                                    format!("{}{}", text, bracket_pair.end).into(),
 3753                                ));
 3754                                bracket_inserted = true;
 3755                                continue;
 3756                            }
 3757                        }
 3758
 3759                        if let Some(region) = autoclose_region {
 3760                            // If the selection is followed by an auto-inserted closing bracket,
 3761                            // then don't insert that closing bracket again; just move the selection
 3762                            // past the closing bracket.
 3763                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3764                                && text.as_ref() == region.pair.end.as_str();
 3765                            if should_skip {
 3766                                let anchor = snapshot.anchor_after(selection.end);
 3767                                new_selections
 3768                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3769                                continue;
 3770                            }
 3771                        }
 3772
 3773                        let always_treat_brackets_as_autoclosed = snapshot
 3774                            .language_settings_at(selection.start, cx)
 3775                            .always_treat_brackets_as_autoclosed;
 3776                        if always_treat_brackets_as_autoclosed
 3777                            && is_bracket_pair_end
 3778                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3779                        {
 3780                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3781                            // and the inserted text is a closing bracket and the selection is followed
 3782                            // by the closing bracket then move the selection past the closing bracket.
 3783                            let anchor = snapshot.anchor_after(selection.end);
 3784                            new_selections.push((selection.map(|_| anchor), text.len()));
 3785                            continue;
 3786                        }
 3787                    }
 3788                    // If an opening bracket is 1 character long and is typed while
 3789                    // text is selected, then surround that text with the bracket pair.
 3790                    else if auto_surround
 3791                        && bracket_pair.surround
 3792                        && is_bracket_pair_start
 3793                        && bracket_pair.start.chars().count() == 1
 3794                    {
 3795                        edits.push((selection.start..selection.start, text.clone()));
 3796                        edits.push((
 3797                            selection.end..selection.end,
 3798                            bracket_pair.end.as_str().into(),
 3799                        ));
 3800                        bracket_inserted = true;
 3801                        new_selections.push((
 3802                            Selection {
 3803                                id: selection.id,
 3804                                start: snapshot.anchor_after(selection.start),
 3805                                end: snapshot.anchor_before(selection.end),
 3806                                reversed: selection.reversed,
 3807                                goal: selection.goal,
 3808                            },
 3809                            0,
 3810                        ));
 3811                        continue;
 3812                    }
 3813                }
 3814            }
 3815
 3816            if self.auto_replace_emoji_shortcode
 3817                && selection.is_empty()
 3818                && text.as_ref().ends_with(':')
 3819            {
 3820                if let Some(possible_emoji_short_code) =
 3821                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3822                {
 3823                    if !possible_emoji_short_code.is_empty() {
 3824                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3825                            let emoji_shortcode_start = Point::new(
 3826                                selection.start.row,
 3827                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3828                            );
 3829
 3830                            // Remove shortcode from buffer
 3831                            edits.push((
 3832                                emoji_shortcode_start..selection.start,
 3833                                "".to_string().into(),
 3834                            ));
 3835                            new_selections.push((
 3836                                Selection {
 3837                                    id: selection.id,
 3838                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3839                                    end: snapshot.anchor_before(selection.start),
 3840                                    reversed: selection.reversed,
 3841                                    goal: selection.goal,
 3842                                },
 3843                                0,
 3844                            ));
 3845
 3846                            // Insert emoji
 3847                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3848                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3849                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3850
 3851                            continue;
 3852                        }
 3853                    }
 3854                }
 3855            }
 3856
 3857            // If not handling any auto-close operation, then just replace the selected
 3858            // text with the given input and move the selection to the end of the
 3859            // newly inserted text.
 3860            let anchor = snapshot.anchor_after(selection.end);
 3861            if !self.linked_edit_ranges.is_empty() {
 3862                let start_anchor = snapshot.anchor_before(selection.start);
 3863
 3864                let is_word_char = text.chars().next().map_or(true, |char| {
 3865                    let classifier = snapshot
 3866                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3867                        .ignore_punctuation(true);
 3868                    classifier.is_word(char)
 3869                });
 3870
 3871                if is_word_char {
 3872                    if let Some(ranges) = self
 3873                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3874                    {
 3875                        for (buffer, edits) in ranges {
 3876                            linked_edits
 3877                                .entry(buffer.clone())
 3878                                .or_default()
 3879                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3880                        }
 3881                    }
 3882                } else {
 3883                    clear_linked_edit_ranges = true;
 3884                }
 3885            }
 3886
 3887            new_selections.push((selection.map(|_| anchor), 0));
 3888            edits.push((selection.start..selection.end, text.clone()));
 3889        }
 3890
 3891        drop(snapshot);
 3892
 3893        self.transact(window, cx, |this, window, cx| {
 3894            if clear_linked_edit_ranges {
 3895                this.linked_edit_ranges.clear();
 3896            }
 3897            let initial_buffer_versions =
 3898                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3899
 3900            this.buffer.update(cx, |buffer, cx| {
 3901                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3902            });
 3903            for (buffer, edits) in linked_edits {
 3904                buffer.update(cx, |buffer, cx| {
 3905                    let snapshot = buffer.snapshot();
 3906                    let edits = edits
 3907                        .into_iter()
 3908                        .map(|(range, text)| {
 3909                            use text::ToPoint as TP;
 3910                            let end_point = TP::to_point(&range.end, &snapshot);
 3911                            let start_point = TP::to_point(&range.start, &snapshot);
 3912                            (start_point..end_point, text)
 3913                        })
 3914                        .sorted_by_key(|(range, _)| range.start);
 3915                    buffer.edit(edits, None, cx);
 3916                })
 3917            }
 3918            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3919            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3920            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3921            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3922                .zip(new_selection_deltas)
 3923                .map(|(selection, delta)| Selection {
 3924                    id: selection.id,
 3925                    start: selection.start + delta,
 3926                    end: selection.end + delta,
 3927                    reversed: selection.reversed,
 3928                    goal: SelectionGoal::None,
 3929                })
 3930                .collect::<Vec<_>>();
 3931
 3932            let mut i = 0;
 3933            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3934                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3935                let start = map.buffer_snapshot.anchor_before(position);
 3936                let end = map.buffer_snapshot.anchor_after(position);
 3937                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3938                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3939                        Ordering::Less => i += 1,
 3940                        Ordering::Greater => break,
 3941                        Ordering::Equal => {
 3942                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3943                                Ordering::Less => i += 1,
 3944                                Ordering::Equal => break,
 3945                                Ordering::Greater => break,
 3946                            }
 3947                        }
 3948                    }
 3949                }
 3950                this.autoclose_regions.insert(
 3951                    i,
 3952                    AutocloseRegion {
 3953                        selection_id,
 3954                        range: start..end,
 3955                        pair,
 3956                    },
 3957                );
 3958            }
 3959
 3960            let had_active_inline_completion = this.has_active_inline_completion();
 3961            this.change_selections_without_showing_completions(
 3962                Some(Autoscroll::fit()),
 3963                window,
 3964                cx,
 3965                |s| s.select(new_selections),
 3966            );
 3967
 3968            if !bracket_inserted {
 3969                if let Some(on_type_format_task) =
 3970                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3971                {
 3972                    on_type_format_task.detach_and_log_err(cx);
 3973                }
 3974            }
 3975
 3976            let editor_settings = EditorSettings::get_global(cx);
 3977            if bracket_inserted
 3978                && (editor_settings.auto_signature_help
 3979                    || editor_settings.show_signature_help_after_edits)
 3980            {
 3981                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3982            }
 3983
 3984            let trigger_in_words =
 3985                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3986            if this.hard_wrap.is_some() {
 3987                let latest: Range<Point> = this.selections.newest(cx).range();
 3988                if latest.is_empty()
 3989                    && this
 3990                        .buffer()
 3991                        .read(cx)
 3992                        .snapshot(cx)
 3993                        .line_len(MultiBufferRow(latest.start.row))
 3994                        == latest.start.column
 3995                {
 3996                    this.rewrap_impl(
 3997                        RewrapOptions {
 3998                            override_language_settings: true,
 3999                            preserve_existing_whitespace: true,
 4000                        },
 4001                        cx,
 4002                    )
 4003                }
 4004            }
 4005            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4006            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4007            this.refresh_inline_completion(true, false, window, cx);
 4008            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4009        });
 4010    }
 4011
 4012    fn find_possible_emoji_shortcode_at_position(
 4013        snapshot: &MultiBufferSnapshot,
 4014        position: Point,
 4015    ) -> Option<String> {
 4016        let mut chars = Vec::new();
 4017        let mut found_colon = false;
 4018        for char in snapshot.reversed_chars_at(position).take(100) {
 4019            // Found a possible emoji shortcode in the middle of the buffer
 4020            if found_colon {
 4021                if char.is_whitespace() {
 4022                    chars.reverse();
 4023                    return Some(chars.iter().collect());
 4024                }
 4025                // If the previous character is not a whitespace, we are in the middle of a word
 4026                // and we only want to complete the shortcode if the word is made up of other emojis
 4027                let mut containing_word = String::new();
 4028                for ch in snapshot
 4029                    .reversed_chars_at(position)
 4030                    .skip(chars.len() + 1)
 4031                    .take(100)
 4032                {
 4033                    if ch.is_whitespace() {
 4034                        break;
 4035                    }
 4036                    containing_word.push(ch);
 4037                }
 4038                let containing_word = containing_word.chars().rev().collect::<String>();
 4039                if util::word_consists_of_emojis(containing_word.as_str()) {
 4040                    chars.reverse();
 4041                    return Some(chars.iter().collect());
 4042                }
 4043            }
 4044
 4045            if char.is_whitespace() || !char.is_ascii() {
 4046                return None;
 4047            }
 4048            if char == ':' {
 4049                found_colon = true;
 4050            } else {
 4051                chars.push(char);
 4052            }
 4053        }
 4054        // Found a possible emoji shortcode at the beginning of the buffer
 4055        chars.reverse();
 4056        Some(chars.iter().collect())
 4057    }
 4058
 4059    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4060        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4061        self.transact(window, cx, |this, window, cx| {
 4062            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4063                let selections = this.selections.all::<usize>(cx);
 4064                let multi_buffer = this.buffer.read(cx);
 4065                let buffer = multi_buffer.snapshot(cx);
 4066                selections
 4067                    .iter()
 4068                    .map(|selection| {
 4069                        let start_point = selection.start.to_point(&buffer);
 4070                        let mut existing_indent =
 4071                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4072                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4073                        let start = selection.start;
 4074                        let end = selection.end;
 4075                        let selection_is_empty = start == end;
 4076                        let language_scope = buffer.language_scope_at(start);
 4077                        let (
 4078                            comment_delimiter,
 4079                            doc_delimiter,
 4080                            insert_extra_newline,
 4081                            indent_on_newline,
 4082                            indent_on_extra_newline,
 4083                        ) = if let Some(language) = &language_scope {
 4084                            let mut insert_extra_newline =
 4085                                insert_extra_newline_brackets(&buffer, start..end, language)
 4086                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4087
 4088                            // Comment extension on newline is allowed only for cursor selections
 4089                            let comment_delimiter = maybe!({
 4090                                if !selection_is_empty {
 4091                                    return None;
 4092                                }
 4093
 4094                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4095                                    return None;
 4096                                }
 4097
 4098                                let delimiters = language.line_comment_prefixes();
 4099                                let max_len_of_delimiter =
 4100                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4101                                let (snapshot, range) =
 4102                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4103
 4104                                let num_of_whitespaces = snapshot
 4105                                    .chars_for_range(range.clone())
 4106                                    .take_while(|c| c.is_whitespace())
 4107                                    .count();
 4108                                let comment_candidate = snapshot
 4109                                    .chars_for_range(range)
 4110                                    .skip(num_of_whitespaces)
 4111                                    .take(max_len_of_delimiter)
 4112                                    .collect::<String>();
 4113                                let (delimiter, trimmed_len) = delimiters
 4114                                    .iter()
 4115                                    .filter_map(|delimiter| {
 4116                                        let prefix = delimiter.trim_end();
 4117                                        if comment_candidate.starts_with(prefix) {
 4118                                            Some((delimiter, prefix.len()))
 4119                                        } else {
 4120                                            None
 4121                                        }
 4122                                    })
 4123                                    .max_by_key(|(_, len)| *len)?;
 4124
 4125                                let cursor_is_placed_after_comment_marker =
 4126                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4127                                if cursor_is_placed_after_comment_marker {
 4128                                    Some(delimiter.clone())
 4129                                } else {
 4130                                    None
 4131                                }
 4132                            });
 4133
 4134                            let mut indent_on_newline = IndentSize::spaces(0);
 4135                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4136
 4137                            let doc_delimiter = maybe!({
 4138                                if !selection_is_empty {
 4139                                    return None;
 4140                                }
 4141
 4142                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4143                                    return None;
 4144                                }
 4145
 4146                                let DocumentationConfig {
 4147                                    start: start_tag,
 4148                                    end: end_tag,
 4149                                    prefix: delimiter,
 4150                                    tab_size: len,
 4151                                } = language.documentation()?;
 4152
 4153                                let is_within_block_comment = buffer
 4154                                    .language_scope_at(start_point)
 4155                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4156                                if !is_within_block_comment {
 4157                                    return None;
 4158                                }
 4159
 4160                                let (snapshot, range) =
 4161                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4162
 4163                                let num_of_whitespaces = snapshot
 4164                                    .chars_for_range(range.clone())
 4165                                    .take_while(|c| c.is_whitespace())
 4166                                    .count();
 4167
 4168                                // 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.
 4169                                let column = start_point.column;
 4170                                let cursor_is_after_start_tag = {
 4171                                    let start_tag_len = start_tag.len();
 4172                                    let start_tag_line = snapshot
 4173                                        .chars_for_range(range.clone())
 4174                                        .skip(num_of_whitespaces)
 4175                                        .take(start_tag_len)
 4176                                        .collect::<String>();
 4177                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4178                                        num_of_whitespaces + start_tag_len <= column as usize
 4179                                    } else {
 4180                                        false
 4181                                    }
 4182                                };
 4183
 4184                                let cursor_is_after_delimiter = {
 4185                                    let delimiter_trim = delimiter.trim_end();
 4186                                    let delimiter_line = snapshot
 4187                                        .chars_for_range(range.clone())
 4188                                        .skip(num_of_whitespaces)
 4189                                        .take(delimiter_trim.len())
 4190                                        .collect::<String>();
 4191                                    if delimiter_line.starts_with(delimiter_trim) {
 4192                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4193                                    } else {
 4194                                        false
 4195                                    }
 4196                                };
 4197
 4198                                let cursor_is_before_end_tag_if_exists = {
 4199                                    let mut char_position = 0u32;
 4200                                    let mut end_tag_offset = None;
 4201
 4202                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4203                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4204                                            let chars_before_match =
 4205                                                chunk[..byte_pos].chars().count() as u32;
 4206                                            end_tag_offset =
 4207                                                Some(char_position + chars_before_match);
 4208                                            break 'outer;
 4209                                        }
 4210                                        char_position += chunk.chars().count() as u32;
 4211                                    }
 4212
 4213                                    if let Some(end_tag_offset) = end_tag_offset {
 4214                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4215                                        if cursor_is_after_start_tag {
 4216                                            if cursor_is_before_end_tag {
 4217                                                insert_extra_newline = true;
 4218                                            }
 4219                                            let cursor_is_at_start_of_end_tag =
 4220                                                column == end_tag_offset;
 4221                                            if cursor_is_at_start_of_end_tag {
 4222                                                indent_on_extra_newline.len = (*len).into();
 4223                                            }
 4224                                        }
 4225                                        cursor_is_before_end_tag
 4226                                    } else {
 4227                                        true
 4228                                    }
 4229                                };
 4230
 4231                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4232                                    && cursor_is_before_end_tag_if_exists
 4233                                {
 4234                                    if cursor_is_after_start_tag {
 4235                                        indent_on_newline.len = (*len).into();
 4236                                    }
 4237                                    Some(delimiter.clone())
 4238                                } else {
 4239                                    None
 4240                                }
 4241                            });
 4242
 4243                            (
 4244                                comment_delimiter,
 4245                                doc_delimiter,
 4246                                insert_extra_newline,
 4247                                indent_on_newline,
 4248                                indent_on_extra_newline,
 4249                            )
 4250                        } else {
 4251                            (
 4252                                None,
 4253                                None,
 4254                                false,
 4255                                IndentSize::default(),
 4256                                IndentSize::default(),
 4257                            )
 4258                        };
 4259
 4260                        let prevent_auto_indent = doc_delimiter.is_some();
 4261                        let delimiter = comment_delimiter.or(doc_delimiter);
 4262
 4263                        let capacity_for_delimiter =
 4264                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4265                        let mut new_text = String::with_capacity(
 4266                            1 + capacity_for_delimiter
 4267                                + existing_indent.len as usize
 4268                                + indent_on_newline.len as usize
 4269                                + indent_on_extra_newline.len as usize,
 4270                        );
 4271                        new_text.push('\n');
 4272                        new_text.extend(existing_indent.chars());
 4273                        new_text.extend(indent_on_newline.chars());
 4274
 4275                        if let Some(delimiter) = &delimiter {
 4276                            new_text.push_str(delimiter);
 4277                        }
 4278
 4279                        if insert_extra_newline {
 4280                            new_text.push('\n');
 4281                            new_text.extend(existing_indent.chars());
 4282                            new_text.extend(indent_on_extra_newline.chars());
 4283                        }
 4284
 4285                        let anchor = buffer.anchor_after(end);
 4286                        let new_selection = selection.map(|_| anchor);
 4287                        (
 4288                            ((start..end, new_text), prevent_auto_indent),
 4289                            (insert_extra_newline, new_selection),
 4290                        )
 4291                    })
 4292                    .unzip()
 4293            };
 4294
 4295            let mut auto_indent_edits = Vec::new();
 4296            let mut edits = Vec::new();
 4297            for (edit, prevent_auto_indent) in edits_with_flags {
 4298                if prevent_auto_indent {
 4299                    edits.push(edit);
 4300                } else {
 4301                    auto_indent_edits.push(edit);
 4302                }
 4303            }
 4304            if !edits.is_empty() {
 4305                this.edit(edits, cx);
 4306            }
 4307            if !auto_indent_edits.is_empty() {
 4308                this.edit_with_autoindent(auto_indent_edits, cx);
 4309            }
 4310
 4311            let buffer = this.buffer.read(cx).snapshot(cx);
 4312            let new_selections = selection_info
 4313                .into_iter()
 4314                .map(|(extra_newline_inserted, new_selection)| {
 4315                    let mut cursor = new_selection.end.to_point(&buffer);
 4316                    if extra_newline_inserted {
 4317                        cursor.row -= 1;
 4318                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4319                    }
 4320                    new_selection.map(|_| cursor)
 4321                })
 4322                .collect();
 4323
 4324            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4325                s.select(new_selections)
 4326            });
 4327            this.refresh_inline_completion(true, false, window, cx);
 4328        });
 4329    }
 4330
 4331    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4332        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4333
 4334        let buffer = self.buffer.read(cx);
 4335        let snapshot = buffer.snapshot(cx);
 4336
 4337        let mut edits = Vec::new();
 4338        let mut rows = Vec::new();
 4339
 4340        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4341            let cursor = selection.head();
 4342            let row = cursor.row;
 4343
 4344            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4345
 4346            let newline = "\n".to_string();
 4347            edits.push((start_of_line..start_of_line, newline));
 4348
 4349            rows.push(row + rows_inserted as u32);
 4350        }
 4351
 4352        self.transact(window, cx, |editor, window, cx| {
 4353            editor.edit(edits, cx);
 4354
 4355            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4356                let mut index = 0;
 4357                s.move_cursors_with(|map, _, _| {
 4358                    let row = rows[index];
 4359                    index += 1;
 4360
 4361                    let point = Point::new(row, 0);
 4362                    let boundary = map.next_line_boundary(point).1;
 4363                    let clipped = map.clip_point(boundary, Bias::Left);
 4364
 4365                    (clipped, SelectionGoal::None)
 4366                });
 4367            });
 4368
 4369            let mut indent_edits = Vec::new();
 4370            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4371            for row in rows {
 4372                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4373                for (row, indent) in indents {
 4374                    if indent.len == 0 {
 4375                        continue;
 4376                    }
 4377
 4378                    let text = match indent.kind {
 4379                        IndentKind::Space => " ".repeat(indent.len as usize),
 4380                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4381                    };
 4382                    let point = Point::new(row.0, 0);
 4383                    indent_edits.push((point..point, text));
 4384                }
 4385            }
 4386            editor.edit(indent_edits, cx);
 4387        });
 4388    }
 4389
 4390    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4391        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4392
 4393        let buffer = self.buffer.read(cx);
 4394        let snapshot = buffer.snapshot(cx);
 4395
 4396        let mut edits = Vec::new();
 4397        let mut rows = Vec::new();
 4398        let mut rows_inserted = 0;
 4399
 4400        for selection in self.selections.all_adjusted(cx) {
 4401            let cursor = selection.head();
 4402            let row = cursor.row;
 4403
 4404            let point = Point::new(row + 1, 0);
 4405            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4406
 4407            let newline = "\n".to_string();
 4408            edits.push((start_of_line..start_of_line, newline));
 4409
 4410            rows_inserted += 1;
 4411            rows.push(row + rows_inserted);
 4412        }
 4413
 4414        self.transact(window, cx, |editor, window, cx| {
 4415            editor.edit(edits, cx);
 4416
 4417            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4418                let mut index = 0;
 4419                s.move_cursors_with(|map, _, _| {
 4420                    let row = rows[index];
 4421                    index += 1;
 4422
 4423                    let point = Point::new(row, 0);
 4424                    let boundary = map.next_line_boundary(point).1;
 4425                    let clipped = map.clip_point(boundary, Bias::Left);
 4426
 4427                    (clipped, SelectionGoal::None)
 4428                });
 4429            });
 4430
 4431            let mut indent_edits = Vec::new();
 4432            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4433            for row in rows {
 4434                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4435                for (row, indent) in indents {
 4436                    if indent.len == 0 {
 4437                        continue;
 4438                    }
 4439
 4440                    let text = match indent.kind {
 4441                        IndentKind::Space => " ".repeat(indent.len as usize),
 4442                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4443                    };
 4444                    let point = Point::new(row.0, 0);
 4445                    indent_edits.push((point..point, text));
 4446                }
 4447            }
 4448            editor.edit(indent_edits, cx);
 4449        });
 4450    }
 4451
 4452    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4453        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4454            original_indent_columns: Vec::new(),
 4455        });
 4456        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4457    }
 4458
 4459    fn insert_with_autoindent_mode(
 4460        &mut self,
 4461        text: &str,
 4462        autoindent_mode: Option<AutoindentMode>,
 4463        window: &mut Window,
 4464        cx: &mut Context<Self>,
 4465    ) {
 4466        if self.read_only(cx) {
 4467            return;
 4468        }
 4469
 4470        let text: Arc<str> = text.into();
 4471        self.transact(window, cx, |this, window, cx| {
 4472            let old_selections = this.selections.all_adjusted(cx);
 4473            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4474                let anchors = {
 4475                    let snapshot = buffer.read(cx);
 4476                    old_selections
 4477                        .iter()
 4478                        .map(|s| {
 4479                            let anchor = snapshot.anchor_after(s.head());
 4480                            s.map(|_| anchor)
 4481                        })
 4482                        .collect::<Vec<_>>()
 4483                };
 4484                buffer.edit(
 4485                    old_selections
 4486                        .iter()
 4487                        .map(|s| (s.start..s.end, text.clone())),
 4488                    autoindent_mode,
 4489                    cx,
 4490                );
 4491                anchors
 4492            });
 4493
 4494            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4495                s.select_anchors(selection_anchors);
 4496            });
 4497
 4498            cx.notify();
 4499        });
 4500    }
 4501
 4502    fn trigger_completion_on_input(
 4503        &mut self,
 4504        text: &str,
 4505        trigger_in_words: bool,
 4506        window: &mut Window,
 4507        cx: &mut Context<Self>,
 4508    ) {
 4509        let ignore_completion_provider = self
 4510            .context_menu
 4511            .borrow()
 4512            .as_ref()
 4513            .map(|menu| match menu {
 4514                CodeContextMenu::Completions(completions_menu) => {
 4515                    completions_menu.ignore_completion_provider
 4516                }
 4517                CodeContextMenu::CodeActions(_) => false,
 4518            })
 4519            .unwrap_or(false);
 4520
 4521        if ignore_completion_provider {
 4522            self.show_word_completions(&ShowWordCompletions, window, cx);
 4523        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 4524            self.show_completions(
 4525                &ShowCompletions {
 4526                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4527                },
 4528                window,
 4529                cx,
 4530            );
 4531        } else {
 4532            self.hide_context_menu(window, cx);
 4533        }
 4534    }
 4535
 4536    fn is_completion_trigger(
 4537        &self,
 4538        text: &str,
 4539        trigger_in_words: bool,
 4540        cx: &mut Context<Self>,
 4541    ) -> bool {
 4542        let position = self.selections.newest_anchor().head();
 4543        let multibuffer = self.buffer.read(cx);
 4544        let Some(buffer) = position
 4545            .buffer_id
 4546            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4547        else {
 4548            return false;
 4549        };
 4550
 4551        if let Some(completion_provider) = &self.completion_provider {
 4552            completion_provider.is_completion_trigger(
 4553                &buffer,
 4554                position.text_anchor,
 4555                text,
 4556                trigger_in_words,
 4557                cx,
 4558            )
 4559        } else {
 4560            false
 4561        }
 4562    }
 4563
 4564    /// If any empty selections is touching the start of its innermost containing autoclose
 4565    /// region, expand it to select the brackets.
 4566    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4567        let selections = self.selections.all::<usize>(cx);
 4568        let buffer = self.buffer.read(cx).read(cx);
 4569        let new_selections = self
 4570            .selections_with_autoclose_regions(selections, &buffer)
 4571            .map(|(mut selection, region)| {
 4572                if !selection.is_empty() {
 4573                    return selection;
 4574                }
 4575
 4576                if let Some(region) = region {
 4577                    let mut range = region.range.to_offset(&buffer);
 4578                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4579                        range.start -= region.pair.start.len();
 4580                        if buffer.contains_str_at(range.start, &region.pair.start)
 4581                            && buffer.contains_str_at(range.end, &region.pair.end)
 4582                        {
 4583                            range.end += region.pair.end.len();
 4584                            selection.start = range.start;
 4585                            selection.end = range.end;
 4586
 4587                            return selection;
 4588                        }
 4589                    }
 4590                }
 4591
 4592                let always_treat_brackets_as_autoclosed = buffer
 4593                    .language_settings_at(selection.start, cx)
 4594                    .always_treat_brackets_as_autoclosed;
 4595
 4596                if !always_treat_brackets_as_autoclosed {
 4597                    return selection;
 4598                }
 4599
 4600                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4601                    for (pair, enabled) in scope.brackets() {
 4602                        if !enabled || !pair.close {
 4603                            continue;
 4604                        }
 4605
 4606                        if buffer.contains_str_at(selection.start, &pair.end) {
 4607                            let pair_start_len = pair.start.len();
 4608                            if buffer.contains_str_at(
 4609                                selection.start.saturating_sub(pair_start_len),
 4610                                &pair.start,
 4611                            ) {
 4612                                selection.start -= pair_start_len;
 4613                                selection.end += pair.end.len();
 4614
 4615                                return selection;
 4616                            }
 4617                        }
 4618                    }
 4619                }
 4620
 4621                selection
 4622            })
 4623            .collect();
 4624
 4625        drop(buffer);
 4626        self.change_selections(None, window, cx, |selections| {
 4627            selections.select(new_selections)
 4628        });
 4629    }
 4630
 4631    /// Iterate the given selections, and for each one, find the smallest surrounding
 4632    /// autoclose region. This uses the ordering of the selections and the autoclose
 4633    /// regions to avoid repeated comparisons.
 4634    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4635        &'a self,
 4636        selections: impl IntoIterator<Item = Selection<D>>,
 4637        buffer: &'a MultiBufferSnapshot,
 4638    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4639        let mut i = 0;
 4640        let mut regions = self.autoclose_regions.as_slice();
 4641        selections.into_iter().map(move |selection| {
 4642            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4643
 4644            let mut enclosing = None;
 4645            while let Some(pair_state) = regions.get(i) {
 4646                if pair_state.range.end.to_offset(buffer) < range.start {
 4647                    regions = &regions[i + 1..];
 4648                    i = 0;
 4649                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4650                    break;
 4651                } else {
 4652                    if pair_state.selection_id == selection.id {
 4653                        enclosing = Some(pair_state);
 4654                    }
 4655                    i += 1;
 4656                }
 4657            }
 4658
 4659            (selection, enclosing)
 4660        })
 4661    }
 4662
 4663    /// Remove any autoclose regions that no longer contain their selection.
 4664    fn invalidate_autoclose_regions(
 4665        &mut self,
 4666        mut selections: &[Selection<Anchor>],
 4667        buffer: &MultiBufferSnapshot,
 4668    ) {
 4669        self.autoclose_regions.retain(|state| {
 4670            let mut i = 0;
 4671            while let Some(selection) = selections.get(i) {
 4672                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4673                    selections = &selections[1..];
 4674                    continue;
 4675                }
 4676                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4677                    break;
 4678                }
 4679                if selection.id == state.selection_id {
 4680                    return true;
 4681                } else {
 4682                    i += 1;
 4683                }
 4684            }
 4685            false
 4686        });
 4687    }
 4688
 4689    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4690        let offset = position.to_offset(buffer);
 4691        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4692        if offset > word_range.start && kind == Some(CharKind::Word) {
 4693            Some(
 4694                buffer
 4695                    .text_for_range(word_range.start..offset)
 4696                    .collect::<String>(),
 4697            )
 4698        } else {
 4699            None
 4700        }
 4701    }
 4702
 4703    pub fn toggle_inline_values(
 4704        &mut self,
 4705        _: &ToggleInlineValues,
 4706        _: &mut Window,
 4707        cx: &mut Context<Self>,
 4708    ) {
 4709        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4710
 4711        self.refresh_inline_values(cx);
 4712    }
 4713
 4714    pub fn toggle_inlay_hints(
 4715        &mut self,
 4716        _: &ToggleInlayHints,
 4717        _: &mut Window,
 4718        cx: &mut Context<Self>,
 4719    ) {
 4720        self.refresh_inlay_hints(
 4721            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4722            cx,
 4723        );
 4724    }
 4725
 4726    pub fn inlay_hints_enabled(&self) -> bool {
 4727        self.inlay_hint_cache.enabled
 4728    }
 4729
 4730    pub fn inline_values_enabled(&self) -> bool {
 4731        self.inline_value_cache.enabled
 4732    }
 4733
 4734    #[cfg(any(test, feature = "test-support"))]
 4735    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4736        self.display_map
 4737            .read(cx)
 4738            .current_inlays()
 4739            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4740            .cloned()
 4741            .collect()
 4742    }
 4743
 4744    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4745        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4746            return;
 4747        }
 4748
 4749        let reason_description = reason.description();
 4750        let ignore_debounce = matches!(
 4751            reason,
 4752            InlayHintRefreshReason::SettingsChange(_)
 4753                | InlayHintRefreshReason::Toggle(_)
 4754                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4755                | InlayHintRefreshReason::ModifiersChanged(_)
 4756        );
 4757        let (invalidate_cache, required_languages) = match reason {
 4758            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4759                match self.inlay_hint_cache.modifiers_override(enabled) {
 4760                    Some(enabled) => {
 4761                        if enabled {
 4762                            (InvalidationStrategy::RefreshRequested, None)
 4763                        } else {
 4764                            self.splice_inlays(
 4765                                &self
 4766                                    .visible_inlay_hints(cx)
 4767                                    .iter()
 4768                                    .map(|inlay| inlay.id)
 4769                                    .collect::<Vec<InlayId>>(),
 4770                                Vec::new(),
 4771                                cx,
 4772                            );
 4773                            return;
 4774                        }
 4775                    }
 4776                    None => return,
 4777                }
 4778            }
 4779            InlayHintRefreshReason::Toggle(enabled) => {
 4780                if self.inlay_hint_cache.toggle(enabled) {
 4781                    if enabled {
 4782                        (InvalidationStrategy::RefreshRequested, None)
 4783                    } else {
 4784                        self.splice_inlays(
 4785                            &self
 4786                                .visible_inlay_hints(cx)
 4787                                .iter()
 4788                                .map(|inlay| inlay.id)
 4789                                .collect::<Vec<InlayId>>(),
 4790                            Vec::new(),
 4791                            cx,
 4792                        );
 4793                        return;
 4794                    }
 4795                } else {
 4796                    return;
 4797                }
 4798            }
 4799            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4800                match self.inlay_hint_cache.update_settings(
 4801                    &self.buffer,
 4802                    new_settings,
 4803                    self.visible_inlay_hints(cx),
 4804                    cx,
 4805                ) {
 4806                    ControlFlow::Break(Some(InlaySplice {
 4807                        to_remove,
 4808                        to_insert,
 4809                    })) => {
 4810                        self.splice_inlays(&to_remove, to_insert, cx);
 4811                        return;
 4812                    }
 4813                    ControlFlow::Break(None) => return,
 4814                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4815                }
 4816            }
 4817            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4818                if let Some(InlaySplice {
 4819                    to_remove,
 4820                    to_insert,
 4821                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4822                {
 4823                    self.splice_inlays(&to_remove, to_insert, cx);
 4824                }
 4825                self.display_map.update(cx, |display_map, _| {
 4826                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4827                });
 4828                return;
 4829            }
 4830            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4831            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4832                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4833            }
 4834            InlayHintRefreshReason::RefreshRequested => {
 4835                (InvalidationStrategy::RefreshRequested, None)
 4836            }
 4837        };
 4838
 4839        if let Some(InlaySplice {
 4840            to_remove,
 4841            to_insert,
 4842        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4843            reason_description,
 4844            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4845            invalidate_cache,
 4846            ignore_debounce,
 4847            cx,
 4848        ) {
 4849            self.splice_inlays(&to_remove, to_insert, cx);
 4850        }
 4851    }
 4852
 4853    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4854        self.display_map
 4855            .read(cx)
 4856            .current_inlays()
 4857            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4858            .cloned()
 4859            .collect()
 4860    }
 4861
 4862    pub fn excerpts_for_inlay_hints_query(
 4863        &self,
 4864        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4865        cx: &mut Context<Editor>,
 4866    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4867        let Some(project) = self.project.as_ref() else {
 4868            return HashMap::default();
 4869        };
 4870        let project = project.read(cx);
 4871        let multi_buffer = self.buffer().read(cx);
 4872        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4873        let multi_buffer_visible_start = self
 4874            .scroll_manager
 4875            .anchor()
 4876            .anchor
 4877            .to_point(&multi_buffer_snapshot);
 4878        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4879            multi_buffer_visible_start
 4880                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4881            Bias::Left,
 4882        );
 4883        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4884        multi_buffer_snapshot
 4885            .range_to_buffer_ranges(multi_buffer_visible_range)
 4886            .into_iter()
 4887            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4888            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4889                let buffer_file = project::File::from_dyn(buffer.file())?;
 4890                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4891                let worktree_entry = buffer_worktree
 4892                    .read(cx)
 4893                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4894                if worktree_entry.is_ignored {
 4895                    return None;
 4896                }
 4897
 4898                let language = buffer.language()?;
 4899                if let Some(restrict_to_languages) = restrict_to_languages {
 4900                    if !restrict_to_languages.contains(language) {
 4901                        return None;
 4902                    }
 4903                }
 4904                Some((
 4905                    excerpt_id,
 4906                    (
 4907                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4908                        buffer.version().clone(),
 4909                        excerpt_visible_range,
 4910                    ),
 4911                ))
 4912            })
 4913            .collect()
 4914    }
 4915
 4916    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4917        TextLayoutDetails {
 4918            text_system: window.text_system().clone(),
 4919            editor_style: self.style.clone().unwrap(),
 4920            rem_size: window.rem_size(),
 4921            scroll_anchor: self.scroll_manager.anchor(),
 4922            visible_rows: self.visible_line_count(),
 4923            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4924        }
 4925    }
 4926
 4927    pub fn splice_inlays(
 4928        &self,
 4929        to_remove: &[InlayId],
 4930        to_insert: Vec<Inlay>,
 4931        cx: &mut Context<Self>,
 4932    ) {
 4933        self.display_map.update(cx, |display_map, cx| {
 4934            display_map.splice_inlays(to_remove, to_insert, cx)
 4935        });
 4936        cx.notify();
 4937    }
 4938
 4939    fn trigger_on_type_formatting(
 4940        &self,
 4941        input: String,
 4942        window: &mut Window,
 4943        cx: &mut Context<Self>,
 4944    ) -> Option<Task<Result<()>>> {
 4945        if input.len() != 1 {
 4946            return None;
 4947        }
 4948
 4949        let project = self.project.as_ref()?;
 4950        let position = self.selections.newest_anchor().head();
 4951        let (buffer, buffer_position) = self
 4952            .buffer
 4953            .read(cx)
 4954            .text_anchor_for_position(position, cx)?;
 4955
 4956        let settings = language_settings::language_settings(
 4957            buffer
 4958                .read(cx)
 4959                .language_at(buffer_position)
 4960                .map(|l| l.name()),
 4961            buffer.read(cx).file(),
 4962            cx,
 4963        );
 4964        if !settings.use_on_type_format {
 4965            return None;
 4966        }
 4967
 4968        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4969        // hence we do LSP request & edit on host side only — add formats to host's history.
 4970        let push_to_lsp_host_history = true;
 4971        // If this is not the host, append its history with new edits.
 4972        let push_to_client_history = project.read(cx).is_via_collab();
 4973
 4974        let on_type_formatting = project.update(cx, |project, cx| {
 4975            project.on_type_format(
 4976                buffer.clone(),
 4977                buffer_position,
 4978                input,
 4979                push_to_lsp_host_history,
 4980                cx,
 4981            )
 4982        });
 4983        Some(cx.spawn_in(window, async move |editor, cx| {
 4984            if let Some(transaction) = on_type_formatting.await? {
 4985                if push_to_client_history {
 4986                    buffer
 4987                        .update(cx, |buffer, _| {
 4988                            buffer.push_transaction(transaction, Instant::now());
 4989                            buffer.finalize_last_transaction();
 4990                        })
 4991                        .ok();
 4992                }
 4993                editor.update(cx, |editor, cx| {
 4994                    editor.refresh_document_highlights(cx);
 4995                })?;
 4996            }
 4997            Ok(())
 4998        }))
 4999    }
 5000
 5001    pub fn show_word_completions(
 5002        &mut self,
 5003        _: &ShowWordCompletions,
 5004        window: &mut Window,
 5005        cx: &mut Context<Self>,
 5006    ) {
 5007        self.open_completions_menu(true, None, window, cx);
 5008    }
 5009
 5010    pub fn show_completions(
 5011        &mut self,
 5012        options: &ShowCompletions,
 5013        window: &mut Window,
 5014        cx: &mut Context<Self>,
 5015    ) {
 5016        self.open_completions_menu(false, options.trigger.as_deref(), window, cx);
 5017    }
 5018
 5019    fn open_completions_menu(
 5020        &mut self,
 5021        ignore_completion_provider: bool,
 5022        trigger: Option<&str>,
 5023        window: &mut Window,
 5024        cx: &mut Context<Self>,
 5025    ) {
 5026        if self.pending_rename.is_some() {
 5027            return;
 5028        }
 5029        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 5030            return;
 5031        }
 5032
 5033        let position = self.selections.newest_anchor().head();
 5034        if position.diff_base_anchor.is_some() {
 5035            return;
 5036        }
 5037        let (buffer, buffer_position) =
 5038            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5039                output
 5040            } else {
 5041                return;
 5042            };
 5043        let buffer_snapshot = buffer.read(cx).snapshot();
 5044        let show_completion_documentation = buffer_snapshot
 5045            .settings_at(buffer_position, cx)
 5046            .show_completion_documentation;
 5047
 5048        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 5049
 5050        let trigger_kind = match trigger {
 5051            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5052                CompletionTriggerKind::TRIGGER_CHARACTER
 5053            }
 5054            _ => CompletionTriggerKind::INVOKED,
 5055        };
 5056        let completion_context = CompletionContext {
 5057            trigger_character: trigger.and_then(|trigger| {
 5058                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5059                    Some(String::from(trigger))
 5060                } else {
 5061                    None
 5062                }
 5063            }),
 5064            trigger_kind,
 5065        };
 5066
 5067        let (old_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 5068        let (old_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 5069            let word_to_exclude = buffer_snapshot
 5070                .text_for_range(old_range.clone())
 5071                .collect::<String>();
 5072            (
 5073                buffer_snapshot.anchor_before(old_range.start)
 5074                    ..buffer_snapshot.anchor_after(old_range.end),
 5075                Some(word_to_exclude),
 5076            )
 5077        } else {
 5078            (buffer_position..buffer_position, None)
 5079        };
 5080
 5081        let language = buffer_snapshot
 5082            .language_at(buffer_position)
 5083            .map(|language| language.name());
 5084
 5085        let completion_settings =
 5086            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5087
 5088        // The document can be large, so stay in reasonable bounds when searching for words,
 5089        // otherwise completion pop-up might be slow to appear.
 5090        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5091        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5092        let min_word_search = buffer_snapshot.clip_point(
 5093            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5094            Bias::Left,
 5095        );
 5096        let max_word_search = buffer_snapshot.clip_point(
 5097            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5098            Bias::Right,
 5099        );
 5100        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5101            ..buffer_snapshot.point_to_offset(max_word_search);
 5102
 5103        let provider = if ignore_completion_provider {
 5104            None
 5105        } else {
 5106            self.completion_provider.clone()
 5107        };
 5108        let skip_digits = query
 5109            .as_ref()
 5110            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5111
 5112        let (mut words, provided_completions) = match &provider {
 5113            Some(provider) => {
 5114                let completions = provider.completions(
 5115                    position.excerpt_id,
 5116                    &buffer,
 5117                    buffer_position,
 5118                    completion_context,
 5119                    window,
 5120                    cx,
 5121                );
 5122
 5123                let words = match completion_settings.words {
 5124                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5125                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5126                        .background_spawn(async move {
 5127                            buffer_snapshot.words_in_range(WordsQuery {
 5128                                fuzzy_contents: None,
 5129                                range: word_search_range,
 5130                                skip_digits,
 5131                            })
 5132                        }),
 5133                };
 5134
 5135                (words, completions)
 5136            }
 5137            None => (
 5138                cx.background_spawn(async move {
 5139                    buffer_snapshot.words_in_range(WordsQuery {
 5140                        fuzzy_contents: None,
 5141                        range: word_search_range,
 5142                        skip_digits,
 5143                    })
 5144                }),
 5145                Task::ready(Ok(None)),
 5146            ),
 5147        };
 5148
 5149        let sort_completions = provider
 5150            .as_ref()
 5151            .map_or(false, |provider| provider.sort_completions());
 5152
 5153        let filter_completions = provider
 5154            .as_ref()
 5155            .map_or(true, |provider| provider.filter_completions());
 5156
 5157        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5158
 5159        let id = post_inc(&mut self.next_completion_id);
 5160        let task = cx.spawn_in(window, async move |editor, cx| {
 5161            async move {
 5162                editor.update(cx, |this, _| {
 5163                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5164                })?;
 5165
 5166                let mut completions = Vec::new();
 5167                if let Some(provided_completions) = provided_completions.await.log_err().flatten() {
 5168                    completions.extend(provided_completions);
 5169                    if completion_settings.words == WordsCompletionMode::Fallback {
 5170                        words = Task::ready(BTreeMap::default());
 5171                    }
 5172                }
 5173
 5174                let mut words = words.await;
 5175                if let Some(word_to_exclude) = &word_to_exclude {
 5176                    words.remove(word_to_exclude);
 5177                }
 5178                for lsp_completion in &completions {
 5179                    words.remove(&lsp_completion.new_text);
 5180                }
 5181                completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5182                    replace_range: old_range.clone(),
 5183                    new_text: word.clone(),
 5184                    label: CodeLabel::plain(word, None),
 5185                    icon_path: None,
 5186                    documentation: None,
 5187                    source: CompletionSource::BufferWord {
 5188                        word_range,
 5189                        resolved: false,
 5190                    },
 5191                    insert_text_mode: Some(InsertTextMode::AS_IS),
 5192                    confirm: None,
 5193                }));
 5194
 5195                let menu = if completions.is_empty() {
 5196                    None
 5197                } else {
 5198                    let mut menu = editor.update(cx, |editor, cx| {
 5199                        let languages = editor
 5200                            .workspace
 5201                            .as_ref()
 5202                            .and_then(|(workspace, _)| workspace.upgrade())
 5203                            .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5204                        CompletionsMenu::new(
 5205                            id,
 5206                            sort_completions,
 5207                            show_completion_documentation,
 5208                            ignore_completion_provider,
 5209                            position,
 5210                            buffer.clone(),
 5211                            completions.into(),
 5212                            snippet_sort_order,
 5213                            languages,
 5214                            language,
 5215                            cx,
 5216                        )
 5217                    })?;
 5218
 5219                    menu.filter(
 5220                        if filter_completions {
 5221                            query.as_deref()
 5222                        } else {
 5223                            None
 5224                        },
 5225                        provider,
 5226                        editor.clone(),
 5227                        cx,
 5228                    )
 5229                    .await;
 5230
 5231                    menu.visible().then_some(menu)
 5232                };
 5233
 5234                editor.update_in(cx, |editor, window, cx| {
 5235                    match editor.context_menu.borrow().as_ref() {
 5236                        None => {}
 5237                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5238                            if prev_menu.id > id {
 5239                                return;
 5240                            }
 5241                        }
 5242                        _ => return,
 5243                    }
 5244
 5245                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 5246                        let mut menu = menu.unwrap();
 5247                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 5248                        crate::hover_popover::hide_hover(editor, cx);
 5249                        *editor.context_menu.borrow_mut() =
 5250                            Some(CodeContextMenu::Completions(menu));
 5251
 5252                        if editor.show_edit_predictions_in_menu() {
 5253                            editor.update_visible_inline_completion(window, cx);
 5254                        } else {
 5255                            editor.discard_inline_completion(false, cx);
 5256                        }
 5257
 5258                        cx.notify();
 5259                    } else if editor.completion_tasks.len() <= 1 {
 5260                        // If there are no more completion tasks and the last menu was
 5261                        // empty, we should hide it.
 5262                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5263                        // If it was already hidden and we don't show inline
 5264                        // completions in the menu, we should also show the
 5265                        // inline-completion when available.
 5266                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5267                            editor.update_visible_inline_completion(window, cx);
 5268                        }
 5269                    }
 5270                })?;
 5271
 5272                anyhow::Ok(())
 5273            }
 5274            .log_err()
 5275            .await
 5276        });
 5277
 5278        self.completion_tasks.push((id, task));
 5279    }
 5280
 5281    #[cfg(feature = "test-support")]
 5282    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5283        let menu = self.context_menu.borrow();
 5284        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5285            let completions = menu.completions.borrow();
 5286            Some(completions.to_vec())
 5287        } else {
 5288            None
 5289        }
 5290    }
 5291
 5292    pub fn with_completions_menu_matching_id<R>(
 5293        &self,
 5294        id: CompletionId,
 5295        on_absent: impl FnOnce() -> R,
 5296        on_match: impl FnOnce(&mut CompletionsMenu) -> R,
 5297    ) -> R {
 5298        let mut context_menu = self.context_menu.borrow_mut();
 5299        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5300            return on_absent();
 5301        };
 5302        if completions_menu.id != id {
 5303            return on_absent();
 5304        }
 5305        on_match(completions_menu)
 5306    }
 5307
 5308    pub fn confirm_completion(
 5309        &mut self,
 5310        action: &ConfirmCompletion,
 5311        window: &mut Window,
 5312        cx: &mut Context<Self>,
 5313    ) -> Option<Task<Result<()>>> {
 5314        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5315        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5316    }
 5317
 5318    pub fn confirm_completion_insert(
 5319        &mut self,
 5320        _: &ConfirmCompletionInsert,
 5321        window: &mut Window,
 5322        cx: &mut Context<Self>,
 5323    ) -> Option<Task<Result<()>>> {
 5324        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5325        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5326    }
 5327
 5328    pub fn confirm_completion_replace(
 5329        &mut self,
 5330        _: &ConfirmCompletionReplace,
 5331        window: &mut Window,
 5332        cx: &mut Context<Self>,
 5333    ) -> Option<Task<Result<()>>> {
 5334        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5335        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5336    }
 5337
 5338    pub fn compose_completion(
 5339        &mut self,
 5340        action: &ComposeCompletion,
 5341        window: &mut Window,
 5342        cx: &mut Context<Self>,
 5343    ) -> Option<Task<Result<()>>> {
 5344        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5345        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5346    }
 5347
 5348    fn do_completion(
 5349        &mut self,
 5350        item_ix: Option<usize>,
 5351        intent: CompletionIntent,
 5352        window: &mut Window,
 5353        cx: &mut Context<Editor>,
 5354    ) -> Option<Task<Result<()>>> {
 5355        use language::ToOffset as _;
 5356
 5357        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5358        else {
 5359            return None;
 5360        };
 5361
 5362        let candidate_id = {
 5363            let entries = completions_menu.entries.borrow();
 5364            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5365            if self.show_edit_predictions_in_menu() {
 5366                self.discard_inline_completion(true, cx);
 5367            }
 5368            mat.candidate_id
 5369        };
 5370
 5371        let buffer_handle = completions_menu.buffer;
 5372        let completion = completions_menu
 5373            .completions
 5374            .borrow()
 5375            .get(candidate_id)?
 5376            .clone();
 5377        cx.stop_propagation();
 5378
 5379        let snapshot = self.buffer.read(cx).snapshot(cx);
 5380        let newest_anchor = self.selections.newest_anchor();
 5381
 5382        let snippet;
 5383        let new_text;
 5384        if completion.is_snippet() {
 5385            let mut snippet_source = completion.new_text.clone();
 5386            if let Some(scope) = snapshot.language_scope_at(newest_anchor.head()) {
 5387                if scope.prefers_label_for_snippet_in_completion() {
 5388                    if let Some(label) = completion.label() {
 5389                        if matches!(
 5390                            completion.kind(),
 5391                            Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
 5392                        ) {
 5393                            snippet_source = label;
 5394                        }
 5395                    }
 5396                }
 5397            }
 5398            snippet = Some(Snippet::parse(&snippet_source).log_err()?);
 5399            new_text = snippet.as_ref().unwrap().text.clone();
 5400        } else {
 5401            snippet = None;
 5402            new_text = completion.new_text.clone();
 5403        };
 5404
 5405        let replace_range = choose_completion_range(&completion, intent, &buffer_handle, cx);
 5406        let buffer = buffer_handle.read(cx);
 5407        let replace_range_multibuffer = {
 5408            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5409            let multibuffer_anchor = snapshot
 5410                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5411                .unwrap()
 5412                ..snapshot
 5413                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5414                    .unwrap();
 5415            multibuffer_anchor.start.to_offset(&snapshot)
 5416                ..multibuffer_anchor.end.to_offset(&snapshot)
 5417        };
 5418        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5419            return None;
 5420        }
 5421
 5422        let old_text = buffer
 5423            .text_for_range(replace_range.clone())
 5424            .collect::<String>();
 5425        let lookbehind = newest_anchor
 5426            .start
 5427            .text_anchor
 5428            .to_offset(buffer)
 5429            .saturating_sub(replace_range.start);
 5430        let lookahead = replace_range
 5431            .end
 5432            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5433        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5434        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5435
 5436        let selections = self.selections.all::<usize>(cx);
 5437        let mut ranges = Vec::new();
 5438        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5439
 5440        for selection in &selections {
 5441            let range = if selection.id == newest_anchor.id {
 5442                replace_range_multibuffer.clone()
 5443            } else {
 5444                let mut range = selection.range();
 5445
 5446                // if prefix is present, don't duplicate it
 5447                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5448                    range.start = range.start.saturating_sub(lookbehind);
 5449
 5450                    // if suffix is also present, mimic the newest cursor and replace it
 5451                    if selection.id != newest_anchor.id
 5452                        && snapshot.contains_str_at(range.end, suffix)
 5453                    {
 5454                        range.end += lookahead;
 5455                    }
 5456                }
 5457                range
 5458            };
 5459
 5460            ranges.push(range.clone());
 5461
 5462            if !self.linked_edit_ranges.is_empty() {
 5463                let start_anchor = snapshot.anchor_before(range.start);
 5464                let end_anchor = snapshot.anchor_after(range.end);
 5465                if let Some(ranges) = self
 5466                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5467                {
 5468                    for (buffer, edits) in ranges {
 5469                        linked_edits
 5470                            .entry(buffer.clone())
 5471                            .or_default()
 5472                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5473                    }
 5474                }
 5475            }
 5476        }
 5477
 5478        cx.emit(EditorEvent::InputHandled {
 5479            utf16_range_to_replace: None,
 5480            text: new_text.clone().into(),
 5481        });
 5482
 5483        self.transact(window, cx, |this, window, cx| {
 5484            if let Some(mut snippet) = snippet {
 5485                snippet.text = new_text.to_string();
 5486                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5487            } else {
 5488                this.buffer.update(cx, |buffer, cx| {
 5489                    let auto_indent = match completion.insert_text_mode {
 5490                        Some(InsertTextMode::AS_IS) => None,
 5491                        _ => this.autoindent_mode.clone(),
 5492                    };
 5493                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5494                    buffer.edit(edits, auto_indent, cx);
 5495                });
 5496            }
 5497            for (buffer, edits) in linked_edits {
 5498                buffer.update(cx, |buffer, cx| {
 5499                    let snapshot = buffer.snapshot();
 5500                    let edits = edits
 5501                        .into_iter()
 5502                        .map(|(range, text)| {
 5503                            use text::ToPoint as TP;
 5504                            let end_point = TP::to_point(&range.end, &snapshot);
 5505                            let start_point = TP::to_point(&range.start, &snapshot);
 5506                            (start_point..end_point, text)
 5507                        })
 5508                        .sorted_by_key(|(range, _)| range.start);
 5509                    buffer.edit(edits, None, cx);
 5510                })
 5511            }
 5512
 5513            this.refresh_inline_completion(true, false, window, cx);
 5514        });
 5515
 5516        let show_new_completions_on_confirm = completion
 5517            .confirm
 5518            .as_ref()
 5519            .map_or(false, |confirm| confirm(intent, window, cx));
 5520        if show_new_completions_on_confirm {
 5521            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5522        }
 5523
 5524        let provider = self.completion_provider.as_ref()?;
 5525        drop(completion);
 5526        let apply_edits = provider.apply_additional_edits_for_completion(
 5527            buffer_handle,
 5528            completions_menu.completions.clone(),
 5529            candidate_id,
 5530            true,
 5531            cx,
 5532        );
 5533
 5534        let editor_settings = EditorSettings::get_global(cx);
 5535        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5536            // After the code completion is finished, users often want to know what signatures are needed.
 5537            // so we should automatically call signature_help
 5538            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5539        }
 5540
 5541        Some(cx.foreground_executor().spawn(async move {
 5542            apply_edits.await?;
 5543            Ok(())
 5544        }))
 5545    }
 5546
 5547    pub fn toggle_code_actions(
 5548        &mut self,
 5549        action: &ToggleCodeActions,
 5550        window: &mut Window,
 5551        cx: &mut Context<Self>,
 5552    ) {
 5553        let quick_launch = action.quick_launch;
 5554        let mut context_menu = self.context_menu.borrow_mut();
 5555        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5556            if code_actions.deployed_from == action.deployed_from {
 5557                // Toggle if we're selecting the same one
 5558                *context_menu = None;
 5559                cx.notify();
 5560                return;
 5561            } else {
 5562                // Otherwise, clear it and start a new one
 5563                *context_menu = None;
 5564                cx.notify();
 5565            }
 5566        }
 5567        drop(context_menu);
 5568        let snapshot = self.snapshot(window, cx);
 5569        let deployed_from = action.deployed_from.clone();
 5570        let mut task = self.code_actions_task.take();
 5571        let action = action.clone();
 5572        cx.spawn_in(window, async move |editor, cx| {
 5573            while let Some(prev_task) = task {
 5574                prev_task.await.log_err();
 5575                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5576            }
 5577
 5578            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5579                if editor.focus_handle.is_focused(window) {
 5580                    let multibuffer_point = match &action.deployed_from {
 5581                        Some(CodeActionSource::Indicator(row)) => {
 5582                            DisplayPoint::new(*row, 0).to_point(&snapshot)
 5583                        }
 5584                        _ => editor.selections.newest::<Point>(cx).head(),
 5585                    };
 5586                    let (buffer, buffer_row) = snapshot
 5587                        .buffer_snapshot
 5588                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5589                        .and_then(|(buffer_snapshot, range)| {
 5590                            editor
 5591                                .buffer
 5592                                .read(cx)
 5593                                .buffer(buffer_snapshot.remote_id())
 5594                                .map(|buffer| (buffer, range.start.row))
 5595                        })?;
 5596                    let (_, code_actions) = editor
 5597                        .available_code_actions
 5598                        .clone()
 5599                        .and_then(|(location, code_actions)| {
 5600                            let snapshot = location.buffer.read(cx).snapshot();
 5601                            let point_range = location.range.to_point(&snapshot);
 5602                            let point_range = point_range.start.row..=point_range.end.row;
 5603                            if point_range.contains(&buffer_row) {
 5604                                Some((location, code_actions))
 5605                            } else {
 5606                                None
 5607                            }
 5608                        })
 5609                        .unzip();
 5610                    let buffer_id = buffer.read(cx).remote_id();
 5611                    let tasks = editor
 5612                        .tasks
 5613                        .get(&(buffer_id, buffer_row))
 5614                        .map(|t| Arc::new(t.to_owned()));
 5615                    if tasks.is_none() && code_actions.is_none() {
 5616                        return None;
 5617                    }
 5618
 5619                    editor.completion_tasks.clear();
 5620                    editor.discard_inline_completion(false, cx);
 5621                    let task_context =
 5622                        tasks
 5623                            .as_ref()
 5624                            .zip(editor.project.clone())
 5625                            .map(|(tasks, project)| {
 5626                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5627                            });
 5628
 5629                    Some(cx.spawn_in(window, async move |editor, cx| {
 5630                        let task_context = match task_context {
 5631                            Some(task_context) => task_context.await,
 5632                            None => None,
 5633                        };
 5634                        let resolved_tasks =
 5635                            tasks
 5636                                .zip(task_context.clone())
 5637                                .map(|(tasks, task_context)| ResolvedTasks {
 5638                                    templates: tasks.resolve(&task_context).collect(),
 5639                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5640                                        multibuffer_point.row,
 5641                                        tasks.column,
 5642                                    )),
 5643                                });
 5644                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5645                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5646                                maybe!({
 5647                                    let project = editor.project.as_ref()?;
 5648                                    let dap_store = project.read(cx).dap_store();
 5649                                    let mut scenarios = vec![];
 5650                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5651                                    let buffer = buffer.read(cx);
 5652                                    let language = buffer.language()?;
 5653                                    let file = buffer.file();
 5654                                    let debug_adapter =
 5655                                        language_settings(language.name().into(), file, cx)
 5656                                            .debuggers
 5657                                            .first()
 5658                                            .map(SharedString::from)
 5659                                            .or_else(|| {
 5660                                                language
 5661                                                    .config()
 5662                                                    .debuggers
 5663                                                    .first()
 5664                                                    .map(SharedString::from)
 5665                                            })?;
 5666
 5667                                    dap_store.update(cx, |dap_store, cx| {
 5668                                        for (_, task) in &resolved_tasks.templates {
 5669                                            if let Some(scenario) = dap_store
 5670                                                .debug_scenario_for_build_task(
 5671                                                    task.original_task().clone(),
 5672                                                    debug_adapter.clone().into(),
 5673                                                    task.display_label().to_owned().into(),
 5674                                                    cx,
 5675                                                )
 5676                                            {
 5677                                                scenarios.push(scenario);
 5678                                            }
 5679                                        }
 5680                                    });
 5681                                    Some(scenarios)
 5682                                })
 5683                                .unwrap_or_default()
 5684                            } else {
 5685                                vec![]
 5686                            }
 5687                        })?;
 5688                        let spawn_straight_away = quick_launch
 5689                            && resolved_tasks
 5690                                .as_ref()
 5691                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5692                            && code_actions
 5693                                .as_ref()
 5694                                .map_or(true, |actions| actions.is_empty())
 5695                            && debug_scenarios.is_empty();
 5696                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5697                            crate::hover_popover::hide_hover(editor, cx);
 5698                            *editor.context_menu.borrow_mut() =
 5699                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5700                                    buffer,
 5701                                    actions: CodeActionContents::new(
 5702                                        resolved_tasks,
 5703                                        code_actions,
 5704                                        debug_scenarios,
 5705                                        task_context.unwrap_or_default(),
 5706                                    ),
 5707                                    selected_item: Default::default(),
 5708                                    scroll_handle: UniformListScrollHandle::default(),
 5709                                    deployed_from,
 5710                                }));
 5711                            if spawn_straight_away {
 5712                                if let Some(task) = editor.confirm_code_action(
 5713                                    &ConfirmCodeAction { item_ix: Some(0) },
 5714                                    window,
 5715                                    cx,
 5716                                ) {
 5717                                    cx.notify();
 5718                                    return task;
 5719                                }
 5720                            }
 5721                            cx.notify();
 5722                            Task::ready(Ok(()))
 5723                        }) {
 5724                            task.await
 5725                        } else {
 5726                            Ok(())
 5727                        }
 5728                    }))
 5729                } else {
 5730                    Some(Task::ready(Ok(())))
 5731                }
 5732            })?;
 5733            if let Some(task) = spawned_test_task {
 5734                task.await?;
 5735            }
 5736
 5737            anyhow::Ok(())
 5738        })
 5739        .detach_and_log_err(cx);
 5740    }
 5741
 5742    pub fn confirm_code_action(
 5743        &mut self,
 5744        action: &ConfirmCodeAction,
 5745        window: &mut Window,
 5746        cx: &mut Context<Self>,
 5747    ) -> Option<Task<Result<()>>> {
 5748        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5749
 5750        let actions_menu =
 5751            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5752                menu
 5753            } else {
 5754                return None;
 5755            };
 5756
 5757        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5758        let action = actions_menu.actions.get(action_ix)?;
 5759        let title = action.label();
 5760        let buffer = actions_menu.buffer;
 5761        let workspace = self.workspace()?;
 5762
 5763        match action {
 5764            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5765                workspace.update(cx, |workspace, cx| {
 5766                    workspace.schedule_resolved_task(
 5767                        task_source_kind,
 5768                        resolved_task,
 5769                        false,
 5770                        window,
 5771                        cx,
 5772                    );
 5773
 5774                    Some(Task::ready(Ok(())))
 5775                })
 5776            }
 5777            CodeActionsItem::CodeAction {
 5778                excerpt_id,
 5779                action,
 5780                provider,
 5781            } => {
 5782                let apply_code_action =
 5783                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5784                let workspace = workspace.downgrade();
 5785                Some(cx.spawn_in(window, async move |editor, cx| {
 5786                    let project_transaction = apply_code_action.await?;
 5787                    Self::open_project_transaction(
 5788                        &editor,
 5789                        workspace,
 5790                        project_transaction,
 5791                        title,
 5792                        cx,
 5793                    )
 5794                    .await
 5795                }))
 5796            }
 5797            CodeActionsItem::DebugScenario(scenario) => {
 5798                let context = actions_menu.actions.context.clone();
 5799
 5800                workspace.update(cx, |workspace, cx| {
 5801                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5802                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5803                });
 5804                Some(Task::ready(Ok(())))
 5805            }
 5806        }
 5807    }
 5808
 5809    pub async fn open_project_transaction(
 5810        this: &WeakEntity<Editor>,
 5811        workspace: WeakEntity<Workspace>,
 5812        transaction: ProjectTransaction,
 5813        title: String,
 5814        cx: &mut AsyncWindowContext,
 5815    ) -> Result<()> {
 5816        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5817        cx.update(|_, cx| {
 5818            entries.sort_unstable_by_key(|(buffer, _)| {
 5819                buffer.read(cx).file().map(|f| f.path().clone())
 5820            });
 5821        })?;
 5822
 5823        // If the project transaction's edits are all contained within this editor, then
 5824        // avoid opening a new editor to display them.
 5825
 5826        if let Some((buffer, transaction)) = entries.first() {
 5827            if entries.len() == 1 {
 5828                let excerpt = this.update(cx, |editor, cx| {
 5829                    editor
 5830                        .buffer()
 5831                        .read(cx)
 5832                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5833                })?;
 5834                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5835                    if excerpted_buffer == *buffer {
 5836                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5837                            let excerpt_range = excerpt_range.to_offset(buffer);
 5838                            buffer
 5839                                .edited_ranges_for_transaction::<usize>(transaction)
 5840                                .all(|range| {
 5841                                    excerpt_range.start <= range.start
 5842                                        && excerpt_range.end >= range.end
 5843                                })
 5844                        })?;
 5845
 5846                        if all_edits_within_excerpt {
 5847                            return Ok(());
 5848                        }
 5849                    }
 5850                }
 5851            }
 5852        } else {
 5853            return Ok(());
 5854        }
 5855
 5856        let mut ranges_to_highlight = Vec::new();
 5857        let excerpt_buffer = cx.new(|cx| {
 5858            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5859            for (buffer_handle, transaction) in &entries {
 5860                let edited_ranges = buffer_handle
 5861                    .read(cx)
 5862                    .edited_ranges_for_transaction::<Point>(transaction)
 5863                    .collect::<Vec<_>>();
 5864                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5865                    PathKey::for_buffer(buffer_handle, cx),
 5866                    buffer_handle.clone(),
 5867                    edited_ranges,
 5868                    DEFAULT_MULTIBUFFER_CONTEXT,
 5869                    cx,
 5870                );
 5871
 5872                ranges_to_highlight.extend(ranges);
 5873            }
 5874            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5875            multibuffer
 5876        })?;
 5877
 5878        workspace.update_in(cx, |workspace, window, cx| {
 5879            let project = workspace.project().clone();
 5880            let editor =
 5881                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5882            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5883            editor.update(cx, |editor, cx| {
 5884                editor.highlight_background::<Self>(
 5885                    &ranges_to_highlight,
 5886                    |theme| theme.editor_highlighted_line_background,
 5887                    cx,
 5888                );
 5889            });
 5890        })?;
 5891
 5892        Ok(())
 5893    }
 5894
 5895    pub fn clear_code_action_providers(&mut self) {
 5896        self.code_action_providers.clear();
 5897        self.available_code_actions.take();
 5898    }
 5899
 5900    pub fn add_code_action_provider(
 5901        &mut self,
 5902        provider: Rc<dyn CodeActionProvider>,
 5903        window: &mut Window,
 5904        cx: &mut Context<Self>,
 5905    ) {
 5906        if self
 5907            .code_action_providers
 5908            .iter()
 5909            .any(|existing_provider| existing_provider.id() == provider.id())
 5910        {
 5911            return;
 5912        }
 5913
 5914        self.code_action_providers.push(provider);
 5915        self.refresh_code_actions(window, cx);
 5916    }
 5917
 5918    pub fn remove_code_action_provider(
 5919        &mut self,
 5920        id: Arc<str>,
 5921        window: &mut Window,
 5922        cx: &mut Context<Self>,
 5923    ) {
 5924        self.code_action_providers
 5925            .retain(|provider| provider.id() != id);
 5926        self.refresh_code_actions(window, cx);
 5927    }
 5928
 5929    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 5930        !self.code_action_providers.is_empty()
 5931            && EditorSettings::get_global(cx).toolbar.code_actions
 5932    }
 5933
 5934    pub fn has_available_code_actions(&self) -> bool {
 5935        self.available_code_actions
 5936            .as_ref()
 5937            .is_some_and(|(_, actions)| !actions.is_empty())
 5938    }
 5939
 5940    fn render_inline_code_actions(
 5941        &self,
 5942        icon_size: ui::IconSize,
 5943        display_row: DisplayRow,
 5944        is_active: bool,
 5945        cx: &mut Context<Self>,
 5946    ) -> AnyElement {
 5947        let show_tooltip = !self.context_menu_visible();
 5948        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 5949            .icon_size(icon_size)
 5950            .shape(ui::IconButtonShape::Square)
 5951            .style(ButtonStyle::Transparent)
 5952            .icon_color(ui::Color::Hidden)
 5953            .toggle_state(is_active)
 5954            .when(show_tooltip, |this| {
 5955                this.tooltip({
 5956                    let focus_handle = self.focus_handle.clone();
 5957                    move |window, cx| {
 5958                        Tooltip::for_action_in(
 5959                            "Toggle Code Actions",
 5960                            &ToggleCodeActions {
 5961                                deployed_from: None,
 5962                                quick_launch: false,
 5963                            },
 5964                            &focus_handle,
 5965                            window,
 5966                            cx,
 5967                        )
 5968                    }
 5969                })
 5970            })
 5971            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 5972                window.focus(&editor.focus_handle(cx));
 5973                editor.toggle_code_actions(
 5974                    &crate::actions::ToggleCodeActions {
 5975                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 5976                            display_row,
 5977                        )),
 5978                        quick_launch: false,
 5979                    },
 5980                    window,
 5981                    cx,
 5982                );
 5983            }))
 5984            .into_any_element()
 5985    }
 5986
 5987    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 5988        &self.context_menu
 5989    }
 5990
 5991    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5992        let newest_selection = self.selections.newest_anchor().clone();
 5993        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5994        let buffer = self.buffer.read(cx);
 5995        if newest_selection.head().diff_base_anchor.is_some() {
 5996            return None;
 5997        }
 5998        let (start_buffer, start) =
 5999            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6000        let (end_buffer, end) =
 6001            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6002        if start_buffer != end_buffer {
 6003            return None;
 6004        }
 6005
 6006        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6007            cx.background_executor()
 6008                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6009                .await;
 6010
 6011            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6012                let providers = this.code_action_providers.clone();
 6013                let tasks = this
 6014                    .code_action_providers
 6015                    .iter()
 6016                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6017                    .collect::<Vec<_>>();
 6018                (providers, tasks)
 6019            })?;
 6020
 6021            let mut actions = Vec::new();
 6022            for (provider, provider_actions) in
 6023                providers.into_iter().zip(future::join_all(tasks).await)
 6024            {
 6025                if let Some(provider_actions) = provider_actions.log_err() {
 6026                    actions.extend(provider_actions.into_iter().map(|action| {
 6027                        AvailableCodeAction {
 6028                            excerpt_id: newest_selection.start.excerpt_id,
 6029                            action,
 6030                            provider: provider.clone(),
 6031                        }
 6032                    }));
 6033                }
 6034            }
 6035
 6036            this.update(cx, |this, cx| {
 6037                this.available_code_actions = if actions.is_empty() {
 6038                    None
 6039                } else {
 6040                    Some((
 6041                        Location {
 6042                            buffer: start_buffer,
 6043                            range: start..end,
 6044                        },
 6045                        actions.into(),
 6046                    ))
 6047                };
 6048                cx.notify();
 6049            })
 6050        }));
 6051        None
 6052    }
 6053
 6054    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6055        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6056            self.show_git_blame_inline = false;
 6057
 6058            self.show_git_blame_inline_delay_task =
 6059                Some(cx.spawn_in(window, async move |this, cx| {
 6060                    cx.background_executor().timer(delay).await;
 6061
 6062                    this.update(cx, |this, cx| {
 6063                        this.show_git_blame_inline = true;
 6064                        cx.notify();
 6065                    })
 6066                    .log_err();
 6067                }));
 6068        }
 6069    }
 6070
 6071    fn show_blame_popover(
 6072        &mut self,
 6073        blame_entry: &BlameEntry,
 6074        position: gpui::Point<Pixels>,
 6075        cx: &mut Context<Self>,
 6076    ) {
 6077        if let Some(state) = &mut self.inline_blame_popover {
 6078            state.hide_task.take();
 6079            cx.notify();
 6080        } else {
 6081            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6082            let show_task = cx.spawn(async move |editor, cx| {
 6083                cx.background_executor()
 6084                    .timer(std::time::Duration::from_millis(delay))
 6085                    .await;
 6086                editor
 6087                    .update(cx, |editor, cx| {
 6088                        if let Some(state) = &mut editor.inline_blame_popover {
 6089                            state.show_task = None;
 6090                            cx.notify();
 6091                        }
 6092                    })
 6093                    .ok();
 6094            });
 6095            let Some(blame) = self.blame.as_ref() else {
 6096                return;
 6097            };
 6098            let blame = blame.read(cx);
 6099            let details = blame.details_for_entry(&blame_entry);
 6100            let markdown = cx.new(|cx| {
 6101                Markdown::new(
 6102                    details
 6103                        .as_ref()
 6104                        .map(|message| message.message.clone())
 6105                        .unwrap_or_default(),
 6106                    None,
 6107                    None,
 6108                    cx,
 6109                )
 6110            });
 6111            self.inline_blame_popover = Some(InlineBlamePopover {
 6112                position,
 6113                show_task: Some(show_task),
 6114                hide_task: None,
 6115                popover_bounds: None,
 6116                popover_state: InlineBlamePopoverState {
 6117                    scroll_handle: ScrollHandle::new(),
 6118                    commit_message: details,
 6119                    markdown,
 6120                },
 6121            });
 6122        }
 6123    }
 6124
 6125    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6126        if let Some(state) = &mut self.inline_blame_popover {
 6127            if state.show_task.is_some() {
 6128                self.inline_blame_popover.take();
 6129                cx.notify();
 6130            } else {
 6131                let hide_task = cx.spawn(async move |editor, cx| {
 6132                    cx.background_executor()
 6133                        .timer(std::time::Duration::from_millis(100))
 6134                        .await;
 6135                    editor
 6136                        .update(cx, |editor, cx| {
 6137                            editor.inline_blame_popover.take();
 6138                            cx.notify();
 6139                        })
 6140                        .ok();
 6141                });
 6142                state.hide_task = Some(hide_task);
 6143            }
 6144        }
 6145    }
 6146
 6147    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6148        if self.pending_rename.is_some() {
 6149            return None;
 6150        }
 6151
 6152        let provider = self.semantics_provider.clone()?;
 6153        let buffer = self.buffer.read(cx);
 6154        let newest_selection = self.selections.newest_anchor().clone();
 6155        let cursor_position = newest_selection.head();
 6156        let (cursor_buffer, cursor_buffer_position) =
 6157            buffer.text_anchor_for_position(cursor_position, cx)?;
 6158        let (tail_buffer, tail_buffer_position) =
 6159            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6160        if cursor_buffer != tail_buffer {
 6161            return None;
 6162        }
 6163
 6164        let snapshot = cursor_buffer.read(cx).snapshot();
 6165        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6166        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6167        if start_word_range != end_word_range {
 6168            self.document_highlights_task.take();
 6169            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6170            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6171            return None;
 6172        }
 6173
 6174        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6175        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6176            cx.background_executor()
 6177                .timer(Duration::from_millis(debounce))
 6178                .await;
 6179
 6180            let highlights = if let Some(highlights) = cx
 6181                .update(|cx| {
 6182                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6183                })
 6184                .ok()
 6185                .flatten()
 6186            {
 6187                highlights.await.log_err()
 6188            } else {
 6189                None
 6190            };
 6191
 6192            if let Some(highlights) = highlights {
 6193                this.update(cx, |this, cx| {
 6194                    if this.pending_rename.is_some() {
 6195                        return;
 6196                    }
 6197
 6198                    let buffer_id = cursor_position.buffer_id;
 6199                    let buffer = this.buffer.read(cx);
 6200                    if !buffer
 6201                        .text_anchor_for_position(cursor_position, cx)
 6202                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6203                    {
 6204                        return;
 6205                    }
 6206
 6207                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6208                    let mut write_ranges = Vec::new();
 6209                    let mut read_ranges = Vec::new();
 6210                    for highlight in highlights {
 6211                        for (excerpt_id, excerpt_range) in
 6212                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6213                        {
 6214                            let start = highlight
 6215                                .range
 6216                                .start
 6217                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6218                            let end = highlight
 6219                                .range
 6220                                .end
 6221                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6222                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6223                                continue;
 6224                            }
 6225
 6226                            let range = Anchor {
 6227                                buffer_id,
 6228                                excerpt_id,
 6229                                text_anchor: start,
 6230                                diff_base_anchor: None,
 6231                            }..Anchor {
 6232                                buffer_id,
 6233                                excerpt_id,
 6234                                text_anchor: end,
 6235                                diff_base_anchor: None,
 6236                            };
 6237                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6238                                write_ranges.push(range);
 6239                            } else {
 6240                                read_ranges.push(range);
 6241                            }
 6242                        }
 6243                    }
 6244
 6245                    this.highlight_background::<DocumentHighlightRead>(
 6246                        &read_ranges,
 6247                        |theme| theme.editor_document_highlight_read_background,
 6248                        cx,
 6249                    );
 6250                    this.highlight_background::<DocumentHighlightWrite>(
 6251                        &write_ranges,
 6252                        |theme| theme.editor_document_highlight_write_background,
 6253                        cx,
 6254                    );
 6255                    cx.notify();
 6256                })
 6257                .log_err();
 6258            }
 6259        }));
 6260        None
 6261    }
 6262
 6263    fn prepare_highlight_query_from_selection(
 6264        &mut self,
 6265        cx: &mut Context<Editor>,
 6266    ) -> Option<(String, Range<Anchor>)> {
 6267        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6268            return None;
 6269        }
 6270        if !EditorSettings::get_global(cx).selection_highlight {
 6271            return None;
 6272        }
 6273        if self.selections.count() != 1 || self.selections.line_mode {
 6274            return None;
 6275        }
 6276        let selection = self.selections.newest::<Point>(cx);
 6277        if selection.is_empty() || selection.start.row != selection.end.row {
 6278            return None;
 6279        }
 6280        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6281        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6282        let query = multi_buffer_snapshot
 6283            .text_for_range(selection_anchor_range.clone())
 6284            .collect::<String>();
 6285        if query.trim().is_empty() {
 6286            return None;
 6287        }
 6288        Some((query, selection_anchor_range))
 6289    }
 6290
 6291    fn update_selection_occurrence_highlights(
 6292        &mut self,
 6293        query_text: String,
 6294        query_range: Range<Anchor>,
 6295        multi_buffer_range_to_query: Range<Point>,
 6296        use_debounce: bool,
 6297        window: &mut Window,
 6298        cx: &mut Context<Editor>,
 6299    ) -> Task<()> {
 6300        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6301        cx.spawn_in(window, async move |editor, cx| {
 6302            if use_debounce {
 6303                cx.background_executor()
 6304                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6305                    .await;
 6306            }
 6307            let match_task = cx.background_spawn(async move {
 6308                let buffer_ranges = multi_buffer_snapshot
 6309                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6310                    .into_iter()
 6311                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6312                let mut match_ranges = Vec::new();
 6313                let Ok(regex) = project::search::SearchQuery::text(
 6314                    query_text.clone(),
 6315                    false,
 6316                    false,
 6317                    false,
 6318                    Default::default(),
 6319                    Default::default(),
 6320                    false,
 6321                    None,
 6322                ) else {
 6323                    return Vec::default();
 6324                };
 6325                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6326                    match_ranges.extend(
 6327                        regex
 6328                            .search(&buffer_snapshot, Some(search_range.clone()))
 6329                            .await
 6330                            .into_iter()
 6331                            .filter_map(|match_range| {
 6332                                let match_start = buffer_snapshot
 6333                                    .anchor_after(search_range.start + match_range.start);
 6334                                let match_end = buffer_snapshot
 6335                                    .anchor_before(search_range.start + match_range.end);
 6336                                let match_anchor_range = Anchor::range_in_buffer(
 6337                                    excerpt_id,
 6338                                    buffer_snapshot.remote_id(),
 6339                                    match_start..match_end,
 6340                                );
 6341                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6342                            }),
 6343                    );
 6344                }
 6345                match_ranges
 6346            });
 6347            let match_ranges = match_task.await;
 6348            editor
 6349                .update_in(cx, |editor, _, cx| {
 6350                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6351                    if !match_ranges.is_empty() {
 6352                        editor.highlight_background::<SelectedTextHighlight>(
 6353                            &match_ranges,
 6354                            |theme| theme.editor_document_highlight_bracket_background,
 6355                            cx,
 6356                        )
 6357                    }
 6358                })
 6359                .log_err();
 6360        })
 6361    }
 6362
 6363    fn refresh_selected_text_highlights(
 6364        &mut self,
 6365        on_buffer_edit: bool,
 6366        window: &mut Window,
 6367        cx: &mut Context<Editor>,
 6368    ) {
 6369        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6370        else {
 6371            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6372            self.quick_selection_highlight_task.take();
 6373            self.debounced_selection_highlight_task.take();
 6374            return;
 6375        };
 6376        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6377        if on_buffer_edit
 6378            || self
 6379                .quick_selection_highlight_task
 6380                .as_ref()
 6381                .map_or(true, |(prev_anchor_range, _)| {
 6382                    prev_anchor_range != &query_range
 6383                })
 6384        {
 6385            let multi_buffer_visible_start = self
 6386                .scroll_manager
 6387                .anchor()
 6388                .anchor
 6389                .to_point(&multi_buffer_snapshot);
 6390            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6391                multi_buffer_visible_start
 6392                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6393                Bias::Left,
 6394            );
 6395            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6396            self.quick_selection_highlight_task = Some((
 6397                query_range.clone(),
 6398                self.update_selection_occurrence_highlights(
 6399                    query_text.clone(),
 6400                    query_range.clone(),
 6401                    multi_buffer_visible_range,
 6402                    false,
 6403                    window,
 6404                    cx,
 6405                ),
 6406            ));
 6407        }
 6408        if on_buffer_edit
 6409            || self
 6410                .debounced_selection_highlight_task
 6411                .as_ref()
 6412                .map_or(true, |(prev_anchor_range, _)| {
 6413                    prev_anchor_range != &query_range
 6414                })
 6415        {
 6416            let multi_buffer_start = multi_buffer_snapshot
 6417                .anchor_before(0)
 6418                .to_point(&multi_buffer_snapshot);
 6419            let multi_buffer_end = multi_buffer_snapshot
 6420                .anchor_after(multi_buffer_snapshot.len())
 6421                .to_point(&multi_buffer_snapshot);
 6422            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6423            self.debounced_selection_highlight_task = Some((
 6424                query_range.clone(),
 6425                self.update_selection_occurrence_highlights(
 6426                    query_text,
 6427                    query_range,
 6428                    multi_buffer_full_range,
 6429                    true,
 6430                    window,
 6431                    cx,
 6432                ),
 6433            ));
 6434        }
 6435    }
 6436
 6437    pub fn refresh_inline_completion(
 6438        &mut self,
 6439        debounce: bool,
 6440        user_requested: bool,
 6441        window: &mut Window,
 6442        cx: &mut Context<Self>,
 6443    ) -> Option<()> {
 6444        let provider = self.edit_prediction_provider()?;
 6445        let cursor = self.selections.newest_anchor().head();
 6446        let (buffer, cursor_buffer_position) =
 6447            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6448
 6449        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6450            self.discard_inline_completion(false, cx);
 6451            return None;
 6452        }
 6453
 6454        if !user_requested
 6455            && (!self.should_show_edit_predictions()
 6456                || !self.is_focused(window)
 6457                || buffer.read(cx).is_empty())
 6458        {
 6459            self.discard_inline_completion(false, cx);
 6460            return None;
 6461        }
 6462
 6463        self.update_visible_inline_completion(window, cx);
 6464        provider.refresh(
 6465            self.project.clone(),
 6466            buffer,
 6467            cursor_buffer_position,
 6468            debounce,
 6469            cx,
 6470        );
 6471        Some(())
 6472    }
 6473
 6474    fn show_edit_predictions_in_menu(&self) -> bool {
 6475        match self.edit_prediction_settings {
 6476            EditPredictionSettings::Disabled => false,
 6477            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6478        }
 6479    }
 6480
 6481    pub fn edit_predictions_enabled(&self) -> bool {
 6482        match self.edit_prediction_settings {
 6483            EditPredictionSettings::Disabled => false,
 6484            EditPredictionSettings::Enabled { .. } => true,
 6485        }
 6486    }
 6487
 6488    fn edit_prediction_requires_modifier(&self) -> bool {
 6489        match self.edit_prediction_settings {
 6490            EditPredictionSettings::Disabled => false,
 6491            EditPredictionSettings::Enabled {
 6492                preview_requires_modifier,
 6493                ..
 6494            } => preview_requires_modifier,
 6495        }
 6496    }
 6497
 6498    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6499        if self.edit_prediction_provider.is_none() {
 6500            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6501        } else {
 6502            let selection = self.selections.newest_anchor();
 6503            let cursor = selection.head();
 6504
 6505            if let Some((buffer, cursor_buffer_position)) =
 6506                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6507            {
 6508                self.edit_prediction_settings =
 6509                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6510            }
 6511        }
 6512    }
 6513
 6514    fn edit_prediction_settings_at_position(
 6515        &self,
 6516        buffer: &Entity<Buffer>,
 6517        buffer_position: language::Anchor,
 6518        cx: &App,
 6519    ) -> EditPredictionSettings {
 6520        if !self.mode.is_full()
 6521            || !self.show_inline_completions_override.unwrap_or(true)
 6522            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6523        {
 6524            return EditPredictionSettings::Disabled;
 6525        }
 6526
 6527        let buffer = buffer.read(cx);
 6528
 6529        let file = buffer.file();
 6530
 6531        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6532            return EditPredictionSettings::Disabled;
 6533        };
 6534
 6535        let by_provider = matches!(
 6536            self.menu_inline_completions_policy,
 6537            MenuInlineCompletionsPolicy::ByProvider
 6538        );
 6539
 6540        let show_in_menu = by_provider
 6541            && self
 6542                .edit_prediction_provider
 6543                .as_ref()
 6544                .map_or(false, |provider| {
 6545                    provider.provider.show_completions_in_menu()
 6546                });
 6547
 6548        let preview_requires_modifier =
 6549            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6550
 6551        EditPredictionSettings::Enabled {
 6552            show_in_menu,
 6553            preview_requires_modifier,
 6554        }
 6555    }
 6556
 6557    fn should_show_edit_predictions(&self) -> bool {
 6558        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6559    }
 6560
 6561    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6562        matches!(
 6563            self.edit_prediction_preview,
 6564            EditPredictionPreview::Active { .. }
 6565        )
 6566    }
 6567
 6568    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6569        let cursor = self.selections.newest_anchor().head();
 6570        if let Some((buffer, cursor_position)) =
 6571            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6572        {
 6573            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6574        } else {
 6575            false
 6576        }
 6577    }
 6578
 6579    pub fn supports_minimap(&self, cx: &App) -> bool {
 6580        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6581    }
 6582
 6583    fn edit_predictions_enabled_in_buffer(
 6584        &self,
 6585        buffer: &Entity<Buffer>,
 6586        buffer_position: language::Anchor,
 6587        cx: &App,
 6588    ) -> bool {
 6589        maybe!({
 6590            if self.read_only(cx) {
 6591                return Some(false);
 6592            }
 6593            let provider = self.edit_prediction_provider()?;
 6594            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6595                return Some(false);
 6596            }
 6597            let buffer = buffer.read(cx);
 6598            let Some(file) = buffer.file() else {
 6599                return Some(true);
 6600            };
 6601            let settings = all_language_settings(Some(file), cx);
 6602            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6603        })
 6604        .unwrap_or(false)
 6605    }
 6606
 6607    fn cycle_inline_completion(
 6608        &mut self,
 6609        direction: Direction,
 6610        window: &mut Window,
 6611        cx: &mut Context<Self>,
 6612    ) -> Option<()> {
 6613        let provider = self.edit_prediction_provider()?;
 6614        let cursor = self.selections.newest_anchor().head();
 6615        let (buffer, cursor_buffer_position) =
 6616            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6617        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6618            return None;
 6619        }
 6620
 6621        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6622        self.update_visible_inline_completion(window, cx);
 6623
 6624        Some(())
 6625    }
 6626
 6627    pub fn show_inline_completion(
 6628        &mut self,
 6629        _: &ShowEditPrediction,
 6630        window: &mut Window,
 6631        cx: &mut Context<Self>,
 6632    ) {
 6633        if !self.has_active_inline_completion() {
 6634            self.refresh_inline_completion(false, true, window, cx);
 6635            return;
 6636        }
 6637
 6638        self.update_visible_inline_completion(window, cx);
 6639    }
 6640
 6641    pub fn display_cursor_names(
 6642        &mut self,
 6643        _: &DisplayCursorNames,
 6644        window: &mut Window,
 6645        cx: &mut Context<Self>,
 6646    ) {
 6647        self.show_cursor_names(window, cx);
 6648    }
 6649
 6650    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6651        self.show_cursor_names = true;
 6652        cx.notify();
 6653        cx.spawn_in(window, async move |this, cx| {
 6654            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6655            this.update(cx, |this, cx| {
 6656                this.show_cursor_names = false;
 6657                cx.notify()
 6658            })
 6659            .ok()
 6660        })
 6661        .detach();
 6662    }
 6663
 6664    pub fn next_edit_prediction(
 6665        &mut self,
 6666        _: &NextEditPrediction,
 6667        window: &mut Window,
 6668        cx: &mut Context<Self>,
 6669    ) {
 6670        if self.has_active_inline_completion() {
 6671            self.cycle_inline_completion(Direction::Next, window, cx);
 6672        } else {
 6673            let is_copilot_disabled = self
 6674                .refresh_inline_completion(false, true, window, cx)
 6675                .is_none();
 6676            if is_copilot_disabled {
 6677                cx.propagate();
 6678            }
 6679        }
 6680    }
 6681
 6682    pub fn previous_edit_prediction(
 6683        &mut self,
 6684        _: &PreviousEditPrediction,
 6685        window: &mut Window,
 6686        cx: &mut Context<Self>,
 6687    ) {
 6688        if self.has_active_inline_completion() {
 6689            self.cycle_inline_completion(Direction::Prev, window, cx);
 6690        } else {
 6691            let is_copilot_disabled = self
 6692                .refresh_inline_completion(false, true, window, cx)
 6693                .is_none();
 6694            if is_copilot_disabled {
 6695                cx.propagate();
 6696            }
 6697        }
 6698    }
 6699
 6700    pub fn accept_edit_prediction(
 6701        &mut self,
 6702        _: &AcceptEditPrediction,
 6703        window: &mut Window,
 6704        cx: &mut Context<Self>,
 6705    ) {
 6706        if self.show_edit_predictions_in_menu() {
 6707            self.hide_context_menu(window, cx);
 6708        }
 6709
 6710        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6711            return;
 6712        };
 6713
 6714        self.report_inline_completion_event(
 6715            active_inline_completion.completion_id.clone(),
 6716            true,
 6717            cx,
 6718        );
 6719
 6720        match &active_inline_completion.completion {
 6721            InlineCompletion::Move { target, .. } => {
 6722                let target = *target;
 6723
 6724                if let Some(position_map) = &self.last_position_map {
 6725                    if position_map
 6726                        .visible_row_range
 6727                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6728                        || !self.edit_prediction_requires_modifier()
 6729                    {
 6730                        self.unfold_ranges(&[target..target], true, false, cx);
 6731                        // Note that this is also done in vim's handler of the Tab action.
 6732                        self.change_selections(
 6733                            Some(Autoscroll::newest()),
 6734                            window,
 6735                            cx,
 6736                            |selections| {
 6737                                selections.select_anchor_ranges([target..target]);
 6738                            },
 6739                        );
 6740                        self.clear_row_highlights::<EditPredictionPreview>();
 6741
 6742                        self.edit_prediction_preview
 6743                            .set_previous_scroll_position(None);
 6744                    } else {
 6745                        self.edit_prediction_preview
 6746                            .set_previous_scroll_position(Some(
 6747                                position_map.snapshot.scroll_anchor,
 6748                            ));
 6749
 6750                        self.highlight_rows::<EditPredictionPreview>(
 6751                            target..target,
 6752                            cx.theme().colors().editor_highlighted_line_background,
 6753                            RowHighlightOptions {
 6754                                autoscroll: true,
 6755                                ..Default::default()
 6756                            },
 6757                            cx,
 6758                        );
 6759                        self.request_autoscroll(Autoscroll::fit(), cx);
 6760                    }
 6761                }
 6762            }
 6763            InlineCompletion::Edit { edits, .. } => {
 6764                if let Some(provider) = self.edit_prediction_provider() {
 6765                    provider.accept(cx);
 6766                }
 6767
 6768                // Store the transaction ID and selections before applying the edit
 6769                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 6770
 6771                let snapshot = self.buffer.read(cx).snapshot(cx);
 6772                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6773
 6774                self.buffer.update(cx, |buffer, cx| {
 6775                    buffer.edit(edits.iter().cloned(), None, cx)
 6776                });
 6777
 6778                self.change_selections(None, window, cx, |s| {
 6779                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6780                });
 6781
 6782                let selections = self.selections.disjoint_anchors();
 6783                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 6784                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6785                    if has_new_transaction {
 6786                        self.selection_history
 6787                            .insert_transaction(transaction_id_now, selections);
 6788                    }
 6789                }
 6790
 6791                self.update_visible_inline_completion(window, cx);
 6792                if self.active_inline_completion.is_none() {
 6793                    self.refresh_inline_completion(true, true, window, cx);
 6794                }
 6795
 6796                cx.notify();
 6797            }
 6798        }
 6799
 6800        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6801    }
 6802
 6803    pub fn accept_partial_inline_completion(
 6804        &mut self,
 6805        _: &AcceptPartialEditPrediction,
 6806        window: &mut Window,
 6807        cx: &mut Context<Self>,
 6808    ) {
 6809        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6810            return;
 6811        };
 6812        if self.selections.count() != 1 {
 6813            return;
 6814        }
 6815
 6816        self.report_inline_completion_event(
 6817            active_inline_completion.completion_id.clone(),
 6818            true,
 6819            cx,
 6820        );
 6821
 6822        match &active_inline_completion.completion {
 6823            InlineCompletion::Move { target, .. } => {
 6824                let target = *target;
 6825                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6826                    selections.select_anchor_ranges([target..target]);
 6827                });
 6828            }
 6829            InlineCompletion::Edit { edits, .. } => {
 6830                // Find an insertion that starts at the cursor position.
 6831                let snapshot = self.buffer.read(cx).snapshot(cx);
 6832                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6833                let insertion = edits.iter().find_map(|(range, text)| {
 6834                    let range = range.to_offset(&snapshot);
 6835                    if range.is_empty() && range.start == cursor_offset {
 6836                        Some(text)
 6837                    } else {
 6838                        None
 6839                    }
 6840                });
 6841
 6842                if let Some(text) = insertion {
 6843                    let mut partial_completion = text
 6844                        .chars()
 6845                        .by_ref()
 6846                        .take_while(|c| c.is_alphabetic())
 6847                        .collect::<String>();
 6848                    if partial_completion.is_empty() {
 6849                        partial_completion = text
 6850                            .chars()
 6851                            .by_ref()
 6852                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6853                            .collect::<String>();
 6854                    }
 6855
 6856                    cx.emit(EditorEvent::InputHandled {
 6857                        utf16_range_to_replace: None,
 6858                        text: partial_completion.clone().into(),
 6859                    });
 6860
 6861                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6862
 6863                    self.refresh_inline_completion(true, true, window, cx);
 6864                    cx.notify();
 6865                } else {
 6866                    self.accept_edit_prediction(&Default::default(), window, cx);
 6867                }
 6868            }
 6869        }
 6870    }
 6871
 6872    fn discard_inline_completion(
 6873        &mut self,
 6874        should_report_inline_completion_event: bool,
 6875        cx: &mut Context<Self>,
 6876    ) -> bool {
 6877        if should_report_inline_completion_event {
 6878            let completion_id = self
 6879                .active_inline_completion
 6880                .as_ref()
 6881                .and_then(|active_completion| active_completion.completion_id.clone());
 6882
 6883            self.report_inline_completion_event(completion_id, false, cx);
 6884        }
 6885
 6886        if let Some(provider) = self.edit_prediction_provider() {
 6887            provider.discard(cx);
 6888        }
 6889
 6890        self.take_active_inline_completion(cx)
 6891    }
 6892
 6893    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6894        let Some(provider) = self.edit_prediction_provider() else {
 6895            return;
 6896        };
 6897
 6898        let Some((_, buffer, _)) = self
 6899            .buffer
 6900            .read(cx)
 6901            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6902        else {
 6903            return;
 6904        };
 6905
 6906        let extension = buffer
 6907            .read(cx)
 6908            .file()
 6909            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6910
 6911        let event_type = match accepted {
 6912            true => "Edit Prediction Accepted",
 6913            false => "Edit Prediction Discarded",
 6914        };
 6915        telemetry::event!(
 6916            event_type,
 6917            provider = provider.name(),
 6918            prediction_id = id,
 6919            suggestion_accepted = accepted,
 6920            file_extension = extension,
 6921        );
 6922    }
 6923
 6924    pub fn has_active_inline_completion(&self) -> bool {
 6925        self.active_inline_completion.is_some()
 6926    }
 6927
 6928    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6929        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6930            return false;
 6931        };
 6932
 6933        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6934        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6935        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6936        true
 6937    }
 6938
 6939    /// Returns true when we're displaying the edit prediction popover below the cursor
 6940    /// like we are not previewing and the LSP autocomplete menu is visible
 6941    /// or we are in `when_holding_modifier` mode.
 6942    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6943        if self.edit_prediction_preview_is_active()
 6944            || !self.show_edit_predictions_in_menu()
 6945            || !self.edit_predictions_enabled()
 6946        {
 6947            return false;
 6948        }
 6949
 6950        if self.has_visible_completions_menu() {
 6951            return true;
 6952        }
 6953
 6954        has_completion && self.edit_prediction_requires_modifier()
 6955    }
 6956
 6957    fn handle_modifiers_changed(
 6958        &mut self,
 6959        modifiers: Modifiers,
 6960        position_map: &PositionMap,
 6961        window: &mut Window,
 6962        cx: &mut Context<Self>,
 6963    ) {
 6964        if self.show_edit_predictions_in_menu() {
 6965            self.update_edit_prediction_preview(&modifiers, window, cx);
 6966        }
 6967
 6968        self.update_selection_mode(&modifiers, position_map, window, cx);
 6969
 6970        let mouse_position = window.mouse_position();
 6971        if !position_map.text_hitbox.is_hovered(window) {
 6972            return;
 6973        }
 6974
 6975        self.update_hovered_link(
 6976            position_map.point_for_position(mouse_position),
 6977            &position_map.snapshot,
 6978            modifiers,
 6979            window,
 6980            cx,
 6981        )
 6982    }
 6983
 6984    fn update_selection_mode(
 6985        &mut self,
 6986        modifiers: &Modifiers,
 6987        position_map: &PositionMap,
 6988        window: &mut Window,
 6989        cx: &mut Context<Self>,
 6990    ) {
 6991        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6992            return;
 6993        }
 6994
 6995        let mouse_position = window.mouse_position();
 6996        let point_for_position = position_map.point_for_position(mouse_position);
 6997        let position = point_for_position.previous_valid;
 6998
 6999        self.select(
 7000            SelectPhase::BeginColumnar {
 7001                position,
 7002                reset: false,
 7003                goal_column: point_for_position.exact_unclipped.column(),
 7004            },
 7005            window,
 7006            cx,
 7007        );
 7008    }
 7009
 7010    fn update_edit_prediction_preview(
 7011        &mut self,
 7012        modifiers: &Modifiers,
 7013        window: &mut Window,
 7014        cx: &mut Context<Self>,
 7015    ) {
 7016        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 7017        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 7018            return;
 7019        };
 7020
 7021        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 7022            if matches!(
 7023                self.edit_prediction_preview,
 7024                EditPredictionPreview::Inactive { .. }
 7025            ) {
 7026                self.edit_prediction_preview = EditPredictionPreview::Active {
 7027                    previous_scroll_position: None,
 7028                    since: Instant::now(),
 7029                };
 7030
 7031                self.update_visible_inline_completion(window, cx);
 7032                cx.notify();
 7033            }
 7034        } else if let EditPredictionPreview::Active {
 7035            previous_scroll_position,
 7036            since,
 7037        } = self.edit_prediction_preview
 7038        {
 7039            if let (Some(previous_scroll_position), Some(position_map)) =
 7040                (previous_scroll_position, self.last_position_map.as_ref())
 7041            {
 7042                self.set_scroll_position(
 7043                    previous_scroll_position
 7044                        .scroll_position(&position_map.snapshot.display_snapshot),
 7045                    window,
 7046                    cx,
 7047                );
 7048            }
 7049
 7050            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7051                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7052            };
 7053            self.clear_row_highlights::<EditPredictionPreview>();
 7054            self.update_visible_inline_completion(window, cx);
 7055            cx.notify();
 7056        }
 7057    }
 7058
 7059    fn update_visible_inline_completion(
 7060        &mut self,
 7061        _window: &mut Window,
 7062        cx: &mut Context<Self>,
 7063    ) -> Option<()> {
 7064        let selection = self.selections.newest_anchor();
 7065        let cursor = selection.head();
 7066        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7067        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7068        let excerpt_id = cursor.excerpt_id;
 7069
 7070        let show_in_menu = self.show_edit_predictions_in_menu();
 7071        let completions_menu_has_precedence = !show_in_menu
 7072            && (self.context_menu.borrow().is_some()
 7073                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7074
 7075        if completions_menu_has_precedence
 7076            || !offset_selection.is_empty()
 7077            || self
 7078                .active_inline_completion
 7079                .as_ref()
 7080                .map_or(false, |completion| {
 7081                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7082                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7083                    !invalidation_range.contains(&offset_selection.head())
 7084                })
 7085        {
 7086            self.discard_inline_completion(false, cx);
 7087            return None;
 7088        }
 7089
 7090        self.take_active_inline_completion(cx);
 7091        let Some(provider) = self.edit_prediction_provider() else {
 7092            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7093            return None;
 7094        };
 7095
 7096        let (buffer, cursor_buffer_position) =
 7097            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7098
 7099        self.edit_prediction_settings =
 7100            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7101
 7102        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7103
 7104        if self.edit_prediction_indent_conflict {
 7105            let cursor_point = cursor.to_point(&multibuffer);
 7106
 7107            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7108
 7109            if let Some((_, indent)) = indents.iter().next() {
 7110                if indent.len == cursor_point.column {
 7111                    self.edit_prediction_indent_conflict = false;
 7112                }
 7113            }
 7114        }
 7115
 7116        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7117        let edits = inline_completion
 7118            .edits
 7119            .into_iter()
 7120            .flat_map(|(range, new_text)| {
 7121                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7122                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7123                Some((start..end, new_text))
 7124            })
 7125            .collect::<Vec<_>>();
 7126        if edits.is_empty() {
 7127            return None;
 7128        }
 7129
 7130        let first_edit_start = edits.first().unwrap().0.start;
 7131        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7132        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7133
 7134        let last_edit_end = edits.last().unwrap().0.end;
 7135        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7136        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7137
 7138        let cursor_row = cursor.to_point(&multibuffer).row;
 7139
 7140        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7141
 7142        let mut inlay_ids = Vec::new();
 7143        let invalidation_row_range;
 7144        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7145            Some(cursor_row..edit_end_row)
 7146        } else if cursor_row > edit_end_row {
 7147            Some(edit_start_row..cursor_row)
 7148        } else {
 7149            None
 7150        };
 7151        let is_move =
 7152            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7153        let completion = if is_move {
 7154            invalidation_row_range =
 7155                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7156            let target = first_edit_start;
 7157            InlineCompletion::Move { target, snapshot }
 7158        } else {
 7159            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7160                && !self.inline_completions_hidden_for_vim_mode;
 7161
 7162            if show_completions_in_buffer {
 7163                if edits
 7164                    .iter()
 7165                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7166                {
 7167                    let mut inlays = Vec::new();
 7168                    for (range, new_text) in &edits {
 7169                        let inlay = Inlay::inline_completion(
 7170                            post_inc(&mut self.next_inlay_id),
 7171                            range.start,
 7172                            new_text.as_str(),
 7173                        );
 7174                        inlay_ids.push(inlay.id);
 7175                        inlays.push(inlay);
 7176                    }
 7177
 7178                    self.splice_inlays(&[], inlays, cx);
 7179                } else {
 7180                    let background_color = cx.theme().status().deleted_background;
 7181                    self.highlight_text::<InlineCompletionHighlight>(
 7182                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7183                        HighlightStyle {
 7184                            background_color: Some(background_color),
 7185                            ..Default::default()
 7186                        },
 7187                        cx,
 7188                    );
 7189                }
 7190            }
 7191
 7192            invalidation_row_range = edit_start_row..edit_end_row;
 7193
 7194            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7195                if provider.show_tab_accept_marker() {
 7196                    EditDisplayMode::TabAccept
 7197                } else {
 7198                    EditDisplayMode::Inline
 7199                }
 7200            } else {
 7201                EditDisplayMode::DiffPopover
 7202            };
 7203
 7204            InlineCompletion::Edit {
 7205                edits,
 7206                edit_preview: inline_completion.edit_preview,
 7207                display_mode,
 7208                snapshot,
 7209            }
 7210        };
 7211
 7212        let invalidation_range = multibuffer
 7213            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7214            ..multibuffer.anchor_after(Point::new(
 7215                invalidation_row_range.end,
 7216                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7217            ));
 7218
 7219        self.stale_inline_completion_in_menu = None;
 7220        self.active_inline_completion = Some(InlineCompletionState {
 7221            inlay_ids,
 7222            completion,
 7223            completion_id: inline_completion.id,
 7224            invalidation_range,
 7225        });
 7226
 7227        cx.notify();
 7228
 7229        Some(())
 7230    }
 7231
 7232    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7233        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7234    }
 7235
 7236    fn clear_tasks(&mut self) {
 7237        self.tasks.clear()
 7238    }
 7239
 7240    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7241        if self.tasks.insert(key, value).is_some() {
 7242            // This case should hopefully be rare, but just in case...
 7243            log::error!(
 7244                "multiple different run targets found on a single line, only the last target will be rendered"
 7245            )
 7246        }
 7247    }
 7248
 7249    /// Get all display points of breakpoints that will be rendered within editor
 7250    ///
 7251    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7252    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7253    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7254    fn active_breakpoints(
 7255        &self,
 7256        range: Range<DisplayRow>,
 7257        window: &mut Window,
 7258        cx: &mut Context<Self>,
 7259    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7260        let mut breakpoint_display_points = HashMap::default();
 7261
 7262        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7263            return breakpoint_display_points;
 7264        };
 7265
 7266        let snapshot = self.snapshot(window, cx);
 7267
 7268        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7269        let Some(project) = self.project.as_ref() else {
 7270            return breakpoint_display_points;
 7271        };
 7272
 7273        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7274            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7275
 7276        for (buffer_snapshot, range, excerpt_id) in
 7277            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7278        {
 7279            let Some(buffer) = project
 7280                .read(cx)
 7281                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7282            else {
 7283                continue;
 7284            };
 7285            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7286                &buffer,
 7287                Some(
 7288                    buffer_snapshot.anchor_before(range.start)
 7289                        ..buffer_snapshot.anchor_after(range.end),
 7290                ),
 7291                buffer_snapshot,
 7292                cx,
 7293            );
 7294            for (breakpoint, state) in breakpoints {
 7295                let multi_buffer_anchor =
 7296                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7297                let position = multi_buffer_anchor
 7298                    .to_point(&multi_buffer_snapshot)
 7299                    .to_display_point(&snapshot);
 7300
 7301                breakpoint_display_points.insert(
 7302                    position.row(),
 7303                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7304                );
 7305            }
 7306        }
 7307
 7308        breakpoint_display_points
 7309    }
 7310
 7311    fn breakpoint_context_menu(
 7312        &self,
 7313        anchor: Anchor,
 7314        window: &mut Window,
 7315        cx: &mut Context<Self>,
 7316    ) -> Entity<ui::ContextMenu> {
 7317        let weak_editor = cx.weak_entity();
 7318        let focus_handle = self.focus_handle(cx);
 7319
 7320        let row = self
 7321            .buffer
 7322            .read(cx)
 7323            .snapshot(cx)
 7324            .summary_for_anchor::<Point>(&anchor)
 7325            .row;
 7326
 7327        let breakpoint = self
 7328            .breakpoint_at_row(row, window, cx)
 7329            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7330
 7331        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7332            "Edit Log Breakpoint"
 7333        } else {
 7334            "Set Log Breakpoint"
 7335        };
 7336
 7337        let condition_breakpoint_msg = if breakpoint
 7338            .as_ref()
 7339            .is_some_and(|bp| bp.1.condition.is_some())
 7340        {
 7341            "Edit Condition Breakpoint"
 7342        } else {
 7343            "Set Condition Breakpoint"
 7344        };
 7345
 7346        let hit_condition_breakpoint_msg = if breakpoint
 7347            .as_ref()
 7348            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7349        {
 7350            "Edit Hit Condition Breakpoint"
 7351        } else {
 7352            "Set Hit Condition Breakpoint"
 7353        };
 7354
 7355        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7356            "Unset Breakpoint"
 7357        } else {
 7358            "Set Breakpoint"
 7359        };
 7360
 7361        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7362            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7363
 7364        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7365            BreakpointState::Enabled => Some("Disable"),
 7366            BreakpointState::Disabled => Some("Enable"),
 7367        });
 7368
 7369        let (anchor, breakpoint) =
 7370            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7371
 7372        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7373            menu.on_blur_subscription(Subscription::new(|| {}))
 7374                .context(focus_handle)
 7375                .when(run_to_cursor, |this| {
 7376                    let weak_editor = weak_editor.clone();
 7377                    this.entry("Run to cursor", None, move |window, cx| {
 7378                        weak_editor
 7379                            .update(cx, |editor, cx| {
 7380                                editor.change_selections(None, window, cx, |s| {
 7381                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7382                                });
 7383                            })
 7384                            .ok();
 7385
 7386                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7387                    })
 7388                    .separator()
 7389                })
 7390                .when_some(toggle_state_msg, |this, msg| {
 7391                    this.entry(msg, None, {
 7392                        let weak_editor = weak_editor.clone();
 7393                        let breakpoint = breakpoint.clone();
 7394                        move |_window, cx| {
 7395                            weak_editor
 7396                                .update(cx, |this, cx| {
 7397                                    this.edit_breakpoint_at_anchor(
 7398                                        anchor,
 7399                                        breakpoint.as_ref().clone(),
 7400                                        BreakpointEditAction::InvertState,
 7401                                        cx,
 7402                                    );
 7403                                })
 7404                                .log_err();
 7405                        }
 7406                    })
 7407                })
 7408                .entry(set_breakpoint_msg, None, {
 7409                    let weak_editor = weak_editor.clone();
 7410                    let breakpoint = breakpoint.clone();
 7411                    move |_window, cx| {
 7412                        weak_editor
 7413                            .update(cx, |this, cx| {
 7414                                this.edit_breakpoint_at_anchor(
 7415                                    anchor,
 7416                                    breakpoint.as_ref().clone(),
 7417                                    BreakpointEditAction::Toggle,
 7418                                    cx,
 7419                                );
 7420                            })
 7421                            .log_err();
 7422                    }
 7423                })
 7424                .entry(log_breakpoint_msg, None, {
 7425                    let breakpoint = breakpoint.clone();
 7426                    let weak_editor = weak_editor.clone();
 7427                    move |window, cx| {
 7428                        weak_editor
 7429                            .update(cx, |this, cx| {
 7430                                this.add_edit_breakpoint_block(
 7431                                    anchor,
 7432                                    breakpoint.as_ref(),
 7433                                    BreakpointPromptEditAction::Log,
 7434                                    window,
 7435                                    cx,
 7436                                );
 7437                            })
 7438                            .log_err();
 7439                    }
 7440                })
 7441                .entry(condition_breakpoint_msg, None, {
 7442                    let breakpoint = breakpoint.clone();
 7443                    let weak_editor = weak_editor.clone();
 7444                    move |window, cx| {
 7445                        weak_editor
 7446                            .update(cx, |this, cx| {
 7447                                this.add_edit_breakpoint_block(
 7448                                    anchor,
 7449                                    breakpoint.as_ref(),
 7450                                    BreakpointPromptEditAction::Condition,
 7451                                    window,
 7452                                    cx,
 7453                                );
 7454                            })
 7455                            .log_err();
 7456                    }
 7457                })
 7458                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7459                    weak_editor
 7460                        .update(cx, |this, cx| {
 7461                            this.add_edit_breakpoint_block(
 7462                                anchor,
 7463                                breakpoint.as_ref(),
 7464                                BreakpointPromptEditAction::HitCondition,
 7465                                window,
 7466                                cx,
 7467                            );
 7468                        })
 7469                        .log_err();
 7470                })
 7471        })
 7472    }
 7473
 7474    fn render_breakpoint(
 7475        &self,
 7476        position: Anchor,
 7477        row: DisplayRow,
 7478        breakpoint: &Breakpoint,
 7479        state: Option<BreakpointSessionState>,
 7480        cx: &mut Context<Self>,
 7481    ) -> IconButton {
 7482        let is_rejected = state.is_some_and(|s| !s.verified);
 7483        // Is it a breakpoint that shows up when hovering over gutter?
 7484        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7485            (false, false),
 7486            |PhantomBreakpointIndicator {
 7487                 is_active,
 7488                 display_row,
 7489                 collides_with_existing_breakpoint,
 7490             }| {
 7491                (
 7492                    is_active && display_row == row,
 7493                    collides_with_existing_breakpoint,
 7494                )
 7495            },
 7496        );
 7497
 7498        let (color, icon) = {
 7499            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7500                (false, false) => ui::IconName::DebugBreakpoint,
 7501                (true, false) => ui::IconName::DebugLogBreakpoint,
 7502                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7503                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7504            };
 7505
 7506            let color = if is_phantom {
 7507                Color::Hint
 7508            } else if is_rejected {
 7509                Color::Disabled
 7510            } else {
 7511                Color::Debugger
 7512            };
 7513
 7514            (color, icon)
 7515        };
 7516
 7517        let breakpoint = Arc::from(breakpoint.clone());
 7518
 7519        let alt_as_text = gpui::Keystroke {
 7520            modifiers: Modifiers::secondary_key(),
 7521            ..Default::default()
 7522        };
 7523        let primary_action_text = if breakpoint.is_disabled() {
 7524            "Enable breakpoint"
 7525        } else if is_phantom && !collides_with_existing {
 7526            "Set breakpoint"
 7527        } else {
 7528            "Unset breakpoint"
 7529        };
 7530        let focus_handle = self.focus_handle.clone();
 7531
 7532        let meta = if is_rejected {
 7533            SharedString::from("No executable code is associated with this line.")
 7534        } else if collides_with_existing && !breakpoint.is_disabled() {
 7535            SharedString::from(format!(
 7536                "{alt_as_text}-click to disable,\nright-click for more options."
 7537            ))
 7538        } else {
 7539            SharedString::from("Right-click for more options.")
 7540        };
 7541        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7542            .icon_size(IconSize::XSmall)
 7543            .size(ui::ButtonSize::None)
 7544            .when(is_rejected, |this| {
 7545                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7546            })
 7547            .icon_color(color)
 7548            .style(ButtonStyle::Transparent)
 7549            .on_click(cx.listener({
 7550                let breakpoint = breakpoint.clone();
 7551
 7552                move |editor, event: &ClickEvent, window, cx| {
 7553                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7554                        BreakpointEditAction::InvertState
 7555                    } else {
 7556                        BreakpointEditAction::Toggle
 7557                    };
 7558
 7559                    window.focus(&editor.focus_handle(cx));
 7560                    editor.edit_breakpoint_at_anchor(
 7561                        position,
 7562                        breakpoint.as_ref().clone(),
 7563                        edit_action,
 7564                        cx,
 7565                    );
 7566                }
 7567            }))
 7568            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7569                editor.set_breakpoint_context_menu(
 7570                    row,
 7571                    Some(position),
 7572                    event.down.position,
 7573                    window,
 7574                    cx,
 7575                );
 7576            }))
 7577            .tooltip(move |window, cx| {
 7578                Tooltip::with_meta_in(
 7579                    primary_action_text,
 7580                    Some(&ToggleBreakpoint),
 7581                    meta.clone(),
 7582                    &focus_handle,
 7583                    window,
 7584                    cx,
 7585                )
 7586            })
 7587    }
 7588
 7589    fn build_tasks_context(
 7590        project: &Entity<Project>,
 7591        buffer: &Entity<Buffer>,
 7592        buffer_row: u32,
 7593        tasks: &Arc<RunnableTasks>,
 7594        cx: &mut Context<Self>,
 7595    ) -> Task<Option<task::TaskContext>> {
 7596        let position = Point::new(buffer_row, tasks.column);
 7597        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7598        let location = Location {
 7599            buffer: buffer.clone(),
 7600            range: range_start..range_start,
 7601        };
 7602        // Fill in the environmental variables from the tree-sitter captures
 7603        let mut captured_task_variables = TaskVariables::default();
 7604        for (capture_name, value) in tasks.extra_variables.clone() {
 7605            captured_task_variables.insert(
 7606                task::VariableName::Custom(capture_name.into()),
 7607                value.clone(),
 7608            );
 7609        }
 7610        project.update(cx, |project, cx| {
 7611            project.task_store().update(cx, |task_store, cx| {
 7612                task_store.task_context_for_location(captured_task_variables, location, cx)
 7613            })
 7614        })
 7615    }
 7616
 7617    pub fn spawn_nearest_task(
 7618        &mut self,
 7619        action: &SpawnNearestTask,
 7620        window: &mut Window,
 7621        cx: &mut Context<Self>,
 7622    ) {
 7623        let Some((workspace, _)) = self.workspace.clone() else {
 7624            return;
 7625        };
 7626        let Some(project) = self.project.clone() else {
 7627            return;
 7628        };
 7629
 7630        // Try to find a closest, enclosing node using tree-sitter that has a
 7631        // task
 7632        let Some((buffer, buffer_row, tasks)) = self
 7633            .find_enclosing_node_task(cx)
 7634            // Or find the task that's closest in row-distance.
 7635            .or_else(|| self.find_closest_task(cx))
 7636        else {
 7637            return;
 7638        };
 7639
 7640        let reveal_strategy = action.reveal;
 7641        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7642        cx.spawn_in(window, async move |_, cx| {
 7643            let context = task_context.await?;
 7644            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7645
 7646            let resolved = &mut resolved_task.resolved;
 7647            resolved.reveal = reveal_strategy;
 7648
 7649            workspace
 7650                .update_in(cx, |workspace, window, cx| {
 7651                    workspace.schedule_resolved_task(
 7652                        task_source_kind,
 7653                        resolved_task,
 7654                        false,
 7655                        window,
 7656                        cx,
 7657                    );
 7658                })
 7659                .ok()
 7660        })
 7661        .detach();
 7662    }
 7663
 7664    fn find_closest_task(
 7665        &mut self,
 7666        cx: &mut Context<Self>,
 7667    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7668        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7669
 7670        let ((buffer_id, row), tasks) = self
 7671            .tasks
 7672            .iter()
 7673            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7674
 7675        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7676        let tasks = Arc::new(tasks.to_owned());
 7677        Some((buffer, *row, tasks))
 7678    }
 7679
 7680    fn find_enclosing_node_task(
 7681        &mut self,
 7682        cx: &mut Context<Self>,
 7683    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7684        let snapshot = self.buffer.read(cx).snapshot(cx);
 7685        let offset = self.selections.newest::<usize>(cx).head();
 7686        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7687        let buffer_id = excerpt.buffer().remote_id();
 7688
 7689        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7690        let mut cursor = layer.node().walk();
 7691
 7692        while cursor.goto_first_child_for_byte(offset).is_some() {
 7693            if cursor.node().end_byte() == offset {
 7694                cursor.goto_next_sibling();
 7695            }
 7696        }
 7697
 7698        // Ascend to the smallest ancestor that contains the range and has a task.
 7699        loop {
 7700            let node = cursor.node();
 7701            let node_range = node.byte_range();
 7702            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7703
 7704            // Check if this node contains our offset
 7705            if node_range.start <= offset && node_range.end >= offset {
 7706                // If it contains offset, check for task
 7707                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7708                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7709                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7710                }
 7711            }
 7712
 7713            if !cursor.goto_parent() {
 7714                break;
 7715            }
 7716        }
 7717        None
 7718    }
 7719
 7720    fn render_run_indicator(
 7721        &self,
 7722        _style: &EditorStyle,
 7723        is_active: bool,
 7724        row: DisplayRow,
 7725        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7726        cx: &mut Context<Self>,
 7727    ) -> IconButton {
 7728        let color = Color::Muted;
 7729        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7730
 7731        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7732            .shape(ui::IconButtonShape::Square)
 7733            .icon_size(IconSize::XSmall)
 7734            .icon_color(color)
 7735            .toggle_state(is_active)
 7736            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7737                let quick_launch = e.down.button == MouseButton::Left;
 7738                window.focus(&editor.focus_handle(cx));
 7739                editor.toggle_code_actions(
 7740                    &ToggleCodeActions {
 7741                        deployed_from: Some(CodeActionSource::Indicator(row)),
 7742                        quick_launch,
 7743                    },
 7744                    window,
 7745                    cx,
 7746                );
 7747            }))
 7748            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7749                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7750            }))
 7751    }
 7752
 7753    pub fn context_menu_visible(&self) -> bool {
 7754        !self.edit_prediction_preview_is_active()
 7755            && self
 7756                .context_menu
 7757                .borrow()
 7758                .as_ref()
 7759                .map_or(false, |menu| menu.visible())
 7760    }
 7761
 7762    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7763        self.context_menu
 7764            .borrow()
 7765            .as_ref()
 7766            .map(|menu| menu.origin())
 7767    }
 7768
 7769    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7770        self.context_menu_options = Some(options);
 7771    }
 7772
 7773    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7774    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7775
 7776    fn render_edit_prediction_popover(
 7777        &mut self,
 7778        text_bounds: &Bounds<Pixels>,
 7779        content_origin: gpui::Point<Pixels>,
 7780        right_margin: Pixels,
 7781        editor_snapshot: &EditorSnapshot,
 7782        visible_row_range: Range<DisplayRow>,
 7783        scroll_top: f32,
 7784        scroll_bottom: f32,
 7785        line_layouts: &[LineWithInvisibles],
 7786        line_height: Pixels,
 7787        scroll_pixel_position: gpui::Point<Pixels>,
 7788        newest_selection_head: Option<DisplayPoint>,
 7789        editor_width: Pixels,
 7790        style: &EditorStyle,
 7791        window: &mut Window,
 7792        cx: &mut App,
 7793    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7794        if self.mode().is_minimap() {
 7795            return None;
 7796        }
 7797        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7798
 7799        if self.edit_prediction_visible_in_cursor_popover(true) {
 7800            return None;
 7801        }
 7802
 7803        match &active_inline_completion.completion {
 7804            InlineCompletion::Move { target, .. } => {
 7805                let target_display_point = target.to_display_point(editor_snapshot);
 7806
 7807                if self.edit_prediction_requires_modifier() {
 7808                    if !self.edit_prediction_preview_is_active() {
 7809                        return None;
 7810                    }
 7811
 7812                    self.render_edit_prediction_modifier_jump_popover(
 7813                        text_bounds,
 7814                        content_origin,
 7815                        visible_row_range,
 7816                        line_layouts,
 7817                        line_height,
 7818                        scroll_pixel_position,
 7819                        newest_selection_head,
 7820                        target_display_point,
 7821                        window,
 7822                        cx,
 7823                    )
 7824                } else {
 7825                    self.render_edit_prediction_eager_jump_popover(
 7826                        text_bounds,
 7827                        content_origin,
 7828                        editor_snapshot,
 7829                        visible_row_range,
 7830                        scroll_top,
 7831                        scroll_bottom,
 7832                        line_height,
 7833                        scroll_pixel_position,
 7834                        target_display_point,
 7835                        editor_width,
 7836                        window,
 7837                        cx,
 7838                    )
 7839                }
 7840            }
 7841            InlineCompletion::Edit {
 7842                display_mode: EditDisplayMode::Inline,
 7843                ..
 7844            } => None,
 7845            InlineCompletion::Edit {
 7846                display_mode: EditDisplayMode::TabAccept,
 7847                edits,
 7848                ..
 7849            } => {
 7850                let range = &edits.first()?.0;
 7851                let target_display_point = range.end.to_display_point(editor_snapshot);
 7852
 7853                self.render_edit_prediction_end_of_line_popover(
 7854                    "Accept",
 7855                    editor_snapshot,
 7856                    visible_row_range,
 7857                    target_display_point,
 7858                    line_height,
 7859                    scroll_pixel_position,
 7860                    content_origin,
 7861                    editor_width,
 7862                    window,
 7863                    cx,
 7864                )
 7865            }
 7866            InlineCompletion::Edit {
 7867                edits,
 7868                edit_preview,
 7869                display_mode: EditDisplayMode::DiffPopover,
 7870                snapshot,
 7871            } => self.render_edit_prediction_diff_popover(
 7872                text_bounds,
 7873                content_origin,
 7874                right_margin,
 7875                editor_snapshot,
 7876                visible_row_range,
 7877                line_layouts,
 7878                line_height,
 7879                scroll_pixel_position,
 7880                newest_selection_head,
 7881                editor_width,
 7882                style,
 7883                edits,
 7884                edit_preview,
 7885                snapshot,
 7886                window,
 7887                cx,
 7888            ),
 7889        }
 7890    }
 7891
 7892    fn render_edit_prediction_modifier_jump_popover(
 7893        &mut self,
 7894        text_bounds: &Bounds<Pixels>,
 7895        content_origin: gpui::Point<Pixels>,
 7896        visible_row_range: Range<DisplayRow>,
 7897        line_layouts: &[LineWithInvisibles],
 7898        line_height: Pixels,
 7899        scroll_pixel_position: gpui::Point<Pixels>,
 7900        newest_selection_head: Option<DisplayPoint>,
 7901        target_display_point: DisplayPoint,
 7902        window: &mut Window,
 7903        cx: &mut App,
 7904    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7905        let scrolled_content_origin =
 7906            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7907
 7908        const SCROLL_PADDING_Y: Pixels = px(12.);
 7909
 7910        if target_display_point.row() < visible_row_range.start {
 7911            return self.render_edit_prediction_scroll_popover(
 7912                |_| SCROLL_PADDING_Y,
 7913                IconName::ArrowUp,
 7914                visible_row_range,
 7915                line_layouts,
 7916                newest_selection_head,
 7917                scrolled_content_origin,
 7918                window,
 7919                cx,
 7920            );
 7921        } else if target_display_point.row() >= visible_row_range.end {
 7922            return self.render_edit_prediction_scroll_popover(
 7923                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7924                IconName::ArrowDown,
 7925                visible_row_range,
 7926                line_layouts,
 7927                newest_selection_head,
 7928                scrolled_content_origin,
 7929                window,
 7930                cx,
 7931            );
 7932        }
 7933
 7934        const POLE_WIDTH: Pixels = px(2.);
 7935
 7936        let line_layout =
 7937            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7938        let target_column = target_display_point.column() as usize;
 7939
 7940        let target_x = line_layout.x_for_index(target_column);
 7941        let target_y =
 7942            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7943
 7944        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7945
 7946        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7947        border_color.l += 0.001;
 7948
 7949        let mut element = v_flex()
 7950            .items_end()
 7951            .when(flag_on_right, |el| el.items_start())
 7952            .child(if flag_on_right {
 7953                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7954                    .rounded_bl(px(0.))
 7955                    .rounded_tl(px(0.))
 7956                    .border_l_2()
 7957                    .border_color(border_color)
 7958            } else {
 7959                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7960                    .rounded_br(px(0.))
 7961                    .rounded_tr(px(0.))
 7962                    .border_r_2()
 7963                    .border_color(border_color)
 7964            })
 7965            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7966            .into_any();
 7967
 7968        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7969
 7970        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7971            - point(
 7972                if flag_on_right {
 7973                    POLE_WIDTH
 7974                } else {
 7975                    size.width - POLE_WIDTH
 7976                },
 7977                size.height - line_height,
 7978            );
 7979
 7980        origin.x = origin.x.max(content_origin.x);
 7981
 7982        element.prepaint_at(origin, window, cx);
 7983
 7984        Some((element, origin))
 7985    }
 7986
 7987    fn render_edit_prediction_scroll_popover(
 7988        &mut self,
 7989        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7990        scroll_icon: IconName,
 7991        visible_row_range: Range<DisplayRow>,
 7992        line_layouts: &[LineWithInvisibles],
 7993        newest_selection_head: Option<DisplayPoint>,
 7994        scrolled_content_origin: gpui::Point<Pixels>,
 7995        window: &mut Window,
 7996        cx: &mut App,
 7997    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7998        let mut element = self
 7999            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8000            .into_any();
 8001
 8002        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8003
 8004        let cursor = newest_selection_head?;
 8005        let cursor_row_layout =
 8006            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8007        let cursor_column = cursor.column() as usize;
 8008
 8009        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8010
 8011        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8012
 8013        element.prepaint_at(origin, window, cx);
 8014        Some((element, origin))
 8015    }
 8016
 8017    fn render_edit_prediction_eager_jump_popover(
 8018        &mut self,
 8019        text_bounds: &Bounds<Pixels>,
 8020        content_origin: gpui::Point<Pixels>,
 8021        editor_snapshot: &EditorSnapshot,
 8022        visible_row_range: Range<DisplayRow>,
 8023        scroll_top: f32,
 8024        scroll_bottom: f32,
 8025        line_height: Pixels,
 8026        scroll_pixel_position: gpui::Point<Pixels>,
 8027        target_display_point: DisplayPoint,
 8028        editor_width: Pixels,
 8029        window: &mut Window,
 8030        cx: &mut App,
 8031    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8032        if target_display_point.row().as_f32() < scroll_top {
 8033            let mut element = self
 8034                .render_edit_prediction_line_popover(
 8035                    "Jump to Edit",
 8036                    Some(IconName::ArrowUp),
 8037                    window,
 8038                    cx,
 8039                )?
 8040                .into_any();
 8041
 8042            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8043            let offset = point(
 8044                (text_bounds.size.width - size.width) / 2.,
 8045                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8046            );
 8047
 8048            let origin = text_bounds.origin + offset;
 8049            element.prepaint_at(origin, window, cx);
 8050            Some((element, origin))
 8051        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8052            let mut element = self
 8053                .render_edit_prediction_line_popover(
 8054                    "Jump to Edit",
 8055                    Some(IconName::ArrowDown),
 8056                    window,
 8057                    cx,
 8058                )?
 8059                .into_any();
 8060
 8061            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8062            let offset = point(
 8063                (text_bounds.size.width - size.width) / 2.,
 8064                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8065            );
 8066
 8067            let origin = text_bounds.origin + offset;
 8068            element.prepaint_at(origin, window, cx);
 8069            Some((element, origin))
 8070        } else {
 8071            self.render_edit_prediction_end_of_line_popover(
 8072                "Jump to Edit",
 8073                editor_snapshot,
 8074                visible_row_range,
 8075                target_display_point,
 8076                line_height,
 8077                scroll_pixel_position,
 8078                content_origin,
 8079                editor_width,
 8080                window,
 8081                cx,
 8082            )
 8083        }
 8084    }
 8085
 8086    fn render_edit_prediction_end_of_line_popover(
 8087        self: &mut Editor,
 8088        label: &'static str,
 8089        editor_snapshot: &EditorSnapshot,
 8090        visible_row_range: Range<DisplayRow>,
 8091        target_display_point: DisplayPoint,
 8092        line_height: Pixels,
 8093        scroll_pixel_position: gpui::Point<Pixels>,
 8094        content_origin: gpui::Point<Pixels>,
 8095        editor_width: Pixels,
 8096        window: &mut Window,
 8097        cx: &mut App,
 8098    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8099        let target_line_end = DisplayPoint::new(
 8100            target_display_point.row(),
 8101            editor_snapshot.line_len(target_display_point.row()),
 8102        );
 8103
 8104        let mut element = self
 8105            .render_edit_prediction_line_popover(label, None, window, cx)?
 8106            .into_any();
 8107
 8108        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8109
 8110        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8111
 8112        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8113        let mut origin = start_point
 8114            + line_origin
 8115            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8116        origin.x = origin.x.max(content_origin.x);
 8117
 8118        let max_x = content_origin.x + editor_width - size.width;
 8119
 8120        if origin.x > max_x {
 8121            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8122
 8123            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8124                origin.y += offset;
 8125                IconName::ArrowUp
 8126            } else {
 8127                origin.y -= offset;
 8128                IconName::ArrowDown
 8129            };
 8130
 8131            element = self
 8132                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8133                .into_any();
 8134
 8135            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8136
 8137            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8138        }
 8139
 8140        element.prepaint_at(origin, window, cx);
 8141        Some((element, origin))
 8142    }
 8143
 8144    fn render_edit_prediction_diff_popover(
 8145        self: &Editor,
 8146        text_bounds: &Bounds<Pixels>,
 8147        content_origin: gpui::Point<Pixels>,
 8148        right_margin: Pixels,
 8149        editor_snapshot: &EditorSnapshot,
 8150        visible_row_range: Range<DisplayRow>,
 8151        line_layouts: &[LineWithInvisibles],
 8152        line_height: Pixels,
 8153        scroll_pixel_position: gpui::Point<Pixels>,
 8154        newest_selection_head: Option<DisplayPoint>,
 8155        editor_width: Pixels,
 8156        style: &EditorStyle,
 8157        edits: &Vec<(Range<Anchor>, String)>,
 8158        edit_preview: &Option<language::EditPreview>,
 8159        snapshot: &language::BufferSnapshot,
 8160        window: &mut Window,
 8161        cx: &mut App,
 8162    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8163        let edit_start = edits
 8164            .first()
 8165            .unwrap()
 8166            .0
 8167            .start
 8168            .to_display_point(editor_snapshot);
 8169        let edit_end = edits
 8170            .last()
 8171            .unwrap()
 8172            .0
 8173            .end
 8174            .to_display_point(editor_snapshot);
 8175
 8176        let is_visible = visible_row_range.contains(&edit_start.row())
 8177            || visible_row_range.contains(&edit_end.row());
 8178        if !is_visible {
 8179            return None;
 8180        }
 8181
 8182        let highlighted_edits =
 8183            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8184
 8185        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8186        let line_count = highlighted_edits.text.lines().count();
 8187
 8188        const BORDER_WIDTH: Pixels = px(1.);
 8189
 8190        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8191        let has_keybind = keybind.is_some();
 8192
 8193        let mut element = h_flex()
 8194            .items_start()
 8195            .child(
 8196                h_flex()
 8197                    .bg(cx.theme().colors().editor_background)
 8198                    .border(BORDER_WIDTH)
 8199                    .shadow_sm()
 8200                    .border_color(cx.theme().colors().border)
 8201                    .rounded_l_lg()
 8202                    .when(line_count > 1, |el| el.rounded_br_lg())
 8203                    .pr_1()
 8204                    .child(styled_text),
 8205            )
 8206            .child(
 8207                h_flex()
 8208                    .h(line_height + BORDER_WIDTH * 2.)
 8209                    .px_1p5()
 8210                    .gap_1()
 8211                    // Workaround: For some reason, there's a gap if we don't do this
 8212                    .ml(-BORDER_WIDTH)
 8213                    .shadow(vec![gpui::BoxShadow {
 8214                        color: gpui::black().opacity(0.05),
 8215                        offset: point(px(1.), px(1.)),
 8216                        blur_radius: px(2.),
 8217                        spread_radius: px(0.),
 8218                    }])
 8219                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8220                    .border(BORDER_WIDTH)
 8221                    .border_color(cx.theme().colors().border)
 8222                    .rounded_r_lg()
 8223                    .id("edit_prediction_diff_popover_keybind")
 8224                    .when(!has_keybind, |el| {
 8225                        let status_colors = cx.theme().status();
 8226
 8227                        el.bg(status_colors.error_background)
 8228                            .border_color(status_colors.error.opacity(0.6))
 8229                            .child(Icon::new(IconName::Info).color(Color::Error))
 8230                            .cursor_default()
 8231                            .hoverable_tooltip(move |_window, cx| {
 8232                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8233                            })
 8234                    })
 8235                    .children(keybind),
 8236            )
 8237            .into_any();
 8238
 8239        let longest_row =
 8240            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8241        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8242            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8243        } else {
 8244            layout_line(
 8245                longest_row,
 8246                editor_snapshot,
 8247                style,
 8248                editor_width,
 8249                |_| false,
 8250                window,
 8251                cx,
 8252            )
 8253            .width
 8254        };
 8255
 8256        let viewport_bounds =
 8257            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8258                right: -right_margin,
 8259                ..Default::default()
 8260            });
 8261
 8262        let x_after_longest =
 8263            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8264                - scroll_pixel_position.x;
 8265
 8266        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8267
 8268        // Fully visible if it can be displayed within the window (allow overlapping other
 8269        // panes). However, this is only allowed if the popover starts within text_bounds.
 8270        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8271            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8272
 8273        let mut origin = if can_position_to_the_right {
 8274            point(
 8275                x_after_longest,
 8276                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8277                    - scroll_pixel_position.y,
 8278            )
 8279        } else {
 8280            let cursor_row = newest_selection_head.map(|head| head.row());
 8281            let above_edit = edit_start
 8282                .row()
 8283                .0
 8284                .checked_sub(line_count as u32)
 8285                .map(DisplayRow);
 8286            let below_edit = Some(edit_end.row() + 1);
 8287            let above_cursor =
 8288                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8289            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8290
 8291            // Place the edit popover adjacent to the edit if there is a location
 8292            // available that is onscreen and does not obscure the cursor. Otherwise,
 8293            // place it adjacent to the cursor.
 8294            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8295                .into_iter()
 8296                .flatten()
 8297                .find(|&start_row| {
 8298                    let end_row = start_row + line_count as u32;
 8299                    visible_row_range.contains(&start_row)
 8300                        && visible_row_range.contains(&end_row)
 8301                        && cursor_row.map_or(true, |cursor_row| {
 8302                            !((start_row..end_row).contains(&cursor_row))
 8303                        })
 8304                })?;
 8305
 8306            content_origin
 8307                + point(
 8308                    -scroll_pixel_position.x,
 8309                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8310                )
 8311        };
 8312
 8313        origin.x -= BORDER_WIDTH;
 8314
 8315        window.defer_draw(element, origin, 1);
 8316
 8317        // Do not return an element, since it will already be drawn due to defer_draw.
 8318        None
 8319    }
 8320
 8321    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8322        px(30.)
 8323    }
 8324
 8325    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8326        if self.read_only(cx) {
 8327            cx.theme().players().read_only()
 8328        } else {
 8329            self.style.as_ref().unwrap().local_player
 8330        }
 8331    }
 8332
 8333    fn render_edit_prediction_accept_keybind(
 8334        &self,
 8335        window: &mut Window,
 8336        cx: &App,
 8337    ) -> Option<AnyElement> {
 8338        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8339        let accept_keystroke = accept_binding.keystroke()?;
 8340
 8341        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8342
 8343        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8344            Color::Accent
 8345        } else {
 8346            Color::Muted
 8347        };
 8348
 8349        h_flex()
 8350            .px_0p5()
 8351            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8352            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8353            .text_size(TextSize::XSmall.rems(cx))
 8354            .child(h_flex().children(ui::render_modifiers(
 8355                &accept_keystroke.modifiers,
 8356                PlatformStyle::platform(),
 8357                Some(modifiers_color),
 8358                Some(IconSize::XSmall.rems().into()),
 8359                true,
 8360            )))
 8361            .when(is_platform_style_mac, |parent| {
 8362                parent.child(accept_keystroke.key.clone())
 8363            })
 8364            .when(!is_platform_style_mac, |parent| {
 8365                parent.child(
 8366                    Key::new(
 8367                        util::capitalize(&accept_keystroke.key),
 8368                        Some(Color::Default),
 8369                    )
 8370                    .size(Some(IconSize::XSmall.rems().into())),
 8371                )
 8372            })
 8373            .into_any()
 8374            .into()
 8375    }
 8376
 8377    fn render_edit_prediction_line_popover(
 8378        &self,
 8379        label: impl Into<SharedString>,
 8380        icon: Option<IconName>,
 8381        window: &mut Window,
 8382        cx: &App,
 8383    ) -> Option<Stateful<Div>> {
 8384        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8385
 8386        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8387        let has_keybind = keybind.is_some();
 8388
 8389        let result = h_flex()
 8390            .id("ep-line-popover")
 8391            .py_0p5()
 8392            .pl_1()
 8393            .pr(padding_right)
 8394            .gap_1()
 8395            .rounded_md()
 8396            .border_1()
 8397            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8398            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8399            .shadow_sm()
 8400            .when(!has_keybind, |el| {
 8401                let status_colors = cx.theme().status();
 8402
 8403                el.bg(status_colors.error_background)
 8404                    .border_color(status_colors.error.opacity(0.6))
 8405                    .pl_2()
 8406                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8407                    .cursor_default()
 8408                    .hoverable_tooltip(move |_window, cx| {
 8409                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8410                    })
 8411            })
 8412            .children(keybind)
 8413            .child(
 8414                Label::new(label)
 8415                    .size(LabelSize::Small)
 8416                    .when(!has_keybind, |el| {
 8417                        el.color(cx.theme().status().error.into()).strikethrough()
 8418                    }),
 8419            )
 8420            .when(!has_keybind, |el| {
 8421                el.child(
 8422                    h_flex().ml_1().child(
 8423                        Icon::new(IconName::Info)
 8424                            .size(IconSize::Small)
 8425                            .color(cx.theme().status().error.into()),
 8426                    ),
 8427                )
 8428            })
 8429            .when_some(icon, |element, icon| {
 8430                element.child(
 8431                    div()
 8432                        .mt(px(1.5))
 8433                        .child(Icon::new(icon).size(IconSize::Small)),
 8434                )
 8435            });
 8436
 8437        Some(result)
 8438    }
 8439
 8440    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8441        let accent_color = cx.theme().colors().text_accent;
 8442        let editor_bg_color = cx.theme().colors().editor_background;
 8443        editor_bg_color.blend(accent_color.opacity(0.1))
 8444    }
 8445
 8446    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8447        let accent_color = cx.theme().colors().text_accent;
 8448        let editor_bg_color = cx.theme().colors().editor_background;
 8449        editor_bg_color.blend(accent_color.opacity(0.6))
 8450    }
 8451
 8452    fn render_edit_prediction_cursor_popover(
 8453        &self,
 8454        min_width: Pixels,
 8455        max_width: Pixels,
 8456        cursor_point: Point,
 8457        style: &EditorStyle,
 8458        accept_keystroke: Option<&gpui::Keystroke>,
 8459        _window: &Window,
 8460        cx: &mut Context<Editor>,
 8461    ) -> Option<AnyElement> {
 8462        let provider = self.edit_prediction_provider.as_ref()?;
 8463
 8464        if provider.provider.needs_terms_acceptance(cx) {
 8465            return Some(
 8466                h_flex()
 8467                    .min_w(min_width)
 8468                    .flex_1()
 8469                    .px_2()
 8470                    .py_1()
 8471                    .gap_3()
 8472                    .elevation_2(cx)
 8473                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8474                    .id("accept-terms")
 8475                    .cursor_pointer()
 8476                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8477                    .on_click(cx.listener(|this, _event, window, cx| {
 8478                        cx.stop_propagation();
 8479                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8480                        window.dispatch_action(
 8481                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8482                            cx,
 8483                        );
 8484                    }))
 8485                    .child(
 8486                        h_flex()
 8487                            .flex_1()
 8488                            .gap_2()
 8489                            .child(Icon::new(IconName::ZedPredict))
 8490                            .child(Label::new("Accept Terms of Service"))
 8491                            .child(div().w_full())
 8492                            .child(
 8493                                Icon::new(IconName::ArrowUpRight)
 8494                                    .color(Color::Muted)
 8495                                    .size(IconSize::Small),
 8496                            )
 8497                            .into_any_element(),
 8498                    )
 8499                    .into_any(),
 8500            );
 8501        }
 8502
 8503        let is_refreshing = provider.provider.is_refreshing(cx);
 8504
 8505        fn pending_completion_container() -> Div {
 8506            h_flex()
 8507                .h_full()
 8508                .flex_1()
 8509                .gap_2()
 8510                .child(Icon::new(IconName::ZedPredict))
 8511        }
 8512
 8513        let completion = match &self.active_inline_completion {
 8514            Some(prediction) => {
 8515                if !self.has_visible_completions_menu() {
 8516                    const RADIUS: Pixels = px(6.);
 8517                    const BORDER_WIDTH: Pixels = px(1.);
 8518
 8519                    return Some(
 8520                        h_flex()
 8521                            .elevation_2(cx)
 8522                            .border(BORDER_WIDTH)
 8523                            .border_color(cx.theme().colors().border)
 8524                            .when(accept_keystroke.is_none(), |el| {
 8525                                el.border_color(cx.theme().status().error)
 8526                            })
 8527                            .rounded(RADIUS)
 8528                            .rounded_tl(px(0.))
 8529                            .overflow_hidden()
 8530                            .child(div().px_1p5().child(match &prediction.completion {
 8531                                InlineCompletion::Move { target, snapshot } => {
 8532                                    use text::ToPoint as _;
 8533                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8534                                    {
 8535                                        Icon::new(IconName::ZedPredictDown)
 8536                                    } else {
 8537                                        Icon::new(IconName::ZedPredictUp)
 8538                                    }
 8539                                }
 8540                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8541                            }))
 8542                            .child(
 8543                                h_flex()
 8544                                    .gap_1()
 8545                                    .py_1()
 8546                                    .px_2()
 8547                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8548                                    .border_l_1()
 8549                                    .border_color(cx.theme().colors().border)
 8550                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8551                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8552                                        el.child(
 8553                                            Label::new("Hold")
 8554                                                .size(LabelSize::Small)
 8555                                                .when(accept_keystroke.is_none(), |el| {
 8556                                                    el.strikethrough()
 8557                                                })
 8558                                                .line_height_style(LineHeightStyle::UiLabel),
 8559                                        )
 8560                                    })
 8561                                    .id("edit_prediction_cursor_popover_keybind")
 8562                                    .when(accept_keystroke.is_none(), |el| {
 8563                                        let status_colors = cx.theme().status();
 8564
 8565                                        el.bg(status_colors.error_background)
 8566                                            .border_color(status_colors.error.opacity(0.6))
 8567                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8568                                            .cursor_default()
 8569                                            .hoverable_tooltip(move |_window, cx| {
 8570                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8571                                                    .into()
 8572                                            })
 8573                                    })
 8574                                    .when_some(
 8575                                        accept_keystroke.as_ref(),
 8576                                        |el, accept_keystroke| {
 8577                                            el.child(h_flex().children(ui::render_modifiers(
 8578                                                &accept_keystroke.modifiers,
 8579                                                PlatformStyle::platform(),
 8580                                                Some(Color::Default),
 8581                                                Some(IconSize::XSmall.rems().into()),
 8582                                                false,
 8583                                            )))
 8584                                        },
 8585                                    ),
 8586                            )
 8587                            .into_any(),
 8588                    );
 8589                }
 8590
 8591                self.render_edit_prediction_cursor_popover_preview(
 8592                    prediction,
 8593                    cursor_point,
 8594                    style,
 8595                    cx,
 8596                )?
 8597            }
 8598
 8599            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8600                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8601                    stale_completion,
 8602                    cursor_point,
 8603                    style,
 8604                    cx,
 8605                )?,
 8606
 8607                None => {
 8608                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8609                }
 8610            },
 8611
 8612            None => pending_completion_container().child(Label::new("No Prediction")),
 8613        };
 8614
 8615        let completion = if is_refreshing {
 8616            completion
 8617                .with_animation(
 8618                    "loading-completion",
 8619                    Animation::new(Duration::from_secs(2))
 8620                        .repeat()
 8621                        .with_easing(pulsating_between(0.4, 0.8)),
 8622                    |label, delta| label.opacity(delta),
 8623                )
 8624                .into_any_element()
 8625        } else {
 8626            completion.into_any_element()
 8627        };
 8628
 8629        let has_completion = self.active_inline_completion.is_some();
 8630
 8631        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8632        Some(
 8633            h_flex()
 8634                .min_w(min_width)
 8635                .max_w(max_width)
 8636                .flex_1()
 8637                .elevation_2(cx)
 8638                .border_color(cx.theme().colors().border)
 8639                .child(
 8640                    div()
 8641                        .flex_1()
 8642                        .py_1()
 8643                        .px_2()
 8644                        .overflow_hidden()
 8645                        .child(completion),
 8646                )
 8647                .when_some(accept_keystroke, |el, accept_keystroke| {
 8648                    if !accept_keystroke.modifiers.modified() {
 8649                        return el;
 8650                    }
 8651
 8652                    el.child(
 8653                        h_flex()
 8654                            .h_full()
 8655                            .border_l_1()
 8656                            .rounded_r_lg()
 8657                            .border_color(cx.theme().colors().border)
 8658                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8659                            .gap_1()
 8660                            .py_1()
 8661                            .px_2()
 8662                            .child(
 8663                                h_flex()
 8664                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8665                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8666                                    .child(h_flex().children(ui::render_modifiers(
 8667                                        &accept_keystroke.modifiers,
 8668                                        PlatformStyle::platform(),
 8669                                        Some(if !has_completion {
 8670                                            Color::Muted
 8671                                        } else {
 8672                                            Color::Default
 8673                                        }),
 8674                                        None,
 8675                                        false,
 8676                                    ))),
 8677                            )
 8678                            .child(Label::new("Preview").into_any_element())
 8679                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8680                    )
 8681                })
 8682                .into_any(),
 8683        )
 8684    }
 8685
 8686    fn render_edit_prediction_cursor_popover_preview(
 8687        &self,
 8688        completion: &InlineCompletionState,
 8689        cursor_point: Point,
 8690        style: &EditorStyle,
 8691        cx: &mut Context<Editor>,
 8692    ) -> Option<Div> {
 8693        use text::ToPoint as _;
 8694
 8695        fn render_relative_row_jump(
 8696            prefix: impl Into<String>,
 8697            current_row: u32,
 8698            target_row: u32,
 8699        ) -> Div {
 8700            let (row_diff, arrow) = if target_row < current_row {
 8701                (current_row - target_row, IconName::ArrowUp)
 8702            } else {
 8703                (target_row - current_row, IconName::ArrowDown)
 8704            };
 8705
 8706            h_flex()
 8707                .child(
 8708                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8709                        .color(Color::Muted)
 8710                        .size(LabelSize::Small),
 8711                )
 8712                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8713        }
 8714
 8715        match &completion.completion {
 8716            InlineCompletion::Move {
 8717                target, snapshot, ..
 8718            } => Some(
 8719                h_flex()
 8720                    .px_2()
 8721                    .gap_2()
 8722                    .flex_1()
 8723                    .child(
 8724                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8725                            Icon::new(IconName::ZedPredictDown)
 8726                        } else {
 8727                            Icon::new(IconName::ZedPredictUp)
 8728                        },
 8729                    )
 8730                    .child(Label::new("Jump to Edit")),
 8731            ),
 8732
 8733            InlineCompletion::Edit {
 8734                edits,
 8735                edit_preview,
 8736                snapshot,
 8737                display_mode: _,
 8738            } => {
 8739                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8740
 8741                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8742                    &snapshot,
 8743                    &edits,
 8744                    edit_preview.as_ref()?,
 8745                    true,
 8746                    cx,
 8747                )
 8748                .first_line_preview();
 8749
 8750                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8751                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8752
 8753                let preview = h_flex()
 8754                    .gap_1()
 8755                    .min_w_16()
 8756                    .child(styled_text)
 8757                    .when(has_more_lines, |parent| parent.child(""));
 8758
 8759                let left = if first_edit_row != cursor_point.row {
 8760                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8761                        .into_any_element()
 8762                } else {
 8763                    Icon::new(IconName::ZedPredict).into_any_element()
 8764                };
 8765
 8766                Some(
 8767                    h_flex()
 8768                        .h_full()
 8769                        .flex_1()
 8770                        .gap_2()
 8771                        .pr_1()
 8772                        .overflow_x_hidden()
 8773                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8774                        .child(left)
 8775                        .child(preview),
 8776                )
 8777            }
 8778        }
 8779    }
 8780
 8781    pub fn render_context_menu(
 8782        &self,
 8783        style: &EditorStyle,
 8784        max_height_in_lines: u32,
 8785        window: &mut Window,
 8786        cx: &mut Context<Editor>,
 8787    ) -> Option<AnyElement> {
 8788        let menu = self.context_menu.borrow();
 8789        let menu = menu.as_ref()?;
 8790        if !menu.visible() {
 8791            return None;
 8792        };
 8793        Some(menu.render(style, max_height_in_lines, window, cx))
 8794    }
 8795
 8796    fn render_context_menu_aside(
 8797        &mut self,
 8798        max_size: Size<Pixels>,
 8799        window: &mut Window,
 8800        cx: &mut Context<Editor>,
 8801    ) -> Option<AnyElement> {
 8802        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8803            if menu.visible() {
 8804                menu.render_aside(max_size, window, cx)
 8805            } else {
 8806                None
 8807            }
 8808        })
 8809    }
 8810
 8811    fn hide_context_menu(
 8812        &mut self,
 8813        window: &mut Window,
 8814        cx: &mut Context<Self>,
 8815    ) -> Option<CodeContextMenu> {
 8816        cx.notify();
 8817        self.completion_tasks.clear();
 8818        let context_menu = self.context_menu.borrow_mut().take();
 8819        self.stale_inline_completion_in_menu.take();
 8820        self.update_visible_inline_completion(window, cx);
 8821        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 8822            if let Some(completion_provider) = &self.completion_provider {
 8823                completion_provider.selection_changed(None, window, cx);
 8824            }
 8825        }
 8826        context_menu
 8827    }
 8828
 8829    fn show_snippet_choices(
 8830        &mut self,
 8831        choices: &Vec<String>,
 8832        selection: Range<Anchor>,
 8833        cx: &mut Context<Self>,
 8834    ) {
 8835        if selection.start.buffer_id.is_none() {
 8836            return;
 8837        }
 8838        let buffer_id = selection.start.buffer_id.unwrap();
 8839        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8840        let id = post_inc(&mut self.next_completion_id);
 8841        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8842
 8843        if let Some(buffer) = buffer {
 8844            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8845                CompletionsMenu::new_snippet_choices(
 8846                    id,
 8847                    true,
 8848                    choices,
 8849                    selection,
 8850                    buffer,
 8851                    snippet_sort_order,
 8852                ),
 8853            ));
 8854        }
 8855    }
 8856
 8857    pub fn insert_snippet(
 8858        &mut self,
 8859        insertion_ranges: &[Range<usize>],
 8860        snippet: Snippet,
 8861        window: &mut Window,
 8862        cx: &mut Context<Self>,
 8863    ) -> Result<()> {
 8864        struct Tabstop<T> {
 8865            is_end_tabstop: bool,
 8866            ranges: Vec<Range<T>>,
 8867            choices: Option<Vec<String>>,
 8868        }
 8869
 8870        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8871            let snippet_text: Arc<str> = snippet.text.clone().into();
 8872            let edits = insertion_ranges
 8873                .iter()
 8874                .cloned()
 8875                .map(|range| (range, snippet_text.clone()));
 8876            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8877
 8878            let snapshot = &*buffer.read(cx);
 8879            let snippet = &snippet;
 8880            snippet
 8881                .tabstops
 8882                .iter()
 8883                .map(|tabstop| {
 8884                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8885                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8886                    });
 8887                    let mut tabstop_ranges = tabstop
 8888                        .ranges
 8889                        .iter()
 8890                        .flat_map(|tabstop_range| {
 8891                            let mut delta = 0_isize;
 8892                            insertion_ranges.iter().map(move |insertion_range| {
 8893                                let insertion_start = insertion_range.start as isize + delta;
 8894                                delta +=
 8895                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8896
 8897                                let start = ((insertion_start + tabstop_range.start) as usize)
 8898                                    .min(snapshot.len());
 8899                                let end = ((insertion_start + tabstop_range.end) as usize)
 8900                                    .min(snapshot.len());
 8901                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8902                            })
 8903                        })
 8904                        .collect::<Vec<_>>();
 8905                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8906
 8907                    Tabstop {
 8908                        is_end_tabstop,
 8909                        ranges: tabstop_ranges,
 8910                        choices: tabstop.choices.clone(),
 8911                    }
 8912                })
 8913                .collect::<Vec<_>>()
 8914        });
 8915        if let Some(tabstop) = tabstops.first() {
 8916            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8917                s.select_ranges(tabstop.ranges.iter().cloned());
 8918            });
 8919
 8920            if let Some(choices) = &tabstop.choices {
 8921                if let Some(selection) = tabstop.ranges.first() {
 8922                    self.show_snippet_choices(choices, selection.clone(), cx)
 8923                }
 8924            }
 8925
 8926            // If we're already at the last tabstop and it's at the end of the snippet,
 8927            // we're done, we don't need to keep the state around.
 8928            if !tabstop.is_end_tabstop {
 8929                let choices = tabstops
 8930                    .iter()
 8931                    .map(|tabstop| tabstop.choices.clone())
 8932                    .collect();
 8933
 8934                let ranges = tabstops
 8935                    .into_iter()
 8936                    .map(|tabstop| tabstop.ranges)
 8937                    .collect::<Vec<_>>();
 8938
 8939                self.snippet_stack.push(SnippetState {
 8940                    active_index: 0,
 8941                    ranges,
 8942                    choices,
 8943                });
 8944            }
 8945
 8946            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8947            if self.autoclose_regions.is_empty() {
 8948                let snapshot = self.buffer.read(cx).snapshot(cx);
 8949                for selection in &mut self.selections.all::<Point>(cx) {
 8950                    let selection_head = selection.head();
 8951                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8952                        continue;
 8953                    };
 8954
 8955                    let mut bracket_pair = None;
 8956                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8957                    let prev_chars = snapshot
 8958                        .reversed_chars_at(selection_head)
 8959                        .collect::<String>();
 8960                    for (pair, enabled) in scope.brackets() {
 8961                        if enabled
 8962                            && pair.close
 8963                            && prev_chars.starts_with(pair.start.as_str())
 8964                            && next_chars.starts_with(pair.end.as_str())
 8965                        {
 8966                            bracket_pair = Some(pair.clone());
 8967                            break;
 8968                        }
 8969                    }
 8970                    if let Some(pair) = bracket_pair {
 8971                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8972                        let autoclose_enabled =
 8973                            self.use_autoclose && snapshot_settings.use_autoclose;
 8974                        if autoclose_enabled {
 8975                            let start = snapshot.anchor_after(selection_head);
 8976                            let end = snapshot.anchor_after(selection_head);
 8977                            self.autoclose_regions.push(AutocloseRegion {
 8978                                selection_id: selection.id,
 8979                                range: start..end,
 8980                                pair,
 8981                            });
 8982                        }
 8983                    }
 8984                }
 8985            }
 8986        }
 8987        Ok(())
 8988    }
 8989
 8990    pub fn move_to_next_snippet_tabstop(
 8991        &mut self,
 8992        window: &mut Window,
 8993        cx: &mut Context<Self>,
 8994    ) -> bool {
 8995        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8996    }
 8997
 8998    pub fn move_to_prev_snippet_tabstop(
 8999        &mut self,
 9000        window: &mut Window,
 9001        cx: &mut Context<Self>,
 9002    ) -> bool {
 9003        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9004    }
 9005
 9006    pub fn move_to_snippet_tabstop(
 9007        &mut self,
 9008        bias: Bias,
 9009        window: &mut Window,
 9010        cx: &mut Context<Self>,
 9011    ) -> bool {
 9012        if let Some(mut snippet) = self.snippet_stack.pop() {
 9013            match bias {
 9014                Bias::Left => {
 9015                    if snippet.active_index > 0 {
 9016                        snippet.active_index -= 1;
 9017                    } else {
 9018                        self.snippet_stack.push(snippet);
 9019                        return false;
 9020                    }
 9021                }
 9022                Bias::Right => {
 9023                    if snippet.active_index + 1 < snippet.ranges.len() {
 9024                        snippet.active_index += 1;
 9025                    } else {
 9026                        self.snippet_stack.push(snippet);
 9027                        return false;
 9028                    }
 9029                }
 9030            }
 9031            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9032                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9033                    s.select_anchor_ranges(current_ranges.iter().cloned())
 9034                });
 9035
 9036                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9037                    if let Some(selection) = current_ranges.first() {
 9038                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9039                    }
 9040                }
 9041
 9042                // If snippet state is not at the last tabstop, push it back on the stack
 9043                if snippet.active_index + 1 < snippet.ranges.len() {
 9044                    self.snippet_stack.push(snippet);
 9045                }
 9046                return true;
 9047            }
 9048        }
 9049
 9050        false
 9051    }
 9052
 9053    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9054        self.transact(window, cx, |this, window, cx| {
 9055            this.select_all(&SelectAll, window, cx);
 9056            this.insert("", window, cx);
 9057        });
 9058    }
 9059
 9060    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9061        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9062        self.transact(window, cx, |this, window, cx| {
 9063            this.select_autoclose_pair(window, cx);
 9064            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9065            if !this.linked_edit_ranges.is_empty() {
 9066                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9067                let snapshot = this.buffer.read(cx).snapshot(cx);
 9068
 9069                for selection in selections.iter() {
 9070                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9071                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9072                    if selection_start.buffer_id != selection_end.buffer_id {
 9073                        continue;
 9074                    }
 9075                    if let Some(ranges) =
 9076                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9077                    {
 9078                        for (buffer, entries) in ranges {
 9079                            linked_ranges.entry(buffer).or_default().extend(entries);
 9080                        }
 9081                    }
 9082                }
 9083            }
 9084
 9085            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9086            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9087            for selection in &mut selections {
 9088                if selection.is_empty() {
 9089                    let old_head = selection.head();
 9090                    let mut new_head =
 9091                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9092                            .to_point(&display_map);
 9093                    if let Some((buffer, line_buffer_range)) = display_map
 9094                        .buffer_snapshot
 9095                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9096                    {
 9097                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9098                        let indent_len = match indent_size.kind {
 9099                            IndentKind::Space => {
 9100                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9101                            }
 9102                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9103                        };
 9104                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9105                            let indent_len = indent_len.get();
 9106                            new_head = cmp::min(
 9107                                new_head,
 9108                                MultiBufferPoint::new(
 9109                                    old_head.row,
 9110                                    ((old_head.column - 1) / indent_len) * indent_len,
 9111                                ),
 9112                            );
 9113                        }
 9114                    }
 9115
 9116                    selection.set_head(new_head, SelectionGoal::None);
 9117                }
 9118            }
 9119
 9120            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9121                s.select(selections)
 9122            });
 9123            this.insert("", window, cx);
 9124            let empty_str: Arc<str> = Arc::from("");
 9125            for (buffer, edits) in linked_ranges {
 9126                let snapshot = buffer.read(cx).snapshot();
 9127                use text::ToPoint as TP;
 9128
 9129                let edits = edits
 9130                    .into_iter()
 9131                    .map(|range| {
 9132                        let end_point = TP::to_point(&range.end, &snapshot);
 9133                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9134
 9135                        if end_point == start_point {
 9136                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9137                                .saturating_sub(1);
 9138                            start_point =
 9139                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9140                        };
 9141
 9142                        (start_point..end_point, empty_str.clone())
 9143                    })
 9144                    .sorted_by_key(|(range, _)| range.start)
 9145                    .collect::<Vec<_>>();
 9146                buffer.update(cx, |this, cx| {
 9147                    this.edit(edits, None, cx);
 9148                })
 9149            }
 9150            this.refresh_inline_completion(true, false, window, cx);
 9151            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9152        });
 9153    }
 9154
 9155    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9156        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9157        self.transact(window, cx, |this, window, cx| {
 9158            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9159                s.move_with(|map, selection| {
 9160                    if selection.is_empty() {
 9161                        let cursor = movement::right(map, selection.head());
 9162                        selection.end = cursor;
 9163                        selection.reversed = true;
 9164                        selection.goal = SelectionGoal::None;
 9165                    }
 9166                })
 9167            });
 9168            this.insert("", window, cx);
 9169            this.refresh_inline_completion(true, false, window, cx);
 9170        });
 9171    }
 9172
 9173    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9174        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9175        if self.move_to_prev_snippet_tabstop(window, cx) {
 9176            return;
 9177        }
 9178        self.outdent(&Outdent, window, cx);
 9179    }
 9180
 9181    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9182        if self.move_to_next_snippet_tabstop(window, cx) {
 9183            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9184            return;
 9185        }
 9186        if self.read_only(cx) {
 9187            return;
 9188        }
 9189        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9190        let mut selections = self.selections.all_adjusted(cx);
 9191        let buffer = self.buffer.read(cx);
 9192        let snapshot = buffer.snapshot(cx);
 9193        let rows_iter = selections.iter().map(|s| s.head().row);
 9194        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9195
 9196        let has_some_cursor_in_whitespace = selections
 9197            .iter()
 9198            .filter(|selection| selection.is_empty())
 9199            .any(|selection| {
 9200                let cursor = selection.head();
 9201                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9202                cursor.column < current_indent.len
 9203            });
 9204
 9205        let mut edits = Vec::new();
 9206        let mut prev_edited_row = 0;
 9207        let mut row_delta = 0;
 9208        for selection in &mut selections {
 9209            if selection.start.row != prev_edited_row {
 9210                row_delta = 0;
 9211            }
 9212            prev_edited_row = selection.end.row;
 9213
 9214            // If the selection is non-empty, then increase the indentation of the selected lines.
 9215            if !selection.is_empty() {
 9216                row_delta =
 9217                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9218                continue;
 9219            }
 9220
 9221            let cursor = selection.head();
 9222            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9223            if let Some(suggested_indent) =
 9224                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9225            {
 9226                // Don't do anything if already at suggested indent
 9227                // and there is any other cursor which is not
 9228                if has_some_cursor_in_whitespace
 9229                    && cursor.column == current_indent.len
 9230                    && current_indent.len == suggested_indent.len
 9231                {
 9232                    continue;
 9233                }
 9234
 9235                // Adjust line and move cursor to suggested indent
 9236                // if cursor is not at suggested indent
 9237                if cursor.column < suggested_indent.len
 9238                    && cursor.column <= current_indent.len
 9239                    && current_indent.len <= suggested_indent.len
 9240                {
 9241                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9242                    selection.end = selection.start;
 9243                    if row_delta == 0 {
 9244                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9245                            cursor.row,
 9246                            current_indent,
 9247                            suggested_indent,
 9248                        ));
 9249                        row_delta = suggested_indent.len - current_indent.len;
 9250                    }
 9251                    continue;
 9252                }
 9253
 9254                // If current indent is more than suggested indent
 9255                // only move cursor to current indent and skip indent
 9256                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9257                    selection.start = Point::new(cursor.row, current_indent.len);
 9258                    selection.end = selection.start;
 9259                    continue;
 9260                }
 9261            }
 9262
 9263            // Otherwise, insert a hard or soft tab.
 9264            let settings = buffer.language_settings_at(cursor, cx);
 9265            let tab_size = if settings.hard_tabs {
 9266                IndentSize::tab()
 9267            } else {
 9268                let tab_size = settings.tab_size.get();
 9269                let indent_remainder = snapshot
 9270                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9271                    .flat_map(str::chars)
 9272                    .fold(row_delta % tab_size, |counter: u32, c| {
 9273                        if c == '\t' {
 9274                            0
 9275                        } else {
 9276                            (counter + 1) % tab_size
 9277                        }
 9278                    });
 9279
 9280                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9281                IndentSize::spaces(chars_to_next_tab_stop)
 9282            };
 9283            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9284            selection.end = selection.start;
 9285            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9286            row_delta += tab_size.len;
 9287        }
 9288
 9289        self.transact(window, cx, |this, window, cx| {
 9290            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9291            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9292                s.select(selections)
 9293            });
 9294            this.refresh_inline_completion(true, false, window, cx);
 9295        });
 9296    }
 9297
 9298    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9299        if self.read_only(cx) {
 9300            return;
 9301        }
 9302        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9303        let mut selections = self.selections.all::<Point>(cx);
 9304        let mut prev_edited_row = 0;
 9305        let mut row_delta = 0;
 9306        let mut edits = Vec::new();
 9307        let buffer = self.buffer.read(cx);
 9308        let snapshot = buffer.snapshot(cx);
 9309        for selection in &mut selections {
 9310            if selection.start.row != prev_edited_row {
 9311                row_delta = 0;
 9312            }
 9313            prev_edited_row = selection.end.row;
 9314
 9315            row_delta =
 9316                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9317        }
 9318
 9319        self.transact(window, cx, |this, window, cx| {
 9320            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9321            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9322                s.select(selections)
 9323            });
 9324        });
 9325    }
 9326
 9327    fn indent_selection(
 9328        buffer: &MultiBuffer,
 9329        snapshot: &MultiBufferSnapshot,
 9330        selection: &mut Selection<Point>,
 9331        edits: &mut Vec<(Range<Point>, String)>,
 9332        delta_for_start_row: u32,
 9333        cx: &App,
 9334    ) -> u32 {
 9335        let settings = buffer.language_settings_at(selection.start, cx);
 9336        let tab_size = settings.tab_size.get();
 9337        let indent_kind = if settings.hard_tabs {
 9338            IndentKind::Tab
 9339        } else {
 9340            IndentKind::Space
 9341        };
 9342        let mut start_row = selection.start.row;
 9343        let mut end_row = selection.end.row + 1;
 9344
 9345        // If a selection ends at the beginning of a line, don't indent
 9346        // that last line.
 9347        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9348            end_row -= 1;
 9349        }
 9350
 9351        // Avoid re-indenting a row that has already been indented by a
 9352        // previous selection, but still update this selection's column
 9353        // to reflect that indentation.
 9354        if delta_for_start_row > 0 {
 9355            start_row += 1;
 9356            selection.start.column += delta_for_start_row;
 9357            if selection.end.row == selection.start.row {
 9358                selection.end.column += delta_for_start_row;
 9359            }
 9360        }
 9361
 9362        let mut delta_for_end_row = 0;
 9363        let has_multiple_rows = start_row + 1 != end_row;
 9364        for row in start_row..end_row {
 9365            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9366            let indent_delta = match (current_indent.kind, indent_kind) {
 9367                (IndentKind::Space, IndentKind::Space) => {
 9368                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9369                    IndentSize::spaces(columns_to_next_tab_stop)
 9370                }
 9371                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9372                (_, IndentKind::Tab) => IndentSize::tab(),
 9373            };
 9374
 9375            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9376                0
 9377            } else {
 9378                selection.start.column
 9379            };
 9380            let row_start = Point::new(row, start);
 9381            edits.push((
 9382                row_start..row_start,
 9383                indent_delta.chars().collect::<String>(),
 9384            ));
 9385
 9386            // Update this selection's endpoints to reflect the indentation.
 9387            if row == selection.start.row {
 9388                selection.start.column += indent_delta.len;
 9389            }
 9390            if row == selection.end.row {
 9391                selection.end.column += indent_delta.len;
 9392                delta_for_end_row = indent_delta.len;
 9393            }
 9394        }
 9395
 9396        if selection.start.row == selection.end.row {
 9397            delta_for_start_row + delta_for_end_row
 9398        } else {
 9399            delta_for_end_row
 9400        }
 9401    }
 9402
 9403    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9404        if self.read_only(cx) {
 9405            return;
 9406        }
 9407        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9408        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9409        let selections = self.selections.all::<Point>(cx);
 9410        let mut deletion_ranges = Vec::new();
 9411        let mut last_outdent = None;
 9412        {
 9413            let buffer = self.buffer.read(cx);
 9414            let snapshot = buffer.snapshot(cx);
 9415            for selection in &selections {
 9416                let settings = buffer.language_settings_at(selection.start, cx);
 9417                let tab_size = settings.tab_size.get();
 9418                let mut rows = selection.spanned_rows(false, &display_map);
 9419
 9420                // Avoid re-outdenting a row that has already been outdented by a
 9421                // previous selection.
 9422                if let Some(last_row) = last_outdent {
 9423                    if last_row == rows.start {
 9424                        rows.start = rows.start.next_row();
 9425                    }
 9426                }
 9427                let has_multiple_rows = rows.len() > 1;
 9428                for row in rows.iter_rows() {
 9429                    let indent_size = snapshot.indent_size_for_line(row);
 9430                    if indent_size.len > 0 {
 9431                        let deletion_len = match indent_size.kind {
 9432                            IndentKind::Space => {
 9433                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9434                                if columns_to_prev_tab_stop == 0 {
 9435                                    tab_size
 9436                                } else {
 9437                                    columns_to_prev_tab_stop
 9438                                }
 9439                            }
 9440                            IndentKind::Tab => 1,
 9441                        };
 9442                        let start = if has_multiple_rows
 9443                            || deletion_len > selection.start.column
 9444                            || indent_size.len < selection.start.column
 9445                        {
 9446                            0
 9447                        } else {
 9448                            selection.start.column - deletion_len
 9449                        };
 9450                        deletion_ranges.push(
 9451                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9452                        );
 9453                        last_outdent = Some(row);
 9454                    }
 9455                }
 9456            }
 9457        }
 9458
 9459        self.transact(window, cx, |this, window, cx| {
 9460            this.buffer.update(cx, |buffer, cx| {
 9461                let empty_str: Arc<str> = Arc::default();
 9462                buffer.edit(
 9463                    deletion_ranges
 9464                        .into_iter()
 9465                        .map(|range| (range, empty_str.clone())),
 9466                    None,
 9467                    cx,
 9468                );
 9469            });
 9470            let selections = this.selections.all::<usize>(cx);
 9471            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9472                s.select(selections)
 9473            });
 9474        });
 9475    }
 9476
 9477    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9478        if self.read_only(cx) {
 9479            return;
 9480        }
 9481        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9482        let selections = self
 9483            .selections
 9484            .all::<usize>(cx)
 9485            .into_iter()
 9486            .map(|s| s.range());
 9487
 9488        self.transact(window, cx, |this, window, cx| {
 9489            this.buffer.update(cx, |buffer, cx| {
 9490                buffer.autoindent_ranges(selections, cx);
 9491            });
 9492            let selections = this.selections.all::<usize>(cx);
 9493            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9494                s.select(selections)
 9495            });
 9496        });
 9497    }
 9498
 9499    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9500        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9501        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9502        let selections = self.selections.all::<Point>(cx);
 9503
 9504        let mut new_cursors = Vec::new();
 9505        let mut edit_ranges = Vec::new();
 9506        let mut selections = selections.iter().peekable();
 9507        while let Some(selection) = selections.next() {
 9508            let mut rows = selection.spanned_rows(false, &display_map);
 9509            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9510
 9511            // Accumulate contiguous regions of rows that we want to delete.
 9512            while let Some(next_selection) = selections.peek() {
 9513                let next_rows = next_selection.spanned_rows(false, &display_map);
 9514                if next_rows.start <= rows.end {
 9515                    rows.end = next_rows.end;
 9516                    selections.next().unwrap();
 9517                } else {
 9518                    break;
 9519                }
 9520            }
 9521
 9522            let buffer = &display_map.buffer_snapshot;
 9523            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9524            let edit_end;
 9525            let cursor_buffer_row;
 9526            if buffer.max_point().row >= rows.end.0 {
 9527                // If there's a line after the range, delete the \n from the end of the row range
 9528                // and position the cursor on the next line.
 9529                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9530                cursor_buffer_row = rows.end;
 9531            } else {
 9532                // If there isn't a line after the range, delete the \n from the line before the
 9533                // start of the row range and position the cursor there.
 9534                edit_start = edit_start.saturating_sub(1);
 9535                edit_end = buffer.len();
 9536                cursor_buffer_row = rows.start.previous_row();
 9537            }
 9538
 9539            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9540            *cursor.column_mut() =
 9541                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9542
 9543            new_cursors.push((
 9544                selection.id,
 9545                buffer.anchor_after(cursor.to_point(&display_map)),
 9546            ));
 9547            edit_ranges.push(edit_start..edit_end);
 9548        }
 9549
 9550        self.transact(window, cx, |this, window, cx| {
 9551            let buffer = this.buffer.update(cx, |buffer, cx| {
 9552                let empty_str: Arc<str> = Arc::default();
 9553                buffer.edit(
 9554                    edit_ranges
 9555                        .into_iter()
 9556                        .map(|range| (range, empty_str.clone())),
 9557                    None,
 9558                    cx,
 9559                );
 9560                buffer.snapshot(cx)
 9561            });
 9562            let new_selections = new_cursors
 9563                .into_iter()
 9564                .map(|(id, cursor)| {
 9565                    let cursor = cursor.to_point(&buffer);
 9566                    Selection {
 9567                        id,
 9568                        start: cursor,
 9569                        end: cursor,
 9570                        reversed: false,
 9571                        goal: SelectionGoal::None,
 9572                    }
 9573                })
 9574                .collect();
 9575
 9576            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9577                s.select(new_selections);
 9578            });
 9579        });
 9580    }
 9581
 9582    pub fn join_lines_impl(
 9583        &mut self,
 9584        insert_whitespace: bool,
 9585        window: &mut Window,
 9586        cx: &mut Context<Self>,
 9587    ) {
 9588        if self.read_only(cx) {
 9589            return;
 9590        }
 9591        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9592        for selection in self.selections.all::<Point>(cx) {
 9593            let start = MultiBufferRow(selection.start.row);
 9594            // Treat single line selections as if they include the next line. Otherwise this action
 9595            // would do nothing for single line selections individual cursors.
 9596            let end = if selection.start.row == selection.end.row {
 9597                MultiBufferRow(selection.start.row + 1)
 9598            } else {
 9599                MultiBufferRow(selection.end.row)
 9600            };
 9601
 9602            if let Some(last_row_range) = row_ranges.last_mut() {
 9603                if start <= last_row_range.end {
 9604                    last_row_range.end = end;
 9605                    continue;
 9606                }
 9607            }
 9608            row_ranges.push(start..end);
 9609        }
 9610
 9611        let snapshot = self.buffer.read(cx).snapshot(cx);
 9612        let mut cursor_positions = Vec::new();
 9613        for row_range in &row_ranges {
 9614            let anchor = snapshot.anchor_before(Point::new(
 9615                row_range.end.previous_row().0,
 9616                snapshot.line_len(row_range.end.previous_row()),
 9617            ));
 9618            cursor_positions.push(anchor..anchor);
 9619        }
 9620
 9621        self.transact(window, cx, |this, window, cx| {
 9622            for row_range in row_ranges.into_iter().rev() {
 9623                for row in row_range.iter_rows().rev() {
 9624                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9625                    let next_line_row = row.next_row();
 9626                    let indent = snapshot.indent_size_for_line(next_line_row);
 9627                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9628
 9629                    let replace =
 9630                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9631                            " "
 9632                        } else {
 9633                            ""
 9634                        };
 9635
 9636                    this.buffer.update(cx, |buffer, cx| {
 9637                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9638                    });
 9639                }
 9640            }
 9641
 9642            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9643                s.select_anchor_ranges(cursor_positions)
 9644            });
 9645        });
 9646    }
 9647
 9648    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9649        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9650        self.join_lines_impl(true, window, cx);
 9651    }
 9652
 9653    pub fn sort_lines_case_sensitive(
 9654        &mut self,
 9655        _: &SortLinesCaseSensitive,
 9656        window: &mut Window,
 9657        cx: &mut Context<Self>,
 9658    ) {
 9659        self.manipulate_lines(window, cx, |lines| lines.sort())
 9660    }
 9661
 9662    pub fn sort_lines_case_insensitive(
 9663        &mut self,
 9664        _: &SortLinesCaseInsensitive,
 9665        window: &mut Window,
 9666        cx: &mut Context<Self>,
 9667    ) {
 9668        self.manipulate_lines(window, cx, |lines| {
 9669            lines.sort_by_key(|line| line.to_lowercase())
 9670        })
 9671    }
 9672
 9673    pub fn unique_lines_case_insensitive(
 9674        &mut self,
 9675        _: &UniqueLinesCaseInsensitive,
 9676        window: &mut Window,
 9677        cx: &mut Context<Self>,
 9678    ) {
 9679        self.manipulate_lines(window, cx, |lines| {
 9680            let mut seen = HashSet::default();
 9681            lines.retain(|line| seen.insert(line.to_lowercase()));
 9682        })
 9683    }
 9684
 9685    pub fn unique_lines_case_sensitive(
 9686        &mut self,
 9687        _: &UniqueLinesCaseSensitive,
 9688        window: &mut Window,
 9689        cx: &mut Context<Self>,
 9690    ) {
 9691        self.manipulate_lines(window, cx, |lines| {
 9692            let mut seen = HashSet::default();
 9693            lines.retain(|line| seen.insert(*line));
 9694        })
 9695    }
 9696
 9697    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9698        let Some(project) = self.project.clone() else {
 9699            return;
 9700        };
 9701        self.reload(project, window, cx)
 9702            .detach_and_notify_err(window, cx);
 9703    }
 9704
 9705    pub fn restore_file(
 9706        &mut self,
 9707        _: &::git::RestoreFile,
 9708        window: &mut Window,
 9709        cx: &mut Context<Self>,
 9710    ) {
 9711        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9712        let mut buffer_ids = HashSet::default();
 9713        let snapshot = self.buffer().read(cx).snapshot(cx);
 9714        for selection in self.selections.all::<usize>(cx) {
 9715            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9716        }
 9717
 9718        let buffer = self.buffer().read(cx);
 9719        let ranges = buffer_ids
 9720            .into_iter()
 9721            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9722            .collect::<Vec<_>>();
 9723
 9724        self.restore_hunks_in_ranges(ranges, window, cx);
 9725    }
 9726
 9727    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9728        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9729        let selections = self
 9730            .selections
 9731            .all(cx)
 9732            .into_iter()
 9733            .map(|s| s.range())
 9734            .collect();
 9735        self.restore_hunks_in_ranges(selections, window, cx);
 9736    }
 9737
 9738    pub fn restore_hunks_in_ranges(
 9739        &mut self,
 9740        ranges: Vec<Range<Point>>,
 9741        window: &mut Window,
 9742        cx: &mut Context<Editor>,
 9743    ) {
 9744        let mut revert_changes = HashMap::default();
 9745        let chunk_by = self
 9746            .snapshot(window, cx)
 9747            .hunks_for_ranges(ranges)
 9748            .into_iter()
 9749            .chunk_by(|hunk| hunk.buffer_id);
 9750        for (buffer_id, hunks) in &chunk_by {
 9751            let hunks = hunks.collect::<Vec<_>>();
 9752            for hunk in &hunks {
 9753                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9754            }
 9755            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9756        }
 9757        drop(chunk_by);
 9758        if !revert_changes.is_empty() {
 9759            self.transact(window, cx, |editor, window, cx| {
 9760                editor.restore(revert_changes, window, cx);
 9761            });
 9762        }
 9763    }
 9764
 9765    pub fn open_active_item_in_terminal(
 9766        &mut self,
 9767        _: &OpenInTerminal,
 9768        window: &mut Window,
 9769        cx: &mut Context<Self>,
 9770    ) {
 9771        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9772            let project_path = buffer.read(cx).project_path(cx)?;
 9773            let project = self.project.as_ref()?.read(cx);
 9774            let entry = project.entry_for_path(&project_path, cx)?;
 9775            let parent = match &entry.canonical_path {
 9776                Some(canonical_path) => canonical_path.to_path_buf(),
 9777                None => project.absolute_path(&project_path, cx)?,
 9778            }
 9779            .parent()?
 9780            .to_path_buf();
 9781            Some(parent)
 9782        }) {
 9783            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9784        }
 9785    }
 9786
 9787    fn set_breakpoint_context_menu(
 9788        &mut self,
 9789        display_row: DisplayRow,
 9790        position: Option<Anchor>,
 9791        clicked_point: gpui::Point<Pixels>,
 9792        window: &mut Window,
 9793        cx: &mut Context<Self>,
 9794    ) {
 9795        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9796            return;
 9797        }
 9798        let source = self
 9799            .buffer
 9800            .read(cx)
 9801            .snapshot(cx)
 9802            .anchor_before(Point::new(display_row.0, 0u32));
 9803
 9804        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9805
 9806        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9807            self,
 9808            source,
 9809            clicked_point,
 9810            context_menu,
 9811            window,
 9812            cx,
 9813        );
 9814    }
 9815
 9816    fn add_edit_breakpoint_block(
 9817        &mut self,
 9818        anchor: Anchor,
 9819        breakpoint: &Breakpoint,
 9820        edit_action: BreakpointPromptEditAction,
 9821        window: &mut Window,
 9822        cx: &mut Context<Self>,
 9823    ) {
 9824        let weak_editor = cx.weak_entity();
 9825        let bp_prompt = cx.new(|cx| {
 9826            BreakpointPromptEditor::new(
 9827                weak_editor,
 9828                anchor,
 9829                breakpoint.clone(),
 9830                edit_action,
 9831                window,
 9832                cx,
 9833            )
 9834        });
 9835
 9836        let height = bp_prompt.update(cx, |this, cx| {
 9837            this.prompt
 9838                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9839        });
 9840        let cloned_prompt = bp_prompt.clone();
 9841        let blocks = vec![BlockProperties {
 9842            style: BlockStyle::Sticky,
 9843            placement: BlockPlacement::Above(anchor),
 9844            height: Some(height),
 9845            render: Arc::new(move |cx| {
 9846                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9847                cloned_prompt.clone().into_any_element()
 9848            }),
 9849            priority: 0,
 9850            render_in_minimap: true,
 9851        }];
 9852
 9853        let focus_handle = bp_prompt.focus_handle(cx);
 9854        window.focus(&focus_handle);
 9855
 9856        let block_ids = self.insert_blocks(blocks, None, cx);
 9857        bp_prompt.update(cx, |prompt, _| {
 9858            prompt.add_block_ids(block_ids);
 9859        });
 9860    }
 9861
 9862    pub(crate) fn breakpoint_at_row(
 9863        &self,
 9864        row: u32,
 9865        window: &mut Window,
 9866        cx: &mut Context<Self>,
 9867    ) -> Option<(Anchor, Breakpoint)> {
 9868        let snapshot = self.snapshot(window, cx);
 9869        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9870
 9871        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9872    }
 9873
 9874    pub(crate) fn breakpoint_at_anchor(
 9875        &self,
 9876        breakpoint_position: Anchor,
 9877        snapshot: &EditorSnapshot,
 9878        cx: &mut Context<Self>,
 9879    ) -> Option<(Anchor, Breakpoint)> {
 9880        let project = self.project.clone()?;
 9881
 9882        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9883            snapshot
 9884                .buffer_snapshot
 9885                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9886        })?;
 9887
 9888        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9889        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
 9890        let buffer_snapshot = buffer.read(cx).snapshot();
 9891
 9892        let row = buffer_snapshot
 9893            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9894            .row;
 9895
 9896        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9897        let anchor_end = snapshot
 9898            .buffer_snapshot
 9899            .anchor_after(Point::new(row, line_len));
 9900
 9901        let bp = self
 9902            .breakpoint_store
 9903            .as_ref()?
 9904            .read_with(cx, |breakpoint_store, cx| {
 9905                breakpoint_store
 9906                    .breakpoints(
 9907                        &buffer,
 9908                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9909                        &buffer_snapshot,
 9910                        cx,
 9911                    )
 9912                    .next()
 9913                    .and_then(|(bp, _)| {
 9914                        let breakpoint_row = buffer_snapshot
 9915                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
 9916                            .row;
 9917
 9918                        if breakpoint_row == row {
 9919                            snapshot
 9920                                .buffer_snapshot
 9921                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
 9922                                .map(|position| (position, bp.bp.clone()))
 9923                        } else {
 9924                            None
 9925                        }
 9926                    })
 9927            });
 9928        bp
 9929    }
 9930
 9931    pub fn edit_log_breakpoint(
 9932        &mut self,
 9933        _: &EditLogBreakpoint,
 9934        window: &mut Window,
 9935        cx: &mut Context<Self>,
 9936    ) {
 9937        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9938            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9939                message: None,
 9940                state: BreakpointState::Enabled,
 9941                condition: None,
 9942                hit_condition: None,
 9943            });
 9944
 9945            self.add_edit_breakpoint_block(
 9946                anchor,
 9947                &breakpoint,
 9948                BreakpointPromptEditAction::Log,
 9949                window,
 9950                cx,
 9951            );
 9952        }
 9953    }
 9954
 9955    fn breakpoints_at_cursors(
 9956        &self,
 9957        window: &mut Window,
 9958        cx: &mut Context<Self>,
 9959    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 9960        let snapshot = self.snapshot(window, cx);
 9961        let cursors = self
 9962            .selections
 9963            .disjoint_anchors()
 9964            .into_iter()
 9965            .map(|selection| {
 9966                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9967
 9968                let breakpoint_position = self
 9969                    .breakpoint_at_row(cursor_position.row, window, cx)
 9970                    .map(|bp| bp.0)
 9971                    .unwrap_or_else(|| {
 9972                        snapshot
 9973                            .display_snapshot
 9974                            .buffer_snapshot
 9975                            .anchor_after(Point::new(cursor_position.row, 0))
 9976                    });
 9977
 9978                let breakpoint = self
 9979                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9980                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9981
 9982                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9983            })
 9984            // 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.
 9985            .collect::<HashMap<Anchor, _>>();
 9986
 9987        cursors.into_iter().collect()
 9988    }
 9989
 9990    pub fn enable_breakpoint(
 9991        &mut self,
 9992        _: &crate::actions::EnableBreakpoint,
 9993        window: &mut Window,
 9994        cx: &mut Context<Self>,
 9995    ) {
 9996        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9997            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9998                continue;
 9999            };
10000            self.edit_breakpoint_at_anchor(
10001                anchor,
10002                breakpoint,
10003                BreakpointEditAction::InvertState,
10004                cx,
10005            );
10006        }
10007    }
10008
10009    pub fn disable_breakpoint(
10010        &mut self,
10011        _: &crate::actions::DisableBreakpoint,
10012        window: &mut Window,
10013        cx: &mut Context<Self>,
10014    ) {
10015        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10016            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10017                continue;
10018            };
10019            self.edit_breakpoint_at_anchor(
10020                anchor,
10021                breakpoint,
10022                BreakpointEditAction::InvertState,
10023                cx,
10024            );
10025        }
10026    }
10027
10028    pub fn toggle_breakpoint(
10029        &mut self,
10030        _: &crate::actions::ToggleBreakpoint,
10031        window: &mut Window,
10032        cx: &mut Context<Self>,
10033    ) {
10034        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10035            if let Some(breakpoint) = breakpoint {
10036                self.edit_breakpoint_at_anchor(
10037                    anchor,
10038                    breakpoint,
10039                    BreakpointEditAction::Toggle,
10040                    cx,
10041                );
10042            } else {
10043                self.edit_breakpoint_at_anchor(
10044                    anchor,
10045                    Breakpoint::new_standard(),
10046                    BreakpointEditAction::Toggle,
10047                    cx,
10048                );
10049            }
10050        }
10051    }
10052
10053    pub fn edit_breakpoint_at_anchor(
10054        &mut self,
10055        breakpoint_position: Anchor,
10056        breakpoint: Breakpoint,
10057        edit_action: BreakpointEditAction,
10058        cx: &mut Context<Self>,
10059    ) {
10060        let Some(breakpoint_store) = &self.breakpoint_store else {
10061            return;
10062        };
10063
10064        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10065            if breakpoint_position == Anchor::min() {
10066                self.buffer()
10067                    .read(cx)
10068                    .excerpt_buffer_ids()
10069                    .into_iter()
10070                    .next()
10071            } else {
10072                None
10073            }
10074        }) else {
10075            return;
10076        };
10077
10078        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10079            return;
10080        };
10081
10082        breakpoint_store.update(cx, |breakpoint_store, cx| {
10083            breakpoint_store.toggle_breakpoint(
10084                buffer,
10085                BreakpointWithPosition {
10086                    position: breakpoint_position.text_anchor,
10087                    bp: breakpoint,
10088                },
10089                edit_action,
10090                cx,
10091            );
10092        });
10093
10094        cx.notify();
10095    }
10096
10097    #[cfg(any(test, feature = "test-support"))]
10098    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10099        self.breakpoint_store.clone()
10100    }
10101
10102    pub fn prepare_restore_change(
10103        &self,
10104        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10105        hunk: &MultiBufferDiffHunk,
10106        cx: &mut App,
10107    ) -> Option<()> {
10108        if hunk.is_created_file() {
10109            return None;
10110        }
10111        let buffer = self.buffer.read(cx);
10112        let diff = buffer.diff_for(hunk.buffer_id)?;
10113        let buffer = buffer.buffer(hunk.buffer_id)?;
10114        let buffer = buffer.read(cx);
10115        let original_text = diff
10116            .read(cx)
10117            .base_text()
10118            .as_rope()
10119            .slice(hunk.diff_base_byte_range.clone());
10120        let buffer_snapshot = buffer.snapshot();
10121        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10122        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10123            probe
10124                .0
10125                .start
10126                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10127                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10128        }) {
10129            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10130            Some(())
10131        } else {
10132            None
10133        }
10134    }
10135
10136    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10137        self.manipulate_lines(window, cx, |lines| lines.reverse())
10138    }
10139
10140    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10141        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10142    }
10143
10144    fn manipulate_lines<Fn>(
10145        &mut self,
10146        window: &mut Window,
10147        cx: &mut Context<Self>,
10148        mut callback: Fn,
10149    ) where
10150        Fn: FnMut(&mut Vec<&str>),
10151    {
10152        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10153
10154        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10155        let buffer = self.buffer.read(cx).snapshot(cx);
10156
10157        let mut edits = Vec::new();
10158
10159        let selections = self.selections.all::<Point>(cx);
10160        let mut selections = selections.iter().peekable();
10161        let mut contiguous_row_selections = Vec::new();
10162        let mut new_selections = Vec::new();
10163        let mut added_lines = 0;
10164        let mut removed_lines = 0;
10165
10166        while let Some(selection) = selections.next() {
10167            let (start_row, end_row) = consume_contiguous_rows(
10168                &mut contiguous_row_selections,
10169                selection,
10170                &display_map,
10171                &mut selections,
10172            );
10173
10174            let start_point = Point::new(start_row.0, 0);
10175            let end_point = Point::new(
10176                end_row.previous_row().0,
10177                buffer.line_len(end_row.previous_row()),
10178            );
10179            let text = buffer
10180                .text_for_range(start_point..end_point)
10181                .collect::<String>();
10182
10183            let mut lines = text.split('\n').collect_vec();
10184
10185            let lines_before = lines.len();
10186            callback(&mut lines);
10187            let lines_after = lines.len();
10188
10189            edits.push((start_point..end_point, lines.join("\n")));
10190
10191            // Selections must change based on added and removed line count
10192            let start_row =
10193                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10194            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10195            new_selections.push(Selection {
10196                id: selection.id,
10197                start: start_row,
10198                end: end_row,
10199                goal: SelectionGoal::None,
10200                reversed: selection.reversed,
10201            });
10202
10203            if lines_after > lines_before {
10204                added_lines += lines_after - lines_before;
10205            } else if lines_before > lines_after {
10206                removed_lines += lines_before - lines_after;
10207            }
10208        }
10209
10210        self.transact(window, cx, |this, window, cx| {
10211            let buffer = this.buffer.update(cx, |buffer, cx| {
10212                buffer.edit(edits, None, cx);
10213                buffer.snapshot(cx)
10214            });
10215
10216            // Recalculate offsets on newly edited buffer
10217            let new_selections = new_selections
10218                .iter()
10219                .map(|s| {
10220                    let start_point = Point::new(s.start.0, 0);
10221                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10222                    Selection {
10223                        id: s.id,
10224                        start: buffer.point_to_offset(start_point),
10225                        end: buffer.point_to_offset(end_point),
10226                        goal: s.goal,
10227                        reversed: s.reversed,
10228                    }
10229                })
10230                .collect();
10231
10232            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10233                s.select(new_selections);
10234            });
10235
10236            this.request_autoscroll(Autoscroll::fit(), cx);
10237        });
10238    }
10239
10240    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10241        self.manipulate_text(window, cx, |text| {
10242            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10243            if has_upper_case_characters {
10244                text.to_lowercase()
10245            } else {
10246                text.to_uppercase()
10247            }
10248        })
10249    }
10250
10251    pub fn convert_to_upper_case(
10252        &mut self,
10253        _: &ConvertToUpperCase,
10254        window: &mut Window,
10255        cx: &mut Context<Self>,
10256    ) {
10257        self.manipulate_text(window, cx, |text| text.to_uppercase())
10258    }
10259
10260    pub fn convert_to_lower_case(
10261        &mut self,
10262        _: &ConvertToLowerCase,
10263        window: &mut Window,
10264        cx: &mut Context<Self>,
10265    ) {
10266        self.manipulate_text(window, cx, |text| text.to_lowercase())
10267    }
10268
10269    pub fn convert_to_title_case(
10270        &mut self,
10271        _: &ConvertToTitleCase,
10272        window: &mut Window,
10273        cx: &mut Context<Self>,
10274    ) {
10275        self.manipulate_text(window, cx, |text| {
10276            text.split('\n')
10277                .map(|line| line.to_case(Case::Title))
10278                .join("\n")
10279        })
10280    }
10281
10282    pub fn convert_to_snake_case(
10283        &mut self,
10284        _: &ConvertToSnakeCase,
10285        window: &mut Window,
10286        cx: &mut Context<Self>,
10287    ) {
10288        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10289    }
10290
10291    pub fn convert_to_kebab_case(
10292        &mut self,
10293        _: &ConvertToKebabCase,
10294        window: &mut Window,
10295        cx: &mut Context<Self>,
10296    ) {
10297        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10298    }
10299
10300    pub fn convert_to_upper_camel_case(
10301        &mut self,
10302        _: &ConvertToUpperCamelCase,
10303        window: &mut Window,
10304        cx: &mut Context<Self>,
10305    ) {
10306        self.manipulate_text(window, cx, |text| {
10307            text.split('\n')
10308                .map(|line| line.to_case(Case::UpperCamel))
10309                .join("\n")
10310        })
10311    }
10312
10313    pub fn convert_to_lower_camel_case(
10314        &mut self,
10315        _: &ConvertToLowerCamelCase,
10316        window: &mut Window,
10317        cx: &mut Context<Self>,
10318    ) {
10319        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10320    }
10321
10322    pub fn convert_to_opposite_case(
10323        &mut self,
10324        _: &ConvertToOppositeCase,
10325        window: &mut Window,
10326        cx: &mut Context<Self>,
10327    ) {
10328        self.manipulate_text(window, cx, |text| {
10329            text.chars()
10330                .fold(String::with_capacity(text.len()), |mut t, c| {
10331                    if c.is_uppercase() {
10332                        t.extend(c.to_lowercase());
10333                    } else {
10334                        t.extend(c.to_uppercase());
10335                    }
10336                    t
10337                })
10338        })
10339    }
10340
10341    pub fn convert_to_rot13(
10342        &mut self,
10343        _: &ConvertToRot13,
10344        window: &mut Window,
10345        cx: &mut Context<Self>,
10346    ) {
10347        self.manipulate_text(window, cx, |text| {
10348            text.chars()
10349                .map(|c| match c {
10350                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10351                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10352                    _ => c,
10353                })
10354                .collect()
10355        })
10356    }
10357
10358    pub fn convert_to_rot47(
10359        &mut self,
10360        _: &ConvertToRot47,
10361        window: &mut Window,
10362        cx: &mut Context<Self>,
10363    ) {
10364        self.manipulate_text(window, cx, |text| {
10365            text.chars()
10366                .map(|c| {
10367                    let code_point = c as u32;
10368                    if code_point >= 33 && code_point <= 126 {
10369                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10370                    }
10371                    c
10372                })
10373                .collect()
10374        })
10375    }
10376
10377    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10378    where
10379        Fn: FnMut(&str) -> String,
10380    {
10381        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10382        let buffer = self.buffer.read(cx).snapshot(cx);
10383
10384        let mut new_selections = Vec::new();
10385        let mut edits = Vec::new();
10386        let mut selection_adjustment = 0i32;
10387
10388        for selection in self.selections.all::<usize>(cx) {
10389            let selection_is_empty = selection.is_empty();
10390
10391            let (start, end) = if selection_is_empty {
10392                let word_range = movement::surrounding_word(
10393                    &display_map,
10394                    selection.start.to_display_point(&display_map),
10395                );
10396                let start = word_range.start.to_offset(&display_map, Bias::Left);
10397                let end = word_range.end.to_offset(&display_map, Bias::Left);
10398                (start, end)
10399            } else {
10400                (selection.start, selection.end)
10401            };
10402
10403            let text = buffer.text_for_range(start..end).collect::<String>();
10404            let old_length = text.len() as i32;
10405            let text = callback(&text);
10406
10407            new_selections.push(Selection {
10408                start: (start as i32 - selection_adjustment) as usize,
10409                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10410                goal: SelectionGoal::None,
10411                ..selection
10412            });
10413
10414            selection_adjustment += old_length - text.len() as i32;
10415
10416            edits.push((start..end, text));
10417        }
10418
10419        self.transact(window, cx, |this, window, cx| {
10420            this.buffer.update(cx, |buffer, cx| {
10421                buffer.edit(edits, None, cx);
10422            });
10423
10424            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10425                s.select(new_selections);
10426            });
10427
10428            this.request_autoscroll(Autoscroll::fit(), cx);
10429        });
10430    }
10431
10432    pub fn duplicate(
10433        &mut self,
10434        upwards: bool,
10435        whole_lines: bool,
10436        window: &mut Window,
10437        cx: &mut Context<Self>,
10438    ) {
10439        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10440
10441        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10442        let buffer = &display_map.buffer_snapshot;
10443        let selections = self.selections.all::<Point>(cx);
10444
10445        let mut edits = Vec::new();
10446        let mut selections_iter = selections.iter().peekable();
10447        while let Some(selection) = selections_iter.next() {
10448            let mut rows = selection.spanned_rows(false, &display_map);
10449            // duplicate line-wise
10450            if whole_lines || selection.start == selection.end {
10451                // Avoid duplicating the same lines twice.
10452                while let Some(next_selection) = selections_iter.peek() {
10453                    let next_rows = next_selection.spanned_rows(false, &display_map);
10454                    if next_rows.start < rows.end {
10455                        rows.end = next_rows.end;
10456                        selections_iter.next().unwrap();
10457                    } else {
10458                        break;
10459                    }
10460                }
10461
10462                // Copy the text from the selected row region and splice it either at the start
10463                // or end of the region.
10464                let start = Point::new(rows.start.0, 0);
10465                let end = Point::new(
10466                    rows.end.previous_row().0,
10467                    buffer.line_len(rows.end.previous_row()),
10468                );
10469                let text = buffer
10470                    .text_for_range(start..end)
10471                    .chain(Some("\n"))
10472                    .collect::<String>();
10473                let insert_location = if upwards {
10474                    Point::new(rows.end.0, 0)
10475                } else {
10476                    start
10477                };
10478                edits.push((insert_location..insert_location, text));
10479            } else {
10480                // duplicate character-wise
10481                let start = selection.start;
10482                let end = selection.end;
10483                let text = buffer.text_for_range(start..end).collect::<String>();
10484                edits.push((selection.end..selection.end, text));
10485            }
10486        }
10487
10488        self.transact(window, cx, |this, _, cx| {
10489            this.buffer.update(cx, |buffer, cx| {
10490                buffer.edit(edits, None, cx);
10491            });
10492
10493            this.request_autoscroll(Autoscroll::fit(), cx);
10494        });
10495    }
10496
10497    pub fn duplicate_line_up(
10498        &mut self,
10499        _: &DuplicateLineUp,
10500        window: &mut Window,
10501        cx: &mut Context<Self>,
10502    ) {
10503        self.duplicate(true, true, window, cx);
10504    }
10505
10506    pub fn duplicate_line_down(
10507        &mut self,
10508        _: &DuplicateLineDown,
10509        window: &mut Window,
10510        cx: &mut Context<Self>,
10511    ) {
10512        self.duplicate(false, true, window, cx);
10513    }
10514
10515    pub fn duplicate_selection(
10516        &mut self,
10517        _: &DuplicateSelection,
10518        window: &mut Window,
10519        cx: &mut Context<Self>,
10520    ) {
10521        self.duplicate(false, false, window, cx);
10522    }
10523
10524    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10525        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10526
10527        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10528        let buffer = self.buffer.read(cx).snapshot(cx);
10529
10530        let mut edits = Vec::new();
10531        let mut unfold_ranges = Vec::new();
10532        let mut refold_creases = Vec::new();
10533
10534        let selections = self.selections.all::<Point>(cx);
10535        let mut selections = selections.iter().peekable();
10536        let mut contiguous_row_selections = Vec::new();
10537        let mut new_selections = Vec::new();
10538
10539        while let Some(selection) = selections.next() {
10540            // Find all the selections that span a contiguous row range
10541            let (start_row, end_row) = consume_contiguous_rows(
10542                &mut contiguous_row_selections,
10543                selection,
10544                &display_map,
10545                &mut selections,
10546            );
10547
10548            // Move the text spanned by the row range to be before the line preceding the row range
10549            if start_row.0 > 0 {
10550                let range_to_move = Point::new(
10551                    start_row.previous_row().0,
10552                    buffer.line_len(start_row.previous_row()),
10553                )
10554                    ..Point::new(
10555                        end_row.previous_row().0,
10556                        buffer.line_len(end_row.previous_row()),
10557                    );
10558                let insertion_point = display_map
10559                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10560                    .0;
10561
10562                // Don't move lines across excerpts
10563                if buffer
10564                    .excerpt_containing(insertion_point..range_to_move.end)
10565                    .is_some()
10566                {
10567                    let text = buffer
10568                        .text_for_range(range_to_move.clone())
10569                        .flat_map(|s| s.chars())
10570                        .skip(1)
10571                        .chain(['\n'])
10572                        .collect::<String>();
10573
10574                    edits.push((
10575                        buffer.anchor_after(range_to_move.start)
10576                            ..buffer.anchor_before(range_to_move.end),
10577                        String::new(),
10578                    ));
10579                    let insertion_anchor = buffer.anchor_after(insertion_point);
10580                    edits.push((insertion_anchor..insertion_anchor, text));
10581
10582                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10583
10584                    // Move selections up
10585                    new_selections.extend(contiguous_row_selections.drain(..).map(
10586                        |mut selection| {
10587                            selection.start.row -= row_delta;
10588                            selection.end.row -= row_delta;
10589                            selection
10590                        },
10591                    ));
10592
10593                    // Move folds up
10594                    unfold_ranges.push(range_to_move.clone());
10595                    for fold in display_map.folds_in_range(
10596                        buffer.anchor_before(range_to_move.start)
10597                            ..buffer.anchor_after(range_to_move.end),
10598                    ) {
10599                        let mut start = fold.range.start.to_point(&buffer);
10600                        let mut end = fold.range.end.to_point(&buffer);
10601                        start.row -= row_delta;
10602                        end.row -= row_delta;
10603                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10604                    }
10605                }
10606            }
10607
10608            // If we didn't move line(s), preserve the existing selections
10609            new_selections.append(&mut contiguous_row_selections);
10610        }
10611
10612        self.transact(window, cx, |this, window, cx| {
10613            this.unfold_ranges(&unfold_ranges, true, true, cx);
10614            this.buffer.update(cx, |buffer, cx| {
10615                for (range, text) in edits {
10616                    buffer.edit([(range, text)], None, cx);
10617                }
10618            });
10619            this.fold_creases(refold_creases, true, window, cx);
10620            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10621                s.select(new_selections);
10622            })
10623        });
10624    }
10625
10626    pub fn move_line_down(
10627        &mut self,
10628        _: &MoveLineDown,
10629        window: &mut Window,
10630        cx: &mut Context<Self>,
10631    ) {
10632        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10633
10634        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10635        let buffer = self.buffer.read(cx).snapshot(cx);
10636
10637        let mut edits = Vec::new();
10638        let mut unfold_ranges = Vec::new();
10639        let mut refold_creases = Vec::new();
10640
10641        let selections = self.selections.all::<Point>(cx);
10642        let mut selections = selections.iter().peekable();
10643        let mut contiguous_row_selections = Vec::new();
10644        let mut new_selections = Vec::new();
10645
10646        while let Some(selection) = selections.next() {
10647            // Find all the selections that span a contiguous row range
10648            let (start_row, end_row) = consume_contiguous_rows(
10649                &mut contiguous_row_selections,
10650                selection,
10651                &display_map,
10652                &mut selections,
10653            );
10654
10655            // Move the text spanned by the row range to be after the last line of the row range
10656            if end_row.0 <= buffer.max_point().row {
10657                let range_to_move =
10658                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10659                let insertion_point = display_map
10660                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10661                    .0;
10662
10663                // Don't move lines across excerpt boundaries
10664                if buffer
10665                    .excerpt_containing(range_to_move.start..insertion_point)
10666                    .is_some()
10667                {
10668                    let mut text = String::from("\n");
10669                    text.extend(buffer.text_for_range(range_to_move.clone()));
10670                    text.pop(); // Drop trailing newline
10671                    edits.push((
10672                        buffer.anchor_after(range_to_move.start)
10673                            ..buffer.anchor_before(range_to_move.end),
10674                        String::new(),
10675                    ));
10676                    let insertion_anchor = buffer.anchor_after(insertion_point);
10677                    edits.push((insertion_anchor..insertion_anchor, text));
10678
10679                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10680
10681                    // Move selections down
10682                    new_selections.extend(contiguous_row_selections.drain(..).map(
10683                        |mut selection| {
10684                            selection.start.row += row_delta;
10685                            selection.end.row += row_delta;
10686                            selection
10687                        },
10688                    ));
10689
10690                    // Move folds down
10691                    unfold_ranges.push(range_to_move.clone());
10692                    for fold in display_map.folds_in_range(
10693                        buffer.anchor_before(range_to_move.start)
10694                            ..buffer.anchor_after(range_to_move.end),
10695                    ) {
10696                        let mut start = fold.range.start.to_point(&buffer);
10697                        let mut end = fold.range.end.to_point(&buffer);
10698                        start.row += row_delta;
10699                        end.row += row_delta;
10700                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10701                    }
10702                }
10703            }
10704
10705            // If we didn't move line(s), preserve the existing selections
10706            new_selections.append(&mut contiguous_row_selections);
10707        }
10708
10709        self.transact(window, cx, |this, window, cx| {
10710            this.unfold_ranges(&unfold_ranges, true, true, cx);
10711            this.buffer.update(cx, |buffer, cx| {
10712                for (range, text) in edits {
10713                    buffer.edit([(range, text)], None, cx);
10714                }
10715            });
10716            this.fold_creases(refold_creases, true, window, cx);
10717            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10718                s.select(new_selections)
10719            });
10720        });
10721    }
10722
10723    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10724        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10725        let text_layout_details = &self.text_layout_details(window);
10726        self.transact(window, cx, |this, window, cx| {
10727            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10728                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10729                s.move_with(|display_map, selection| {
10730                    if !selection.is_empty() {
10731                        return;
10732                    }
10733
10734                    let mut head = selection.head();
10735                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10736                    if head.column() == display_map.line_len(head.row()) {
10737                        transpose_offset = display_map
10738                            .buffer_snapshot
10739                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10740                    }
10741
10742                    if transpose_offset == 0 {
10743                        return;
10744                    }
10745
10746                    *head.column_mut() += 1;
10747                    head = display_map.clip_point(head, Bias::Right);
10748                    let goal = SelectionGoal::HorizontalPosition(
10749                        display_map
10750                            .x_for_display_point(head, text_layout_details)
10751                            .into(),
10752                    );
10753                    selection.collapse_to(head, goal);
10754
10755                    let transpose_start = display_map
10756                        .buffer_snapshot
10757                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10758                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10759                        let transpose_end = display_map
10760                            .buffer_snapshot
10761                            .clip_offset(transpose_offset + 1, Bias::Right);
10762                        if let Some(ch) =
10763                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10764                        {
10765                            edits.push((transpose_start..transpose_offset, String::new()));
10766                            edits.push((transpose_end..transpose_end, ch.to_string()));
10767                        }
10768                    }
10769                });
10770                edits
10771            });
10772            this.buffer
10773                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10774            let selections = this.selections.all::<usize>(cx);
10775            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10776                s.select(selections);
10777            });
10778        });
10779    }
10780
10781    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10782        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10783        self.rewrap_impl(RewrapOptions::default(), cx)
10784    }
10785
10786    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10787        let buffer = self.buffer.read(cx).snapshot(cx);
10788        let selections = self.selections.all::<Point>(cx);
10789        let mut selections = selections.iter().peekable();
10790
10791        let mut edits = Vec::new();
10792        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10793
10794        while let Some(selection) = selections.next() {
10795            let mut start_row = selection.start.row;
10796            let mut end_row = selection.end.row;
10797
10798            // Skip selections that overlap with a range that has already been rewrapped.
10799            let selection_range = start_row..end_row;
10800            if rewrapped_row_ranges
10801                .iter()
10802                .any(|range| range.overlaps(&selection_range))
10803            {
10804                continue;
10805            }
10806
10807            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10808
10809            // Since not all lines in the selection may be at the same indent
10810            // level, choose the indent size that is the most common between all
10811            // of the lines.
10812            //
10813            // If there is a tie, we use the deepest indent.
10814            let (indent_size, indent_end) = {
10815                let mut indent_size_occurrences = HashMap::default();
10816                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10817
10818                for row in start_row..=end_row {
10819                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10820                    rows_by_indent_size.entry(indent).or_default().push(row);
10821                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10822                }
10823
10824                let indent_size = indent_size_occurrences
10825                    .into_iter()
10826                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10827                    .map(|(indent, _)| indent)
10828                    .unwrap_or_default();
10829                let row = rows_by_indent_size[&indent_size][0];
10830                let indent_end = Point::new(row, indent_size.len);
10831
10832                (indent_size, indent_end)
10833            };
10834
10835            let mut line_prefix = indent_size.chars().collect::<String>();
10836
10837            let mut inside_comment = false;
10838            if let Some(comment_prefix) =
10839                buffer
10840                    .language_scope_at(selection.head())
10841                    .and_then(|language| {
10842                        language
10843                            .line_comment_prefixes()
10844                            .iter()
10845                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10846                            .cloned()
10847                    })
10848            {
10849                line_prefix.push_str(&comment_prefix);
10850                inside_comment = true;
10851            }
10852
10853            let language_settings = buffer.language_settings_at(selection.head(), cx);
10854            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10855                RewrapBehavior::InComments => inside_comment,
10856                RewrapBehavior::InSelections => !selection.is_empty(),
10857                RewrapBehavior::Anywhere => true,
10858            };
10859
10860            let should_rewrap = options.override_language_settings
10861                || allow_rewrap_based_on_language
10862                || self.hard_wrap.is_some();
10863            if !should_rewrap {
10864                continue;
10865            }
10866
10867            if selection.is_empty() {
10868                'expand_upwards: while start_row > 0 {
10869                    let prev_row = start_row - 1;
10870                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10871                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10872                    {
10873                        start_row = prev_row;
10874                    } else {
10875                        break 'expand_upwards;
10876                    }
10877                }
10878
10879                'expand_downwards: while end_row < buffer.max_point().row {
10880                    let next_row = end_row + 1;
10881                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10882                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10883                    {
10884                        end_row = next_row;
10885                    } else {
10886                        break 'expand_downwards;
10887                    }
10888                }
10889            }
10890
10891            let start = Point::new(start_row, 0);
10892            let start_offset = start.to_offset(&buffer);
10893            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10894            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10895            let Some(lines_without_prefixes) = selection_text
10896                .lines()
10897                .map(|line| {
10898                    line.strip_prefix(&line_prefix)
10899                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10900                        .with_context(|| {
10901                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
10902                        })
10903                })
10904                .collect::<Result<Vec<_>, _>>()
10905                .log_err()
10906            else {
10907                continue;
10908            };
10909
10910            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10911                buffer
10912                    .language_settings_at(Point::new(start_row, 0), cx)
10913                    .preferred_line_length as usize
10914            });
10915            let wrapped_text = wrap_with_prefix(
10916                line_prefix,
10917                lines_without_prefixes.join("\n"),
10918                wrap_column,
10919                tab_size,
10920                options.preserve_existing_whitespace,
10921            );
10922
10923            // TODO: should always use char-based diff while still supporting cursor behavior that
10924            // matches vim.
10925            let mut diff_options = DiffOptions::default();
10926            if options.override_language_settings {
10927                diff_options.max_word_diff_len = 0;
10928                diff_options.max_word_diff_line_count = 0;
10929            } else {
10930                diff_options.max_word_diff_len = usize::MAX;
10931                diff_options.max_word_diff_line_count = usize::MAX;
10932            }
10933
10934            for (old_range, new_text) in
10935                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10936            {
10937                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10938                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10939                edits.push((edit_start..edit_end, new_text));
10940            }
10941
10942            rewrapped_row_ranges.push(start_row..=end_row);
10943        }
10944
10945        self.buffer
10946            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10947    }
10948
10949    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
10950        let mut text = String::new();
10951        let buffer = self.buffer.read(cx).snapshot(cx);
10952        let mut selections = self.selections.all::<Point>(cx);
10953        let mut clipboard_selections = Vec::with_capacity(selections.len());
10954        {
10955            let max_point = buffer.max_point();
10956            let mut is_first = true;
10957            for selection in &mut selections {
10958                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10959                if is_entire_line {
10960                    selection.start = Point::new(selection.start.row, 0);
10961                    if !selection.is_empty() && selection.end.column == 0 {
10962                        selection.end = cmp::min(max_point, selection.end);
10963                    } else {
10964                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
10965                    }
10966                    selection.goal = SelectionGoal::None;
10967                }
10968                if is_first {
10969                    is_first = false;
10970                } else {
10971                    text += "\n";
10972                }
10973                let mut len = 0;
10974                for chunk in buffer.text_for_range(selection.start..selection.end) {
10975                    text.push_str(chunk);
10976                    len += chunk.len();
10977                }
10978                clipboard_selections.push(ClipboardSelection {
10979                    len,
10980                    is_entire_line,
10981                    first_line_indent: buffer
10982                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10983                        .len,
10984                });
10985            }
10986        }
10987
10988        self.transact(window, cx, |this, window, cx| {
10989            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10990                s.select(selections);
10991            });
10992            this.insert("", window, cx);
10993        });
10994        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10995    }
10996
10997    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10998        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10999        let item = self.cut_common(window, cx);
11000        cx.write_to_clipboard(item);
11001    }
11002
11003    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11004        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11005        self.change_selections(None, window, cx, |s| {
11006            s.move_with(|snapshot, sel| {
11007                if sel.is_empty() {
11008                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11009                }
11010            });
11011        });
11012        let item = self.cut_common(window, cx);
11013        cx.set_global(KillRing(item))
11014    }
11015
11016    pub fn kill_ring_yank(
11017        &mut self,
11018        _: &KillRingYank,
11019        window: &mut Window,
11020        cx: &mut Context<Self>,
11021    ) {
11022        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11023        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11024            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11025                (kill_ring.text().to_string(), kill_ring.metadata_json())
11026            } else {
11027                return;
11028            }
11029        } else {
11030            return;
11031        };
11032        self.do_paste(&text, metadata, false, window, cx);
11033    }
11034
11035    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11036        self.do_copy(true, cx);
11037    }
11038
11039    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11040        self.do_copy(false, cx);
11041    }
11042
11043    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11044        let selections = self.selections.all::<Point>(cx);
11045        let buffer = self.buffer.read(cx).read(cx);
11046        let mut text = String::new();
11047
11048        let mut clipboard_selections = Vec::with_capacity(selections.len());
11049        {
11050            let max_point = buffer.max_point();
11051            let mut is_first = true;
11052            for selection in &selections {
11053                let mut start = selection.start;
11054                let mut end = selection.end;
11055                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11056                if is_entire_line {
11057                    start = Point::new(start.row, 0);
11058                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11059                }
11060
11061                let mut trimmed_selections = Vec::new();
11062                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11063                    let row = MultiBufferRow(start.row);
11064                    let first_indent = buffer.indent_size_for_line(row);
11065                    if first_indent.len == 0 || start.column > first_indent.len {
11066                        trimmed_selections.push(start..end);
11067                    } else {
11068                        trimmed_selections.push(
11069                            Point::new(row.0, first_indent.len)
11070                                ..Point::new(row.0, buffer.line_len(row)),
11071                        );
11072                        for row in start.row + 1..=end.row {
11073                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11074                            if row == end.row {
11075                                line_len = end.column;
11076                            }
11077                            if line_len == 0 {
11078                                trimmed_selections
11079                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11080                                continue;
11081                            }
11082                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11083                            if row_indent_size.len >= first_indent.len {
11084                                trimmed_selections.push(
11085                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11086                                );
11087                            } else {
11088                                trimmed_selections.clear();
11089                                trimmed_selections.push(start..end);
11090                                break;
11091                            }
11092                        }
11093                    }
11094                } else {
11095                    trimmed_selections.push(start..end);
11096                }
11097
11098                for trimmed_range in trimmed_selections {
11099                    if is_first {
11100                        is_first = false;
11101                    } else {
11102                        text += "\n";
11103                    }
11104                    let mut len = 0;
11105                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11106                        text.push_str(chunk);
11107                        len += chunk.len();
11108                    }
11109                    clipboard_selections.push(ClipboardSelection {
11110                        len,
11111                        is_entire_line,
11112                        first_line_indent: buffer
11113                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11114                            .len,
11115                    });
11116                }
11117            }
11118        }
11119
11120        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11121            text,
11122            clipboard_selections,
11123        ));
11124    }
11125
11126    pub fn do_paste(
11127        &mut self,
11128        text: &String,
11129        clipboard_selections: Option<Vec<ClipboardSelection>>,
11130        handle_entire_lines: bool,
11131        window: &mut Window,
11132        cx: &mut Context<Self>,
11133    ) {
11134        if self.read_only(cx) {
11135            return;
11136        }
11137
11138        let clipboard_text = Cow::Borrowed(text);
11139
11140        self.transact(window, cx, |this, window, cx| {
11141            if let Some(mut clipboard_selections) = clipboard_selections {
11142                let old_selections = this.selections.all::<usize>(cx);
11143                let all_selections_were_entire_line =
11144                    clipboard_selections.iter().all(|s| s.is_entire_line);
11145                let first_selection_indent_column =
11146                    clipboard_selections.first().map(|s| s.first_line_indent);
11147                if clipboard_selections.len() != old_selections.len() {
11148                    clipboard_selections.drain(..);
11149                }
11150                let cursor_offset = this.selections.last::<usize>(cx).head();
11151                let mut auto_indent_on_paste = true;
11152
11153                this.buffer.update(cx, |buffer, cx| {
11154                    let snapshot = buffer.read(cx);
11155                    auto_indent_on_paste = snapshot
11156                        .language_settings_at(cursor_offset, cx)
11157                        .auto_indent_on_paste;
11158
11159                    let mut start_offset = 0;
11160                    let mut edits = Vec::new();
11161                    let mut original_indent_columns = Vec::new();
11162                    for (ix, selection) in old_selections.iter().enumerate() {
11163                        let to_insert;
11164                        let entire_line;
11165                        let original_indent_column;
11166                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11167                            let end_offset = start_offset + clipboard_selection.len;
11168                            to_insert = &clipboard_text[start_offset..end_offset];
11169                            entire_line = clipboard_selection.is_entire_line;
11170                            start_offset = end_offset + 1;
11171                            original_indent_column = Some(clipboard_selection.first_line_indent);
11172                        } else {
11173                            to_insert = clipboard_text.as_str();
11174                            entire_line = all_selections_were_entire_line;
11175                            original_indent_column = first_selection_indent_column
11176                        }
11177
11178                        // If the corresponding selection was empty when this slice of the
11179                        // clipboard text was written, then the entire line containing the
11180                        // selection was copied. If this selection is also currently empty,
11181                        // then paste the line before the current line of the buffer.
11182                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11183                            let column = selection.start.to_point(&snapshot).column as usize;
11184                            let line_start = selection.start - column;
11185                            line_start..line_start
11186                        } else {
11187                            selection.range()
11188                        };
11189
11190                        edits.push((range, to_insert));
11191                        original_indent_columns.push(original_indent_column);
11192                    }
11193                    drop(snapshot);
11194
11195                    buffer.edit(
11196                        edits,
11197                        if auto_indent_on_paste {
11198                            Some(AutoindentMode::Block {
11199                                original_indent_columns,
11200                            })
11201                        } else {
11202                            None
11203                        },
11204                        cx,
11205                    );
11206                });
11207
11208                let selections = this.selections.all::<usize>(cx);
11209                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11210                    s.select(selections)
11211                });
11212            } else {
11213                this.insert(&clipboard_text, window, cx);
11214            }
11215        });
11216    }
11217
11218    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11219        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11220        if let Some(item) = cx.read_from_clipboard() {
11221            let entries = item.entries();
11222
11223            match entries.first() {
11224                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11225                // of all the pasted entries.
11226                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11227                    .do_paste(
11228                        clipboard_string.text(),
11229                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11230                        true,
11231                        window,
11232                        cx,
11233                    ),
11234                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11235            }
11236        }
11237    }
11238
11239    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11240        if self.read_only(cx) {
11241            return;
11242        }
11243
11244        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11245
11246        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11247            if let Some((selections, _)) =
11248                self.selection_history.transaction(transaction_id).cloned()
11249            {
11250                self.change_selections(None, window, cx, |s| {
11251                    s.select_anchors(selections.to_vec());
11252                });
11253            } else {
11254                log::error!(
11255                    "No entry in selection_history found for undo. \
11256                     This may correspond to a bug where undo does not update the selection. \
11257                     If this is occurring, please add details to \
11258                     https://github.com/zed-industries/zed/issues/22692"
11259                );
11260            }
11261            self.request_autoscroll(Autoscroll::fit(), cx);
11262            self.unmark_text(window, cx);
11263            self.refresh_inline_completion(true, false, window, cx);
11264            cx.emit(EditorEvent::Edited { transaction_id });
11265            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11266        }
11267    }
11268
11269    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11270        if self.read_only(cx) {
11271            return;
11272        }
11273
11274        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11275
11276        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11277            if let Some((_, Some(selections))) =
11278                self.selection_history.transaction(transaction_id).cloned()
11279            {
11280                self.change_selections(None, window, cx, |s| {
11281                    s.select_anchors(selections.to_vec());
11282                });
11283            } else {
11284                log::error!(
11285                    "No entry in selection_history found for redo. \
11286                     This may correspond to a bug where undo does not update the selection. \
11287                     If this is occurring, please add details to \
11288                     https://github.com/zed-industries/zed/issues/22692"
11289                );
11290            }
11291            self.request_autoscroll(Autoscroll::fit(), cx);
11292            self.unmark_text(window, cx);
11293            self.refresh_inline_completion(true, false, window, cx);
11294            cx.emit(EditorEvent::Edited { transaction_id });
11295        }
11296    }
11297
11298    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11299        self.buffer
11300            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11301    }
11302
11303    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11304        self.buffer
11305            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11306    }
11307
11308    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11309        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11310        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11311            s.move_with(|map, selection| {
11312                let cursor = if selection.is_empty() {
11313                    movement::left(map, selection.start)
11314                } else {
11315                    selection.start
11316                };
11317                selection.collapse_to(cursor, SelectionGoal::None);
11318            });
11319        })
11320    }
11321
11322    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11323        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11324        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11325            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11326        })
11327    }
11328
11329    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11330        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11331        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11332            s.move_with(|map, selection| {
11333                let cursor = if selection.is_empty() {
11334                    movement::right(map, selection.end)
11335                } else {
11336                    selection.end
11337                };
11338                selection.collapse_to(cursor, SelectionGoal::None)
11339            });
11340        })
11341    }
11342
11343    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11344        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11345        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11346            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11347        })
11348    }
11349
11350    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11351        if self.take_rename(true, window, cx).is_some() {
11352            return;
11353        }
11354
11355        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11356            cx.propagate();
11357            return;
11358        }
11359
11360        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11361
11362        let text_layout_details = &self.text_layout_details(window);
11363        let selection_count = self.selections.count();
11364        let first_selection = self.selections.first_anchor();
11365
11366        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11367            s.move_with(|map, selection| {
11368                if !selection.is_empty() {
11369                    selection.goal = SelectionGoal::None;
11370                }
11371                let (cursor, goal) = movement::up(
11372                    map,
11373                    selection.start,
11374                    selection.goal,
11375                    false,
11376                    text_layout_details,
11377                );
11378                selection.collapse_to(cursor, goal);
11379            });
11380        });
11381
11382        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11383        {
11384            cx.propagate();
11385        }
11386    }
11387
11388    pub fn move_up_by_lines(
11389        &mut self,
11390        action: &MoveUpByLines,
11391        window: &mut Window,
11392        cx: &mut Context<Self>,
11393    ) {
11394        if self.take_rename(true, window, cx).is_some() {
11395            return;
11396        }
11397
11398        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11399            cx.propagate();
11400            return;
11401        }
11402
11403        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11404
11405        let text_layout_details = &self.text_layout_details(window);
11406
11407        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11408            s.move_with(|map, selection| {
11409                if !selection.is_empty() {
11410                    selection.goal = SelectionGoal::None;
11411                }
11412                let (cursor, goal) = movement::up_by_rows(
11413                    map,
11414                    selection.start,
11415                    action.lines,
11416                    selection.goal,
11417                    false,
11418                    text_layout_details,
11419                );
11420                selection.collapse_to(cursor, goal);
11421            });
11422        })
11423    }
11424
11425    pub fn move_down_by_lines(
11426        &mut self,
11427        action: &MoveDownByLines,
11428        window: &mut Window,
11429        cx: &mut Context<Self>,
11430    ) {
11431        if self.take_rename(true, window, cx).is_some() {
11432            return;
11433        }
11434
11435        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11436            cx.propagate();
11437            return;
11438        }
11439
11440        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11441
11442        let text_layout_details = &self.text_layout_details(window);
11443
11444        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11445            s.move_with(|map, selection| {
11446                if !selection.is_empty() {
11447                    selection.goal = SelectionGoal::None;
11448                }
11449                let (cursor, goal) = movement::down_by_rows(
11450                    map,
11451                    selection.start,
11452                    action.lines,
11453                    selection.goal,
11454                    false,
11455                    text_layout_details,
11456                );
11457                selection.collapse_to(cursor, goal);
11458            });
11459        })
11460    }
11461
11462    pub fn select_down_by_lines(
11463        &mut self,
11464        action: &SelectDownByLines,
11465        window: &mut Window,
11466        cx: &mut Context<Self>,
11467    ) {
11468        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11469        let text_layout_details = &self.text_layout_details(window);
11470        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11471            s.move_heads_with(|map, head, goal| {
11472                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11473            })
11474        })
11475    }
11476
11477    pub fn select_up_by_lines(
11478        &mut self,
11479        action: &SelectUpByLines,
11480        window: &mut Window,
11481        cx: &mut Context<Self>,
11482    ) {
11483        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11484        let text_layout_details = &self.text_layout_details(window);
11485        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11486            s.move_heads_with(|map, head, goal| {
11487                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11488            })
11489        })
11490    }
11491
11492    pub fn select_page_up(
11493        &mut self,
11494        _: &SelectPageUp,
11495        window: &mut Window,
11496        cx: &mut Context<Self>,
11497    ) {
11498        let Some(row_count) = self.visible_row_count() else {
11499            return;
11500        };
11501
11502        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11503
11504        let text_layout_details = &self.text_layout_details(window);
11505
11506        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11507            s.move_heads_with(|map, head, goal| {
11508                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11509            })
11510        })
11511    }
11512
11513    pub fn move_page_up(
11514        &mut self,
11515        action: &MovePageUp,
11516        window: &mut Window,
11517        cx: &mut Context<Self>,
11518    ) {
11519        if self.take_rename(true, window, cx).is_some() {
11520            return;
11521        }
11522
11523        if self
11524            .context_menu
11525            .borrow_mut()
11526            .as_mut()
11527            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11528            .unwrap_or(false)
11529        {
11530            return;
11531        }
11532
11533        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11534            cx.propagate();
11535            return;
11536        }
11537
11538        let Some(row_count) = self.visible_row_count() else {
11539            return;
11540        };
11541
11542        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11543
11544        let autoscroll = if action.center_cursor {
11545            Autoscroll::center()
11546        } else {
11547            Autoscroll::fit()
11548        };
11549
11550        let text_layout_details = &self.text_layout_details(window);
11551
11552        self.change_selections(Some(autoscroll), window, cx, |s| {
11553            s.move_with(|map, selection| {
11554                if !selection.is_empty() {
11555                    selection.goal = SelectionGoal::None;
11556                }
11557                let (cursor, goal) = movement::up_by_rows(
11558                    map,
11559                    selection.end,
11560                    row_count,
11561                    selection.goal,
11562                    false,
11563                    text_layout_details,
11564                );
11565                selection.collapse_to(cursor, goal);
11566            });
11567        });
11568    }
11569
11570    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11571        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11572        let text_layout_details = &self.text_layout_details(window);
11573        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11574            s.move_heads_with(|map, head, goal| {
11575                movement::up(map, head, goal, false, text_layout_details)
11576            })
11577        })
11578    }
11579
11580    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11581        self.take_rename(true, window, cx);
11582
11583        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11584            cx.propagate();
11585            return;
11586        }
11587
11588        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11589
11590        let text_layout_details = &self.text_layout_details(window);
11591        let selection_count = self.selections.count();
11592        let first_selection = self.selections.first_anchor();
11593
11594        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11595            s.move_with(|map, selection| {
11596                if !selection.is_empty() {
11597                    selection.goal = SelectionGoal::None;
11598                }
11599                let (cursor, goal) = movement::down(
11600                    map,
11601                    selection.end,
11602                    selection.goal,
11603                    false,
11604                    text_layout_details,
11605                );
11606                selection.collapse_to(cursor, goal);
11607            });
11608        });
11609
11610        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11611        {
11612            cx.propagate();
11613        }
11614    }
11615
11616    pub fn select_page_down(
11617        &mut self,
11618        _: &SelectPageDown,
11619        window: &mut Window,
11620        cx: &mut Context<Self>,
11621    ) {
11622        let Some(row_count) = self.visible_row_count() else {
11623            return;
11624        };
11625
11626        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11627
11628        let text_layout_details = &self.text_layout_details(window);
11629
11630        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11631            s.move_heads_with(|map, head, goal| {
11632                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11633            })
11634        })
11635    }
11636
11637    pub fn move_page_down(
11638        &mut self,
11639        action: &MovePageDown,
11640        window: &mut Window,
11641        cx: &mut Context<Self>,
11642    ) {
11643        if self.take_rename(true, window, cx).is_some() {
11644            return;
11645        }
11646
11647        if self
11648            .context_menu
11649            .borrow_mut()
11650            .as_mut()
11651            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
11652            .unwrap_or(false)
11653        {
11654            return;
11655        }
11656
11657        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11658            cx.propagate();
11659            return;
11660        }
11661
11662        let Some(row_count) = self.visible_row_count() else {
11663            return;
11664        };
11665
11666        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11667
11668        let autoscroll = if action.center_cursor {
11669            Autoscroll::center()
11670        } else {
11671            Autoscroll::fit()
11672        };
11673
11674        let text_layout_details = &self.text_layout_details(window);
11675        self.change_selections(Some(autoscroll), window, cx, |s| {
11676            s.move_with(|map, selection| {
11677                if !selection.is_empty() {
11678                    selection.goal = SelectionGoal::None;
11679                }
11680                let (cursor, goal) = movement::down_by_rows(
11681                    map,
11682                    selection.end,
11683                    row_count,
11684                    selection.goal,
11685                    false,
11686                    text_layout_details,
11687                );
11688                selection.collapse_to(cursor, goal);
11689            });
11690        });
11691    }
11692
11693    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11694        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11695        let text_layout_details = &self.text_layout_details(window);
11696        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11697            s.move_heads_with(|map, head, goal| {
11698                movement::down(map, head, goal, false, text_layout_details)
11699            })
11700        });
11701    }
11702
11703    pub fn context_menu_first(
11704        &mut self,
11705        _: &ContextMenuFirst,
11706        window: &mut Window,
11707        cx: &mut Context<Self>,
11708    ) {
11709        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11710            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
11711        }
11712    }
11713
11714    pub fn context_menu_prev(
11715        &mut self,
11716        _: &ContextMenuPrevious,
11717        window: &mut Window,
11718        cx: &mut Context<Self>,
11719    ) {
11720        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11721            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
11722        }
11723    }
11724
11725    pub fn context_menu_next(
11726        &mut self,
11727        _: &ContextMenuNext,
11728        window: &mut Window,
11729        cx: &mut Context<Self>,
11730    ) {
11731        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11732            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
11733        }
11734    }
11735
11736    pub fn context_menu_last(
11737        &mut self,
11738        _: &ContextMenuLast,
11739        window: &mut Window,
11740        cx: &mut Context<Self>,
11741    ) {
11742        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11743            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
11744        }
11745    }
11746
11747    pub fn move_to_previous_word_start(
11748        &mut self,
11749        _: &MoveToPreviousWordStart,
11750        window: &mut Window,
11751        cx: &mut Context<Self>,
11752    ) {
11753        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11754        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11755            s.move_cursors_with(|map, head, _| {
11756                (
11757                    movement::previous_word_start(map, head),
11758                    SelectionGoal::None,
11759                )
11760            });
11761        })
11762    }
11763
11764    pub fn move_to_previous_subword_start(
11765        &mut self,
11766        _: &MoveToPreviousSubwordStart,
11767        window: &mut Window,
11768        cx: &mut Context<Self>,
11769    ) {
11770        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11771        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11772            s.move_cursors_with(|map, head, _| {
11773                (
11774                    movement::previous_subword_start(map, head),
11775                    SelectionGoal::None,
11776                )
11777            });
11778        })
11779    }
11780
11781    pub fn select_to_previous_word_start(
11782        &mut self,
11783        _: &SelectToPreviousWordStart,
11784        window: &mut Window,
11785        cx: &mut Context<Self>,
11786    ) {
11787        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11788        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11789            s.move_heads_with(|map, head, _| {
11790                (
11791                    movement::previous_word_start(map, head),
11792                    SelectionGoal::None,
11793                )
11794            });
11795        })
11796    }
11797
11798    pub fn select_to_previous_subword_start(
11799        &mut self,
11800        _: &SelectToPreviousSubwordStart,
11801        window: &mut Window,
11802        cx: &mut Context<Self>,
11803    ) {
11804        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11805        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11806            s.move_heads_with(|map, head, _| {
11807                (
11808                    movement::previous_subword_start(map, head),
11809                    SelectionGoal::None,
11810                )
11811            });
11812        })
11813    }
11814
11815    pub fn delete_to_previous_word_start(
11816        &mut self,
11817        action: &DeleteToPreviousWordStart,
11818        window: &mut Window,
11819        cx: &mut Context<Self>,
11820    ) {
11821        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11822        self.transact(window, cx, |this, window, cx| {
11823            this.select_autoclose_pair(window, cx);
11824            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11825                s.move_with(|map, selection| {
11826                    if selection.is_empty() {
11827                        let cursor = if action.ignore_newlines {
11828                            movement::previous_word_start(map, selection.head())
11829                        } else {
11830                            movement::previous_word_start_or_newline(map, selection.head())
11831                        };
11832                        selection.set_head(cursor, SelectionGoal::None);
11833                    }
11834                });
11835            });
11836            this.insert("", window, cx);
11837        });
11838    }
11839
11840    pub fn delete_to_previous_subword_start(
11841        &mut self,
11842        _: &DeleteToPreviousSubwordStart,
11843        window: &mut Window,
11844        cx: &mut Context<Self>,
11845    ) {
11846        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11847        self.transact(window, cx, |this, window, cx| {
11848            this.select_autoclose_pair(window, cx);
11849            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11850                s.move_with(|map, selection| {
11851                    if selection.is_empty() {
11852                        let cursor = movement::previous_subword_start(map, selection.head());
11853                        selection.set_head(cursor, SelectionGoal::None);
11854                    }
11855                });
11856            });
11857            this.insert("", window, cx);
11858        });
11859    }
11860
11861    pub fn move_to_next_word_end(
11862        &mut self,
11863        _: &MoveToNextWordEnd,
11864        window: &mut Window,
11865        cx: &mut Context<Self>,
11866    ) {
11867        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11868        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11869            s.move_cursors_with(|map, head, _| {
11870                (movement::next_word_end(map, head), SelectionGoal::None)
11871            });
11872        })
11873    }
11874
11875    pub fn move_to_next_subword_end(
11876        &mut self,
11877        _: &MoveToNextSubwordEnd,
11878        window: &mut Window,
11879        cx: &mut Context<Self>,
11880    ) {
11881        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11882        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11883            s.move_cursors_with(|map, head, _| {
11884                (movement::next_subword_end(map, head), SelectionGoal::None)
11885            });
11886        })
11887    }
11888
11889    pub fn select_to_next_word_end(
11890        &mut self,
11891        _: &SelectToNextWordEnd,
11892        window: &mut Window,
11893        cx: &mut Context<Self>,
11894    ) {
11895        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11896        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11897            s.move_heads_with(|map, head, _| {
11898                (movement::next_word_end(map, head), SelectionGoal::None)
11899            });
11900        })
11901    }
11902
11903    pub fn select_to_next_subword_end(
11904        &mut self,
11905        _: &SelectToNextSubwordEnd,
11906        window: &mut Window,
11907        cx: &mut Context<Self>,
11908    ) {
11909        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11910        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11911            s.move_heads_with(|map, head, _| {
11912                (movement::next_subword_end(map, head), SelectionGoal::None)
11913            });
11914        })
11915    }
11916
11917    pub fn delete_to_next_word_end(
11918        &mut self,
11919        action: &DeleteToNextWordEnd,
11920        window: &mut Window,
11921        cx: &mut Context<Self>,
11922    ) {
11923        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11924        self.transact(window, cx, |this, window, cx| {
11925            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11926                s.move_with(|map, selection| {
11927                    if selection.is_empty() {
11928                        let cursor = if action.ignore_newlines {
11929                            movement::next_word_end(map, selection.head())
11930                        } else {
11931                            movement::next_word_end_or_newline(map, selection.head())
11932                        };
11933                        selection.set_head(cursor, SelectionGoal::None);
11934                    }
11935                });
11936            });
11937            this.insert("", window, cx);
11938        });
11939    }
11940
11941    pub fn delete_to_next_subword_end(
11942        &mut self,
11943        _: &DeleteToNextSubwordEnd,
11944        window: &mut Window,
11945        cx: &mut Context<Self>,
11946    ) {
11947        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11948        self.transact(window, cx, |this, window, cx| {
11949            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11950                s.move_with(|map, selection| {
11951                    if selection.is_empty() {
11952                        let cursor = movement::next_subword_end(map, selection.head());
11953                        selection.set_head(cursor, SelectionGoal::None);
11954                    }
11955                });
11956            });
11957            this.insert("", window, cx);
11958        });
11959    }
11960
11961    pub fn move_to_beginning_of_line(
11962        &mut self,
11963        action: &MoveToBeginningOfLine,
11964        window: &mut Window,
11965        cx: &mut Context<Self>,
11966    ) {
11967        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11968        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11969            s.move_cursors_with(|map, head, _| {
11970                (
11971                    movement::indented_line_beginning(
11972                        map,
11973                        head,
11974                        action.stop_at_soft_wraps,
11975                        action.stop_at_indent,
11976                    ),
11977                    SelectionGoal::None,
11978                )
11979            });
11980        })
11981    }
11982
11983    pub fn select_to_beginning_of_line(
11984        &mut self,
11985        action: &SelectToBeginningOfLine,
11986        window: &mut Window,
11987        cx: &mut Context<Self>,
11988    ) {
11989        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11990        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11991            s.move_heads_with(|map, head, _| {
11992                (
11993                    movement::indented_line_beginning(
11994                        map,
11995                        head,
11996                        action.stop_at_soft_wraps,
11997                        action.stop_at_indent,
11998                    ),
11999                    SelectionGoal::None,
12000                )
12001            });
12002        });
12003    }
12004
12005    pub fn delete_to_beginning_of_line(
12006        &mut self,
12007        action: &DeleteToBeginningOfLine,
12008        window: &mut Window,
12009        cx: &mut Context<Self>,
12010    ) {
12011        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12012        self.transact(window, cx, |this, window, cx| {
12013            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12014                s.move_with(|_, selection| {
12015                    selection.reversed = true;
12016                });
12017            });
12018
12019            this.select_to_beginning_of_line(
12020                &SelectToBeginningOfLine {
12021                    stop_at_soft_wraps: false,
12022                    stop_at_indent: action.stop_at_indent,
12023                },
12024                window,
12025                cx,
12026            );
12027            this.backspace(&Backspace, window, cx);
12028        });
12029    }
12030
12031    pub fn move_to_end_of_line(
12032        &mut self,
12033        action: &MoveToEndOfLine,
12034        window: &mut Window,
12035        cx: &mut Context<Self>,
12036    ) {
12037        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12038        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12039            s.move_cursors_with(|map, head, _| {
12040                (
12041                    movement::line_end(map, head, action.stop_at_soft_wraps),
12042                    SelectionGoal::None,
12043                )
12044            });
12045        })
12046    }
12047
12048    pub fn select_to_end_of_line(
12049        &mut self,
12050        action: &SelectToEndOfLine,
12051        window: &mut Window,
12052        cx: &mut Context<Self>,
12053    ) {
12054        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12055        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12056            s.move_heads_with(|map, head, _| {
12057                (
12058                    movement::line_end(map, head, action.stop_at_soft_wraps),
12059                    SelectionGoal::None,
12060                )
12061            });
12062        })
12063    }
12064
12065    pub fn delete_to_end_of_line(
12066        &mut self,
12067        _: &DeleteToEndOfLine,
12068        window: &mut Window,
12069        cx: &mut Context<Self>,
12070    ) {
12071        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12072        self.transact(window, cx, |this, window, cx| {
12073            this.select_to_end_of_line(
12074                &SelectToEndOfLine {
12075                    stop_at_soft_wraps: false,
12076                },
12077                window,
12078                cx,
12079            );
12080            this.delete(&Delete, window, cx);
12081        });
12082    }
12083
12084    pub fn cut_to_end_of_line(
12085        &mut self,
12086        _: &CutToEndOfLine,
12087        window: &mut Window,
12088        cx: &mut Context<Self>,
12089    ) {
12090        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12091        self.transact(window, cx, |this, window, cx| {
12092            this.select_to_end_of_line(
12093                &SelectToEndOfLine {
12094                    stop_at_soft_wraps: false,
12095                },
12096                window,
12097                cx,
12098            );
12099            this.cut(&Cut, window, cx);
12100        });
12101    }
12102
12103    pub fn move_to_start_of_paragraph(
12104        &mut self,
12105        _: &MoveToStartOfParagraph,
12106        window: &mut Window,
12107        cx: &mut Context<Self>,
12108    ) {
12109        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12110            cx.propagate();
12111            return;
12112        }
12113        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12114        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12115            s.move_with(|map, selection| {
12116                selection.collapse_to(
12117                    movement::start_of_paragraph(map, selection.head(), 1),
12118                    SelectionGoal::None,
12119                )
12120            });
12121        })
12122    }
12123
12124    pub fn move_to_end_of_paragraph(
12125        &mut self,
12126        _: &MoveToEndOfParagraph,
12127        window: &mut Window,
12128        cx: &mut Context<Self>,
12129    ) {
12130        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12131            cx.propagate();
12132            return;
12133        }
12134        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12135        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12136            s.move_with(|map, selection| {
12137                selection.collapse_to(
12138                    movement::end_of_paragraph(map, selection.head(), 1),
12139                    SelectionGoal::None,
12140                )
12141            });
12142        })
12143    }
12144
12145    pub fn select_to_start_of_paragraph(
12146        &mut self,
12147        _: &SelectToStartOfParagraph,
12148        window: &mut Window,
12149        cx: &mut Context<Self>,
12150    ) {
12151        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12152            cx.propagate();
12153            return;
12154        }
12155        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12156        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12157            s.move_heads_with(|map, head, _| {
12158                (
12159                    movement::start_of_paragraph(map, head, 1),
12160                    SelectionGoal::None,
12161                )
12162            });
12163        })
12164    }
12165
12166    pub fn select_to_end_of_paragraph(
12167        &mut self,
12168        _: &SelectToEndOfParagraph,
12169        window: &mut Window,
12170        cx: &mut Context<Self>,
12171    ) {
12172        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12173            cx.propagate();
12174            return;
12175        }
12176        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12177        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12178            s.move_heads_with(|map, head, _| {
12179                (
12180                    movement::end_of_paragraph(map, head, 1),
12181                    SelectionGoal::None,
12182                )
12183            });
12184        })
12185    }
12186
12187    pub fn move_to_start_of_excerpt(
12188        &mut self,
12189        _: &MoveToStartOfExcerpt,
12190        window: &mut Window,
12191        cx: &mut Context<Self>,
12192    ) {
12193        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12194            cx.propagate();
12195            return;
12196        }
12197        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12198        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12199            s.move_with(|map, selection| {
12200                selection.collapse_to(
12201                    movement::start_of_excerpt(
12202                        map,
12203                        selection.head(),
12204                        workspace::searchable::Direction::Prev,
12205                    ),
12206                    SelectionGoal::None,
12207                )
12208            });
12209        })
12210    }
12211
12212    pub fn move_to_start_of_next_excerpt(
12213        &mut self,
12214        _: &MoveToStartOfNextExcerpt,
12215        window: &mut Window,
12216        cx: &mut Context<Self>,
12217    ) {
12218        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12219            cx.propagate();
12220            return;
12221        }
12222
12223        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12224            s.move_with(|map, selection| {
12225                selection.collapse_to(
12226                    movement::start_of_excerpt(
12227                        map,
12228                        selection.head(),
12229                        workspace::searchable::Direction::Next,
12230                    ),
12231                    SelectionGoal::None,
12232                )
12233            });
12234        })
12235    }
12236
12237    pub fn move_to_end_of_excerpt(
12238        &mut self,
12239        _: &MoveToEndOfExcerpt,
12240        window: &mut Window,
12241        cx: &mut Context<Self>,
12242    ) {
12243        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12244            cx.propagate();
12245            return;
12246        }
12247        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12248        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12249            s.move_with(|map, selection| {
12250                selection.collapse_to(
12251                    movement::end_of_excerpt(
12252                        map,
12253                        selection.head(),
12254                        workspace::searchable::Direction::Next,
12255                    ),
12256                    SelectionGoal::None,
12257                )
12258            });
12259        })
12260    }
12261
12262    pub fn move_to_end_of_previous_excerpt(
12263        &mut self,
12264        _: &MoveToEndOfPreviousExcerpt,
12265        window: &mut Window,
12266        cx: &mut Context<Self>,
12267    ) {
12268        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12269            cx.propagate();
12270            return;
12271        }
12272        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12273        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12274            s.move_with(|map, selection| {
12275                selection.collapse_to(
12276                    movement::end_of_excerpt(
12277                        map,
12278                        selection.head(),
12279                        workspace::searchable::Direction::Prev,
12280                    ),
12281                    SelectionGoal::None,
12282                )
12283            });
12284        })
12285    }
12286
12287    pub fn select_to_start_of_excerpt(
12288        &mut self,
12289        _: &SelectToStartOfExcerpt,
12290        window: &mut Window,
12291        cx: &mut Context<Self>,
12292    ) {
12293        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12294            cx.propagate();
12295            return;
12296        }
12297        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12298        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12299            s.move_heads_with(|map, head, _| {
12300                (
12301                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12302                    SelectionGoal::None,
12303                )
12304            });
12305        })
12306    }
12307
12308    pub fn select_to_start_of_next_excerpt(
12309        &mut self,
12310        _: &SelectToStartOfNextExcerpt,
12311        window: &mut Window,
12312        cx: &mut Context<Self>,
12313    ) {
12314        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12315            cx.propagate();
12316            return;
12317        }
12318        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12319        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12320            s.move_heads_with(|map, head, _| {
12321                (
12322                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12323                    SelectionGoal::None,
12324                )
12325            });
12326        })
12327    }
12328
12329    pub fn select_to_end_of_excerpt(
12330        &mut self,
12331        _: &SelectToEndOfExcerpt,
12332        window: &mut Window,
12333        cx: &mut Context<Self>,
12334    ) {
12335        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12336            cx.propagate();
12337            return;
12338        }
12339        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12340        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12341            s.move_heads_with(|map, head, _| {
12342                (
12343                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12344                    SelectionGoal::None,
12345                )
12346            });
12347        })
12348    }
12349
12350    pub fn select_to_end_of_previous_excerpt(
12351        &mut self,
12352        _: &SelectToEndOfPreviousExcerpt,
12353        window: &mut Window,
12354        cx: &mut Context<Self>,
12355    ) {
12356        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12357            cx.propagate();
12358            return;
12359        }
12360        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12361        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12362            s.move_heads_with(|map, head, _| {
12363                (
12364                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12365                    SelectionGoal::None,
12366                )
12367            });
12368        })
12369    }
12370
12371    pub fn move_to_beginning(
12372        &mut self,
12373        _: &MoveToBeginning,
12374        window: &mut Window,
12375        cx: &mut Context<Self>,
12376    ) {
12377        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12378            cx.propagate();
12379            return;
12380        }
12381        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12382        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12383            s.select_ranges(vec![0..0]);
12384        });
12385    }
12386
12387    pub fn select_to_beginning(
12388        &mut self,
12389        _: &SelectToBeginning,
12390        window: &mut Window,
12391        cx: &mut Context<Self>,
12392    ) {
12393        let mut selection = self.selections.last::<Point>(cx);
12394        selection.set_head(Point::zero(), SelectionGoal::None);
12395        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12396        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12397            s.select(vec![selection]);
12398        });
12399    }
12400
12401    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12402        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12403            cx.propagate();
12404            return;
12405        }
12406        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12407        let cursor = self.buffer.read(cx).read(cx).len();
12408        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12409            s.select_ranges(vec![cursor..cursor])
12410        });
12411    }
12412
12413    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12414        self.nav_history = nav_history;
12415    }
12416
12417    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12418        self.nav_history.as_ref()
12419    }
12420
12421    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12422        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12423    }
12424
12425    fn push_to_nav_history(
12426        &mut self,
12427        cursor_anchor: Anchor,
12428        new_position: Option<Point>,
12429        is_deactivate: bool,
12430        cx: &mut Context<Self>,
12431    ) {
12432        if let Some(nav_history) = self.nav_history.as_mut() {
12433            let buffer = self.buffer.read(cx).read(cx);
12434            let cursor_position = cursor_anchor.to_point(&buffer);
12435            let scroll_state = self.scroll_manager.anchor();
12436            let scroll_top_row = scroll_state.top_row(&buffer);
12437            drop(buffer);
12438
12439            if let Some(new_position) = new_position {
12440                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12441                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12442                    return;
12443                }
12444            }
12445
12446            nav_history.push(
12447                Some(NavigationData {
12448                    cursor_anchor,
12449                    cursor_position,
12450                    scroll_anchor: scroll_state,
12451                    scroll_top_row,
12452                }),
12453                cx,
12454            );
12455            cx.emit(EditorEvent::PushedToNavHistory {
12456                anchor: cursor_anchor,
12457                is_deactivate,
12458            })
12459        }
12460    }
12461
12462    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12463        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12464        let buffer = self.buffer.read(cx).snapshot(cx);
12465        let mut selection = self.selections.first::<usize>(cx);
12466        selection.set_head(buffer.len(), SelectionGoal::None);
12467        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12468            s.select(vec![selection]);
12469        });
12470    }
12471
12472    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12473        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12474        let end = self.buffer.read(cx).read(cx).len();
12475        self.change_selections(None, window, cx, |s| {
12476            s.select_ranges(vec![0..end]);
12477        });
12478    }
12479
12480    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12481        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12482        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12483        let mut selections = self.selections.all::<Point>(cx);
12484        let max_point = display_map.buffer_snapshot.max_point();
12485        for selection in &mut selections {
12486            let rows = selection.spanned_rows(true, &display_map);
12487            selection.start = Point::new(rows.start.0, 0);
12488            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12489            selection.reversed = false;
12490        }
12491        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12492            s.select(selections);
12493        });
12494    }
12495
12496    pub fn split_selection_into_lines(
12497        &mut self,
12498        _: &SplitSelectionIntoLines,
12499        window: &mut Window,
12500        cx: &mut Context<Self>,
12501    ) {
12502        let selections = self
12503            .selections
12504            .all::<Point>(cx)
12505            .into_iter()
12506            .map(|selection| selection.start..selection.end)
12507            .collect::<Vec<_>>();
12508        self.unfold_ranges(&selections, true, true, cx);
12509
12510        let mut new_selection_ranges = Vec::new();
12511        {
12512            let buffer = self.buffer.read(cx).read(cx);
12513            for selection in selections {
12514                for row in selection.start.row..selection.end.row {
12515                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12516                    new_selection_ranges.push(cursor..cursor);
12517                }
12518
12519                let is_multiline_selection = selection.start.row != selection.end.row;
12520                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12521                // so this action feels more ergonomic when paired with other selection operations
12522                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12523                if !should_skip_last {
12524                    new_selection_ranges.push(selection.end..selection.end);
12525                }
12526            }
12527        }
12528        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12529            s.select_ranges(new_selection_ranges);
12530        });
12531    }
12532
12533    pub fn add_selection_above(
12534        &mut self,
12535        _: &AddSelectionAbove,
12536        window: &mut Window,
12537        cx: &mut Context<Self>,
12538    ) {
12539        self.add_selection(true, window, cx);
12540    }
12541
12542    pub fn add_selection_below(
12543        &mut self,
12544        _: &AddSelectionBelow,
12545        window: &mut Window,
12546        cx: &mut Context<Self>,
12547    ) {
12548        self.add_selection(false, window, cx);
12549    }
12550
12551    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12552        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12553
12554        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12555        let mut selections = self.selections.all::<Point>(cx);
12556        let text_layout_details = self.text_layout_details(window);
12557        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12558            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12559            let range = oldest_selection.display_range(&display_map).sorted();
12560
12561            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12562            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12563            let positions = start_x.min(end_x)..start_x.max(end_x);
12564
12565            selections.clear();
12566            let mut stack = Vec::new();
12567            for row in range.start.row().0..=range.end.row().0 {
12568                if let Some(selection) = self.selections.build_columnar_selection(
12569                    &display_map,
12570                    DisplayRow(row),
12571                    &positions,
12572                    oldest_selection.reversed,
12573                    &text_layout_details,
12574                ) {
12575                    stack.push(selection.id);
12576                    selections.push(selection);
12577                }
12578            }
12579
12580            if above {
12581                stack.reverse();
12582            }
12583
12584            AddSelectionsState { above, stack }
12585        });
12586
12587        let last_added_selection = *state.stack.last().unwrap();
12588        let mut new_selections = Vec::new();
12589        if above == state.above {
12590            let end_row = if above {
12591                DisplayRow(0)
12592            } else {
12593                display_map.max_point().row()
12594            };
12595
12596            'outer: for selection in selections {
12597                if selection.id == last_added_selection {
12598                    let range = selection.display_range(&display_map).sorted();
12599                    debug_assert_eq!(range.start.row(), range.end.row());
12600                    let mut row = range.start.row();
12601                    let positions =
12602                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12603                            px(start)..px(end)
12604                        } else {
12605                            let start_x =
12606                                display_map.x_for_display_point(range.start, &text_layout_details);
12607                            let end_x =
12608                                display_map.x_for_display_point(range.end, &text_layout_details);
12609                            start_x.min(end_x)..start_x.max(end_x)
12610                        };
12611
12612                    while row != end_row {
12613                        if above {
12614                            row.0 -= 1;
12615                        } else {
12616                            row.0 += 1;
12617                        }
12618
12619                        if let Some(new_selection) = self.selections.build_columnar_selection(
12620                            &display_map,
12621                            row,
12622                            &positions,
12623                            selection.reversed,
12624                            &text_layout_details,
12625                        ) {
12626                            state.stack.push(new_selection.id);
12627                            if above {
12628                                new_selections.push(new_selection);
12629                                new_selections.push(selection);
12630                            } else {
12631                                new_selections.push(selection);
12632                                new_selections.push(new_selection);
12633                            }
12634
12635                            continue 'outer;
12636                        }
12637                    }
12638                }
12639
12640                new_selections.push(selection);
12641            }
12642        } else {
12643            new_selections = selections;
12644            new_selections.retain(|s| s.id != last_added_selection);
12645            state.stack.pop();
12646        }
12647
12648        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12649            s.select(new_selections);
12650        });
12651        if state.stack.len() > 1 {
12652            self.add_selections_state = Some(state);
12653        }
12654    }
12655
12656    fn select_match_ranges(
12657        &mut self,
12658        range: Range<usize>,
12659        reversed: bool,
12660        replace_newest: bool,
12661        auto_scroll: Option<Autoscroll>,
12662        window: &mut Window,
12663        cx: &mut Context<Editor>,
12664    ) {
12665        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12666        self.change_selections(auto_scroll, window, cx, |s| {
12667            if replace_newest {
12668                s.delete(s.newest_anchor().id);
12669            }
12670            if reversed {
12671                s.insert_range(range.end..range.start);
12672            } else {
12673                s.insert_range(range);
12674            }
12675        });
12676    }
12677
12678    pub fn select_next_match_internal(
12679        &mut self,
12680        display_map: &DisplaySnapshot,
12681        replace_newest: bool,
12682        autoscroll: Option<Autoscroll>,
12683        window: &mut Window,
12684        cx: &mut Context<Self>,
12685    ) -> Result<()> {
12686        let buffer = &display_map.buffer_snapshot;
12687        let mut selections = self.selections.all::<usize>(cx);
12688        if let Some(mut select_next_state) = self.select_next_state.take() {
12689            let query = &select_next_state.query;
12690            if !select_next_state.done {
12691                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12692                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12693                let mut next_selected_range = None;
12694
12695                let bytes_after_last_selection =
12696                    buffer.bytes_in_range(last_selection.end..buffer.len());
12697                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12698                let query_matches = query
12699                    .stream_find_iter(bytes_after_last_selection)
12700                    .map(|result| (last_selection.end, result))
12701                    .chain(
12702                        query
12703                            .stream_find_iter(bytes_before_first_selection)
12704                            .map(|result| (0, result)),
12705                    );
12706
12707                for (start_offset, query_match) in query_matches {
12708                    let query_match = query_match.unwrap(); // can only fail due to I/O
12709                    let offset_range =
12710                        start_offset + query_match.start()..start_offset + query_match.end();
12711                    let display_range = offset_range.start.to_display_point(display_map)
12712                        ..offset_range.end.to_display_point(display_map);
12713
12714                    if !select_next_state.wordwise
12715                        || (!movement::is_inside_word(display_map, display_range.start)
12716                            && !movement::is_inside_word(display_map, display_range.end))
12717                    {
12718                        // TODO: This is n^2, because we might check all the selections
12719                        if !selections
12720                            .iter()
12721                            .any(|selection| selection.range().overlaps(&offset_range))
12722                        {
12723                            next_selected_range = Some(offset_range);
12724                            break;
12725                        }
12726                    }
12727                }
12728
12729                if let Some(next_selected_range) = next_selected_range {
12730                    self.select_match_ranges(
12731                        next_selected_range,
12732                        last_selection.reversed,
12733                        replace_newest,
12734                        autoscroll,
12735                        window,
12736                        cx,
12737                    );
12738                } else {
12739                    select_next_state.done = true;
12740                }
12741            }
12742
12743            self.select_next_state = Some(select_next_state);
12744        } else {
12745            let mut only_carets = true;
12746            let mut same_text_selected = true;
12747            let mut selected_text = None;
12748
12749            let mut selections_iter = selections.iter().peekable();
12750            while let Some(selection) = selections_iter.next() {
12751                if selection.start != selection.end {
12752                    only_carets = false;
12753                }
12754
12755                if same_text_selected {
12756                    if selected_text.is_none() {
12757                        selected_text =
12758                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12759                    }
12760
12761                    if let Some(next_selection) = selections_iter.peek() {
12762                        if next_selection.range().len() == selection.range().len() {
12763                            let next_selected_text = buffer
12764                                .text_for_range(next_selection.range())
12765                                .collect::<String>();
12766                            if Some(next_selected_text) != selected_text {
12767                                same_text_selected = false;
12768                                selected_text = None;
12769                            }
12770                        } else {
12771                            same_text_selected = false;
12772                            selected_text = None;
12773                        }
12774                    }
12775                }
12776            }
12777
12778            if only_carets {
12779                for selection in &mut selections {
12780                    let word_range = movement::surrounding_word(
12781                        display_map,
12782                        selection.start.to_display_point(display_map),
12783                    );
12784                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12785                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12786                    selection.goal = SelectionGoal::None;
12787                    selection.reversed = false;
12788                    self.select_match_ranges(
12789                        selection.start..selection.end,
12790                        selection.reversed,
12791                        replace_newest,
12792                        autoscroll,
12793                        window,
12794                        cx,
12795                    );
12796                }
12797
12798                if selections.len() == 1 {
12799                    let selection = selections
12800                        .last()
12801                        .expect("ensured that there's only one selection");
12802                    let query = buffer
12803                        .text_for_range(selection.start..selection.end)
12804                        .collect::<String>();
12805                    let is_empty = query.is_empty();
12806                    let select_state = SelectNextState {
12807                        query: AhoCorasick::new(&[query])?,
12808                        wordwise: true,
12809                        done: is_empty,
12810                    };
12811                    self.select_next_state = Some(select_state);
12812                } else {
12813                    self.select_next_state = None;
12814                }
12815            } else if let Some(selected_text) = selected_text {
12816                self.select_next_state = Some(SelectNextState {
12817                    query: AhoCorasick::new(&[selected_text])?,
12818                    wordwise: false,
12819                    done: false,
12820                });
12821                self.select_next_match_internal(
12822                    display_map,
12823                    replace_newest,
12824                    autoscroll,
12825                    window,
12826                    cx,
12827                )?;
12828            }
12829        }
12830        Ok(())
12831    }
12832
12833    pub fn select_all_matches(
12834        &mut self,
12835        _action: &SelectAllMatches,
12836        window: &mut Window,
12837        cx: &mut Context<Self>,
12838    ) -> Result<()> {
12839        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12840
12841        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12842
12843        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12844        let Some(select_next_state) = self.select_next_state.as_mut() else {
12845            return Ok(());
12846        };
12847        if select_next_state.done {
12848            return Ok(());
12849        }
12850
12851        let mut new_selections = Vec::new();
12852
12853        let reversed = self.selections.oldest::<usize>(cx).reversed;
12854        let buffer = &display_map.buffer_snapshot;
12855        let query_matches = select_next_state
12856            .query
12857            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12858
12859        for query_match in query_matches.into_iter() {
12860            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12861            let offset_range = if reversed {
12862                query_match.end()..query_match.start()
12863            } else {
12864                query_match.start()..query_match.end()
12865            };
12866            let display_range = offset_range.start.to_display_point(&display_map)
12867                ..offset_range.end.to_display_point(&display_map);
12868
12869            if !select_next_state.wordwise
12870                || (!movement::is_inside_word(&display_map, display_range.start)
12871                    && !movement::is_inside_word(&display_map, display_range.end))
12872            {
12873                new_selections.push(offset_range.start..offset_range.end);
12874            }
12875        }
12876
12877        select_next_state.done = true;
12878        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12879        self.change_selections(None, window, cx, |selections| {
12880            selections.select_ranges(new_selections)
12881        });
12882
12883        Ok(())
12884    }
12885
12886    pub fn select_next(
12887        &mut self,
12888        action: &SelectNext,
12889        window: &mut Window,
12890        cx: &mut Context<Self>,
12891    ) -> Result<()> {
12892        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12893        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12894        self.select_next_match_internal(
12895            &display_map,
12896            action.replace_newest,
12897            Some(Autoscroll::newest()),
12898            window,
12899            cx,
12900        )?;
12901        Ok(())
12902    }
12903
12904    pub fn select_previous(
12905        &mut self,
12906        action: &SelectPrevious,
12907        window: &mut Window,
12908        cx: &mut Context<Self>,
12909    ) -> Result<()> {
12910        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12911        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12912        let buffer = &display_map.buffer_snapshot;
12913        let mut selections = self.selections.all::<usize>(cx);
12914        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12915            let query = &select_prev_state.query;
12916            if !select_prev_state.done {
12917                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12918                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12919                let mut next_selected_range = None;
12920                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12921                let bytes_before_last_selection =
12922                    buffer.reversed_bytes_in_range(0..last_selection.start);
12923                let bytes_after_first_selection =
12924                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12925                let query_matches = query
12926                    .stream_find_iter(bytes_before_last_selection)
12927                    .map(|result| (last_selection.start, result))
12928                    .chain(
12929                        query
12930                            .stream_find_iter(bytes_after_first_selection)
12931                            .map(|result| (buffer.len(), result)),
12932                    );
12933                for (end_offset, query_match) in query_matches {
12934                    let query_match = query_match.unwrap(); // can only fail due to I/O
12935                    let offset_range =
12936                        end_offset - query_match.end()..end_offset - query_match.start();
12937                    let display_range = offset_range.start.to_display_point(&display_map)
12938                        ..offset_range.end.to_display_point(&display_map);
12939
12940                    if !select_prev_state.wordwise
12941                        || (!movement::is_inside_word(&display_map, display_range.start)
12942                            && !movement::is_inside_word(&display_map, display_range.end))
12943                    {
12944                        next_selected_range = Some(offset_range);
12945                        break;
12946                    }
12947                }
12948
12949                if let Some(next_selected_range) = next_selected_range {
12950                    self.select_match_ranges(
12951                        next_selected_range,
12952                        last_selection.reversed,
12953                        action.replace_newest,
12954                        Some(Autoscroll::newest()),
12955                        window,
12956                        cx,
12957                    );
12958                } else {
12959                    select_prev_state.done = true;
12960                }
12961            }
12962
12963            self.select_prev_state = Some(select_prev_state);
12964        } else {
12965            let mut only_carets = true;
12966            let mut same_text_selected = true;
12967            let mut selected_text = None;
12968
12969            let mut selections_iter = selections.iter().peekable();
12970            while let Some(selection) = selections_iter.next() {
12971                if selection.start != selection.end {
12972                    only_carets = false;
12973                }
12974
12975                if same_text_selected {
12976                    if selected_text.is_none() {
12977                        selected_text =
12978                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12979                    }
12980
12981                    if let Some(next_selection) = selections_iter.peek() {
12982                        if next_selection.range().len() == selection.range().len() {
12983                            let next_selected_text = buffer
12984                                .text_for_range(next_selection.range())
12985                                .collect::<String>();
12986                            if Some(next_selected_text) != selected_text {
12987                                same_text_selected = false;
12988                                selected_text = None;
12989                            }
12990                        } else {
12991                            same_text_selected = false;
12992                            selected_text = None;
12993                        }
12994                    }
12995                }
12996            }
12997
12998            if only_carets {
12999                for selection in &mut selections {
13000                    let word_range = movement::surrounding_word(
13001                        &display_map,
13002                        selection.start.to_display_point(&display_map),
13003                    );
13004                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13005                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13006                    selection.goal = SelectionGoal::None;
13007                    selection.reversed = false;
13008                    self.select_match_ranges(
13009                        selection.start..selection.end,
13010                        selection.reversed,
13011                        action.replace_newest,
13012                        Some(Autoscroll::newest()),
13013                        window,
13014                        cx,
13015                    );
13016                }
13017                if selections.len() == 1 {
13018                    let selection = selections
13019                        .last()
13020                        .expect("ensured that there's only one selection");
13021                    let query = buffer
13022                        .text_for_range(selection.start..selection.end)
13023                        .collect::<String>();
13024                    let is_empty = query.is_empty();
13025                    let select_state = SelectNextState {
13026                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13027                        wordwise: true,
13028                        done: is_empty,
13029                    };
13030                    self.select_prev_state = Some(select_state);
13031                } else {
13032                    self.select_prev_state = None;
13033                }
13034            } else if let Some(selected_text) = selected_text {
13035                self.select_prev_state = Some(SelectNextState {
13036                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13037                    wordwise: false,
13038                    done: false,
13039                });
13040                self.select_previous(action, window, cx)?;
13041            }
13042        }
13043        Ok(())
13044    }
13045
13046    pub fn find_next_match(
13047        &mut self,
13048        _: &FindNextMatch,
13049        window: &mut Window,
13050        cx: &mut Context<Self>,
13051    ) -> Result<()> {
13052        let selections = self.selections.disjoint_anchors();
13053        match selections.first() {
13054            Some(first) if selections.len() >= 2 => {
13055                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13056                    s.select_ranges([first.range()]);
13057                });
13058            }
13059            _ => self.select_next(
13060                &SelectNext {
13061                    replace_newest: true,
13062                },
13063                window,
13064                cx,
13065            )?,
13066        }
13067        Ok(())
13068    }
13069
13070    pub fn find_previous_match(
13071        &mut self,
13072        _: &FindPreviousMatch,
13073        window: &mut Window,
13074        cx: &mut Context<Self>,
13075    ) -> Result<()> {
13076        let selections = self.selections.disjoint_anchors();
13077        match selections.last() {
13078            Some(last) if selections.len() >= 2 => {
13079                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13080                    s.select_ranges([last.range()]);
13081                });
13082            }
13083            _ => self.select_previous(
13084                &SelectPrevious {
13085                    replace_newest: true,
13086                },
13087                window,
13088                cx,
13089            )?,
13090        }
13091        Ok(())
13092    }
13093
13094    pub fn toggle_comments(
13095        &mut self,
13096        action: &ToggleComments,
13097        window: &mut Window,
13098        cx: &mut Context<Self>,
13099    ) {
13100        if self.read_only(cx) {
13101            return;
13102        }
13103        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
13104        let text_layout_details = &self.text_layout_details(window);
13105        self.transact(window, cx, |this, window, cx| {
13106            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13107            let mut edits = Vec::new();
13108            let mut selection_edit_ranges = Vec::new();
13109            let mut last_toggled_row = None;
13110            let snapshot = this.buffer.read(cx).read(cx);
13111            let empty_str: Arc<str> = Arc::default();
13112            let mut suffixes_inserted = Vec::new();
13113            let ignore_indent = action.ignore_indent;
13114
13115            fn comment_prefix_range(
13116                snapshot: &MultiBufferSnapshot,
13117                row: MultiBufferRow,
13118                comment_prefix: &str,
13119                comment_prefix_whitespace: &str,
13120                ignore_indent: bool,
13121            ) -> Range<Point> {
13122                let indent_size = if ignore_indent {
13123                    0
13124                } else {
13125                    snapshot.indent_size_for_line(row).len
13126                };
13127
13128                let start = Point::new(row.0, indent_size);
13129
13130                let mut line_bytes = snapshot
13131                    .bytes_in_range(start..snapshot.max_point())
13132                    .flatten()
13133                    .copied();
13134
13135                // If this line currently begins with the line comment prefix, then record
13136                // the range containing the prefix.
13137                if line_bytes
13138                    .by_ref()
13139                    .take(comment_prefix.len())
13140                    .eq(comment_prefix.bytes())
13141                {
13142                    // Include any whitespace that matches the comment prefix.
13143                    let matching_whitespace_len = line_bytes
13144                        .zip(comment_prefix_whitespace.bytes())
13145                        .take_while(|(a, b)| a == b)
13146                        .count() as u32;
13147                    let end = Point::new(
13148                        start.row,
13149                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13150                    );
13151                    start..end
13152                } else {
13153                    start..start
13154                }
13155            }
13156
13157            fn comment_suffix_range(
13158                snapshot: &MultiBufferSnapshot,
13159                row: MultiBufferRow,
13160                comment_suffix: &str,
13161                comment_suffix_has_leading_space: bool,
13162            ) -> Range<Point> {
13163                let end = Point::new(row.0, snapshot.line_len(row));
13164                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13165
13166                let mut line_end_bytes = snapshot
13167                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13168                    .flatten()
13169                    .copied();
13170
13171                let leading_space_len = if suffix_start_column > 0
13172                    && line_end_bytes.next() == Some(b' ')
13173                    && comment_suffix_has_leading_space
13174                {
13175                    1
13176                } else {
13177                    0
13178                };
13179
13180                // If this line currently begins with the line comment prefix, then record
13181                // the range containing the prefix.
13182                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13183                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13184                    start..end
13185                } else {
13186                    end..end
13187                }
13188            }
13189
13190            // TODO: Handle selections that cross excerpts
13191            for selection in &mut selections {
13192                let start_column = snapshot
13193                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13194                    .len;
13195                let language = if let Some(language) =
13196                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13197                {
13198                    language
13199                } else {
13200                    continue;
13201                };
13202
13203                selection_edit_ranges.clear();
13204
13205                // If multiple selections contain a given row, avoid processing that
13206                // row more than once.
13207                let mut start_row = MultiBufferRow(selection.start.row);
13208                if last_toggled_row == Some(start_row) {
13209                    start_row = start_row.next_row();
13210                }
13211                let end_row =
13212                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13213                        MultiBufferRow(selection.end.row - 1)
13214                    } else {
13215                        MultiBufferRow(selection.end.row)
13216                    };
13217                last_toggled_row = Some(end_row);
13218
13219                if start_row > end_row {
13220                    continue;
13221                }
13222
13223                // If the language has line comments, toggle those.
13224                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13225
13226                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13227                if ignore_indent {
13228                    full_comment_prefixes = full_comment_prefixes
13229                        .into_iter()
13230                        .map(|s| Arc::from(s.trim_end()))
13231                        .collect();
13232                }
13233
13234                if !full_comment_prefixes.is_empty() {
13235                    let first_prefix = full_comment_prefixes
13236                        .first()
13237                        .expect("prefixes is non-empty");
13238                    let prefix_trimmed_lengths = full_comment_prefixes
13239                        .iter()
13240                        .map(|p| p.trim_end_matches(' ').len())
13241                        .collect::<SmallVec<[usize; 4]>>();
13242
13243                    let mut all_selection_lines_are_comments = true;
13244
13245                    for row in start_row.0..=end_row.0 {
13246                        let row = MultiBufferRow(row);
13247                        if start_row < end_row && snapshot.is_line_blank(row) {
13248                            continue;
13249                        }
13250
13251                        let prefix_range = full_comment_prefixes
13252                            .iter()
13253                            .zip(prefix_trimmed_lengths.iter().copied())
13254                            .map(|(prefix, trimmed_prefix_len)| {
13255                                comment_prefix_range(
13256                                    snapshot.deref(),
13257                                    row,
13258                                    &prefix[..trimmed_prefix_len],
13259                                    &prefix[trimmed_prefix_len..],
13260                                    ignore_indent,
13261                                )
13262                            })
13263                            .max_by_key(|range| range.end.column - range.start.column)
13264                            .expect("prefixes is non-empty");
13265
13266                        if prefix_range.is_empty() {
13267                            all_selection_lines_are_comments = false;
13268                        }
13269
13270                        selection_edit_ranges.push(prefix_range);
13271                    }
13272
13273                    if all_selection_lines_are_comments {
13274                        edits.extend(
13275                            selection_edit_ranges
13276                                .iter()
13277                                .cloned()
13278                                .map(|range| (range, empty_str.clone())),
13279                        );
13280                    } else {
13281                        let min_column = selection_edit_ranges
13282                            .iter()
13283                            .map(|range| range.start.column)
13284                            .min()
13285                            .unwrap_or(0);
13286                        edits.extend(selection_edit_ranges.iter().map(|range| {
13287                            let position = Point::new(range.start.row, min_column);
13288                            (position..position, first_prefix.clone())
13289                        }));
13290                    }
13291                } else if let Some((full_comment_prefix, comment_suffix)) =
13292                    language.block_comment_delimiters()
13293                {
13294                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13295                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13296                    let prefix_range = comment_prefix_range(
13297                        snapshot.deref(),
13298                        start_row,
13299                        comment_prefix,
13300                        comment_prefix_whitespace,
13301                        ignore_indent,
13302                    );
13303                    let suffix_range = comment_suffix_range(
13304                        snapshot.deref(),
13305                        end_row,
13306                        comment_suffix.trim_start_matches(' '),
13307                        comment_suffix.starts_with(' '),
13308                    );
13309
13310                    if prefix_range.is_empty() || suffix_range.is_empty() {
13311                        edits.push((
13312                            prefix_range.start..prefix_range.start,
13313                            full_comment_prefix.clone(),
13314                        ));
13315                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13316                        suffixes_inserted.push((end_row, comment_suffix.len()));
13317                    } else {
13318                        edits.push((prefix_range, empty_str.clone()));
13319                        edits.push((suffix_range, empty_str.clone()));
13320                    }
13321                } else {
13322                    continue;
13323                }
13324            }
13325
13326            drop(snapshot);
13327            this.buffer.update(cx, |buffer, cx| {
13328                buffer.edit(edits, None, cx);
13329            });
13330
13331            // Adjust selections so that they end before any comment suffixes that
13332            // were inserted.
13333            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13334            let mut selections = this.selections.all::<Point>(cx);
13335            let snapshot = this.buffer.read(cx).read(cx);
13336            for selection in &mut selections {
13337                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13338                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13339                        Ordering::Less => {
13340                            suffixes_inserted.next();
13341                            continue;
13342                        }
13343                        Ordering::Greater => break,
13344                        Ordering::Equal => {
13345                            if selection.end.column == snapshot.line_len(row) {
13346                                if selection.is_empty() {
13347                                    selection.start.column -= suffix_len as u32;
13348                                }
13349                                selection.end.column -= suffix_len as u32;
13350                            }
13351                            break;
13352                        }
13353                    }
13354                }
13355            }
13356
13357            drop(snapshot);
13358            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13359                s.select(selections)
13360            });
13361
13362            let selections = this.selections.all::<Point>(cx);
13363            let selections_on_single_row = selections.windows(2).all(|selections| {
13364                selections[0].start.row == selections[1].start.row
13365                    && selections[0].end.row == selections[1].end.row
13366                    && selections[0].start.row == selections[0].end.row
13367            });
13368            let selections_selecting = selections
13369                .iter()
13370                .any(|selection| selection.start != selection.end);
13371            let advance_downwards = action.advance_downwards
13372                && selections_on_single_row
13373                && !selections_selecting
13374                && !matches!(this.mode, EditorMode::SingleLine { .. });
13375
13376            if advance_downwards {
13377                let snapshot = this.buffer.read(cx).snapshot(cx);
13378
13379                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13380                    s.move_cursors_with(|display_snapshot, display_point, _| {
13381                        let mut point = display_point.to_point(display_snapshot);
13382                        point.row += 1;
13383                        point = snapshot.clip_point(point, Bias::Left);
13384                        let display_point = point.to_display_point(display_snapshot);
13385                        let goal = SelectionGoal::HorizontalPosition(
13386                            display_snapshot
13387                                .x_for_display_point(display_point, text_layout_details)
13388                                .into(),
13389                        );
13390                        (display_point, goal)
13391                    })
13392                });
13393            }
13394        });
13395    }
13396
13397    pub fn select_enclosing_symbol(
13398        &mut self,
13399        _: &SelectEnclosingSymbol,
13400        window: &mut Window,
13401        cx: &mut Context<Self>,
13402    ) {
13403        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13404
13405        let buffer = self.buffer.read(cx).snapshot(cx);
13406        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13407
13408        fn update_selection(
13409            selection: &Selection<usize>,
13410            buffer_snap: &MultiBufferSnapshot,
13411        ) -> Option<Selection<usize>> {
13412            let cursor = selection.head();
13413            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13414            for symbol in symbols.iter().rev() {
13415                let start = symbol.range.start.to_offset(buffer_snap);
13416                let end = symbol.range.end.to_offset(buffer_snap);
13417                let new_range = start..end;
13418                if start < selection.start || end > selection.end {
13419                    return Some(Selection {
13420                        id: selection.id,
13421                        start: new_range.start,
13422                        end: new_range.end,
13423                        goal: SelectionGoal::None,
13424                        reversed: selection.reversed,
13425                    });
13426                }
13427            }
13428            None
13429        }
13430
13431        let mut selected_larger_symbol = false;
13432        let new_selections = old_selections
13433            .iter()
13434            .map(|selection| match update_selection(selection, &buffer) {
13435                Some(new_selection) => {
13436                    if new_selection.range() != selection.range() {
13437                        selected_larger_symbol = true;
13438                    }
13439                    new_selection
13440                }
13441                None => selection.clone(),
13442            })
13443            .collect::<Vec<_>>();
13444
13445        if selected_larger_symbol {
13446            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13447                s.select(new_selections);
13448            });
13449        }
13450    }
13451
13452    pub fn select_larger_syntax_node(
13453        &mut self,
13454        _: &SelectLargerSyntaxNode,
13455        window: &mut Window,
13456        cx: &mut Context<Self>,
13457    ) {
13458        let Some(visible_row_count) = self.visible_row_count() else {
13459            return;
13460        };
13461        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13462        if old_selections.is_empty() {
13463            return;
13464        }
13465
13466        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13467
13468        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13469        let buffer = self.buffer.read(cx).snapshot(cx);
13470
13471        let mut selected_larger_node = false;
13472        let mut new_selections = old_selections
13473            .iter()
13474            .map(|selection| {
13475                let old_range = selection.start..selection.end;
13476
13477                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13478                    // manually select word at selection
13479                    if ["string_content", "inline"].contains(&node.kind()) {
13480                        let word_range = {
13481                            let display_point = buffer
13482                                .offset_to_point(old_range.start)
13483                                .to_display_point(&display_map);
13484                            let Range { start, end } =
13485                                movement::surrounding_word(&display_map, display_point);
13486                            start.to_point(&display_map).to_offset(&buffer)
13487                                ..end.to_point(&display_map).to_offset(&buffer)
13488                        };
13489                        // ignore if word is already selected
13490                        if !word_range.is_empty() && old_range != word_range {
13491                            let last_word_range = {
13492                                let display_point = buffer
13493                                    .offset_to_point(old_range.end)
13494                                    .to_display_point(&display_map);
13495                                let Range { start, end } =
13496                                    movement::surrounding_word(&display_map, display_point);
13497                                start.to_point(&display_map).to_offset(&buffer)
13498                                    ..end.to_point(&display_map).to_offset(&buffer)
13499                            };
13500                            // only select word if start and end point belongs to same word
13501                            if word_range == last_word_range {
13502                                selected_larger_node = true;
13503                                return Selection {
13504                                    id: selection.id,
13505                                    start: word_range.start,
13506                                    end: word_range.end,
13507                                    goal: SelectionGoal::None,
13508                                    reversed: selection.reversed,
13509                                };
13510                            }
13511                        }
13512                    }
13513                }
13514
13515                let mut new_range = old_range.clone();
13516                while let Some((_node, containing_range)) =
13517                    buffer.syntax_ancestor(new_range.clone())
13518                {
13519                    new_range = match containing_range {
13520                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13521                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13522                    };
13523                    if !display_map.intersects_fold(new_range.start)
13524                        && !display_map.intersects_fold(new_range.end)
13525                    {
13526                        break;
13527                    }
13528                }
13529
13530                selected_larger_node |= new_range != old_range;
13531                Selection {
13532                    id: selection.id,
13533                    start: new_range.start,
13534                    end: new_range.end,
13535                    goal: SelectionGoal::None,
13536                    reversed: selection.reversed,
13537                }
13538            })
13539            .collect::<Vec<_>>();
13540
13541        if !selected_larger_node {
13542            return; // don't put this call in the history
13543        }
13544
13545        // scroll based on transformation done to the last selection created by the user
13546        let (last_old, last_new) = old_selections
13547            .last()
13548            .zip(new_selections.last().cloned())
13549            .expect("old_selections isn't empty");
13550
13551        // revert selection
13552        let is_selection_reversed = {
13553            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13554            new_selections.last_mut().expect("checked above").reversed =
13555                should_newest_selection_be_reversed;
13556            should_newest_selection_be_reversed
13557        };
13558
13559        if selected_larger_node {
13560            self.select_syntax_node_history.disable_clearing = true;
13561            self.change_selections(None, window, cx, |s| {
13562                s.select(new_selections.clone());
13563            });
13564            self.select_syntax_node_history.disable_clearing = false;
13565        }
13566
13567        let start_row = last_new.start.to_display_point(&display_map).row().0;
13568        let end_row = last_new.end.to_display_point(&display_map).row().0;
13569        let selection_height = end_row - start_row + 1;
13570        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13571
13572        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13573        let scroll_behavior = if fits_on_the_screen {
13574            self.request_autoscroll(Autoscroll::fit(), cx);
13575            SelectSyntaxNodeScrollBehavior::FitSelection
13576        } else if is_selection_reversed {
13577            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13578            SelectSyntaxNodeScrollBehavior::CursorTop
13579        } else {
13580            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13581            SelectSyntaxNodeScrollBehavior::CursorBottom
13582        };
13583
13584        self.select_syntax_node_history.push((
13585            old_selections,
13586            scroll_behavior,
13587            is_selection_reversed,
13588        ));
13589    }
13590
13591    pub fn select_smaller_syntax_node(
13592        &mut self,
13593        _: &SelectSmallerSyntaxNode,
13594        window: &mut Window,
13595        cx: &mut Context<Self>,
13596    ) {
13597        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13598
13599        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13600            self.select_syntax_node_history.pop()
13601        {
13602            if let Some(selection) = selections.last_mut() {
13603                selection.reversed = is_selection_reversed;
13604            }
13605
13606            self.select_syntax_node_history.disable_clearing = true;
13607            self.change_selections(None, window, cx, |s| {
13608                s.select(selections.to_vec());
13609            });
13610            self.select_syntax_node_history.disable_clearing = false;
13611
13612            match scroll_behavior {
13613                SelectSyntaxNodeScrollBehavior::CursorTop => {
13614                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13615                }
13616                SelectSyntaxNodeScrollBehavior::FitSelection => {
13617                    self.request_autoscroll(Autoscroll::fit(), cx);
13618                }
13619                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13620                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13621                }
13622            }
13623        }
13624    }
13625
13626    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13627        if !EditorSettings::get_global(cx).gutter.runnables {
13628            self.clear_tasks();
13629            return Task::ready(());
13630        }
13631        let project = self.project.as_ref().map(Entity::downgrade);
13632        let task_sources = self.lsp_task_sources(cx);
13633        let multi_buffer = self.buffer.downgrade();
13634        cx.spawn_in(window, async move |editor, cx| {
13635            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13636            let Some(project) = project.and_then(|p| p.upgrade()) else {
13637                return;
13638            };
13639            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13640                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13641            }) else {
13642                return;
13643            };
13644
13645            let hide_runnables = project
13646                .update(cx, |project, cx| {
13647                    // Do not display any test indicators in non-dev server remote projects.
13648                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13649                })
13650                .unwrap_or(true);
13651            if hide_runnables {
13652                return;
13653            }
13654            let new_rows =
13655                cx.background_spawn({
13656                    let snapshot = display_snapshot.clone();
13657                    async move {
13658                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13659                    }
13660                })
13661                    .await;
13662            let Ok(lsp_tasks) =
13663                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13664            else {
13665                return;
13666            };
13667            let lsp_tasks = lsp_tasks.await;
13668
13669            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13670                lsp_tasks
13671                    .into_iter()
13672                    .flat_map(|(kind, tasks)| {
13673                        tasks.into_iter().filter_map(move |(location, task)| {
13674                            Some((kind.clone(), location?, task))
13675                        })
13676                    })
13677                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13678                        let buffer = location.target.buffer;
13679                        let buffer_snapshot = buffer.read(cx).snapshot();
13680                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13681                            |(excerpt_id, snapshot, _)| {
13682                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13683                                    display_snapshot
13684                                        .buffer_snapshot
13685                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13686                                } else {
13687                                    None
13688                                }
13689                            },
13690                        );
13691                        if let Some(offset) = offset {
13692                            let task_buffer_range =
13693                                location.target.range.to_point(&buffer_snapshot);
13694                            let context_buffer_range =
13695                                task_buffer_range.to_offset(&buffer_snapshot);
13696                            let context_range = BufferOffset(context_buffer_range.start)
13697                                ..BufferOffset(context_buffer_range.end);
13698
13699                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13700                                .or_insert_with(|| RunnableTasks {
13701                                    templates: Vec::new(),
13702                                    offset,
13703                                    column: task_buffer_range.start.column,
13704                                    extra_variables: HashMap::default(),
13705                                    context_range,
13706                                })
13707                                .templates
13708                                .push((kind, task.original_task().clone()));
13709                        }
13710
13711                        acc
13712                    })
13713            }) else {
13714                return;
13715            };
13716
13717            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
13718                buffer.language_settings(cx).tasks.prefer_lsp
13719            }) else {
13720                return;
13721            };
13722
13723            let rows = Self::runnable_rows(
13724                project,
13725                display_snapshot,
13726                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
13727                new_rows,
13728                cx.clone(),
13729            );
13730            editor
13731                .update(cx, |editor, _| {
13732                    editor.clear_tasks();
13733                    for (key, mut value) in rows {
13734                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13735                            value.templates.extend(lsp_tasks.templates);
13736                        }
13737
13738                        editor.insert_tasks(key, value);
13739                    }
13740                    for (key, value) in lsp_tasks_by_rows {
13741                        editor.insert_tasks(key, value);
13742                    }
13743                })
13744                .ok();
13745        })
13746    }
13747    fn fetch_runnable_ranges(
13748        snapshot: &DisplaySnapshot,
13749        range: Range<Anchor>,
13750    ) -> Vec<language::RunnableRange> {
13751        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13752    }
13753
13754    fn runnable_rows(
13755        project: Entity<Project>,
13756        snapshot: DisplaySnapshot,
13757        prefer_lsp: bool,
13758        runnable_ranges: Vec<RunnableRange>,
13759        mut cx: AsyncWindowContext,
13760    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13761        runnable_ranges
13762            .into_iter()
13763            .filter_map(|mut runnable| {
13764                let mut tasks = cx
13765                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13766                    .ok()?;
13767                if prefer_lsp {
13768                    tasks.retain(|(task_kind, _)| {
13769                        !matches!(task_kind, TaskSourceKind::Language { .. })
13770                    });
13771                }
13772                if tasks.is_empty() {
13773                    return None;
13774                }
13775
13776                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13777
13778                let row = snapshot
13779                    .buffer_snapshot
13780                    .buffer_line_for_row(MultiBufferRow(point.row))?
13781                    .1
13782                    .start
13783                    .row;
13784
13785                let context_range =
13786                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13787                Some((
13788                    (runnable.buffer_id, row),
13789                    RunnableTasks {
13790                        templates: tasks,
13791                        offset: snapshot
13792                            .buffer_snapshot
13793                            .anchor_before(runnable.run_range.start),
13794                        context_range,
13795                        column: point.column,
13796                        extra_variables: runnable.extra_captures,
13797                    },
13798                ))
13799            })
13800            .collect()
13801    }
13802
13803    fn templates_with_tags(
13804        project: &Entity<Project>,
13805        runnable: &mut Runnable,
13806        cx: &mut App,
13807    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13808        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13809            let (worktree_id, file) = project
13810                .buffer_for_id(runnable.buffer, cx)
13811                .and_then(|buffer| buffer.read(cx).file())
13812                .map(|file| (file.worktree_id(cx), file.clone()))
13813                .unzip();
13814
13815            (
13816                project.task_store().read(cx).task_inventory().cloned(),
13817                worktree_id,
13818                file,
13819            )
13820        });
13821
13822        let mut templates_with_tags = mem::take(&mut runnable.tags)
13823            .into_iter()
13824            .flat_map(|RunnableTag(tag)| {
13825                inventory
13826                    .as_ref()
13827                    .into_iter()
13828                    .flat_map(|inventory| {
13829                        inventory.read(cx).list_tasks(
13830                            file.clone(),
13831                            Some(runnable.language.clone()),
13832                            worktree_id,
13833                            cx,
13834                        )
13835                    })
13836                    .filter(move |(_, template)| {
13837                        template.tags.iter().any(|source_tag| source_tag == &tag)
13838                    })
13839            })
13840            .sorted_by_key(|(kind, _)| kind.to_owned())
13841            .collect::<Vec<_>>();
13842        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13843            // Strongest source wins; if we have worktree tag binding, prefer that to
13844            // global and language bindings;
13845            // if we have a global binding, prefer that to language binding.
13846            let first_mismatch = templates_with_tags
13847                .iter()
13848                .position(|(tag_source, _)| tag_source != leading_tag_source);
13849            if let Some(index) = first_mismatch {
13850                templates_with_tags.truncate(index);
13851            }
13852        }
13853
13854        templates_with_tags
13855    }
13856
13857    pub fn move_to_enclosing_bracket(
13858        &mut self,
13859        _: &MoveToEnclosingBracket,
13860        window: &mut Window,
13861        cx: &mut Context<Self>,
13862    ) {
13863        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13864        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13865            s.move_offsets_with(|snapshot, selection| {
13866                let Some(enclosing_bracket_ranges) =
13867                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13868                else {
13869                    return;
13870                };
13871
13872                let mut best_length = usize::MAX;
13873                let mut best_inside = false;
13874                let mut best_in_bracket_range = false;
13875                let mut best_destination = None;
13876                for (open, close) in enclosing_bracket_ranges {
13877                    let close = close.to_inclusive();
13878                    let length = close.end() - open.start;
13879                    let inside = selection.start >= open.end && selection.end <= *close.start();
13880                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13881                        || close.contains(&selection.head());
13882
13883                    // If best is next to a bracket and current isn't, skip
13884                    if !in_bracket_range && best_in_bracket_range {
13885                        continue;
13886                    }
13887
13888                    // Prefer smaller lengths unless best is inside and current isn't
13889                    if length > best_length && (best_inside || !inside) {
13890                        continue;
13891                    }
13892
13893                    best_length = length;
13894                    best_inside = inside;
13895                    best_in_bracket_range = in_bracket_range;
13896                    best_destination = Some(
13897                        if close.contains(&selection.start) && close.contains(&selection.end) {
13898                            if inside { open.end } else { open.start }
13899                        } else if inside {
13900                            *close.start()
13901                        } else {
13902                            *close.end()
13903                        },
13904                    );
13905                }
13906
13907                if let Some(destination) = best_destination {
13908                    selection.collapse_to(destination, SelectionGoal::None);
13909                }
13910            })
13911        });
13912    }
13913
13914    pub fn undo_selection(
13915        &mut self,
13916        _: &UndoSelection,
13917        window: &mut Window,
13918        cx: &mut Context<Self>,
13919    ) {
13920        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13921        self.end_selection(window, cx);
13922        self.selection_history.mode = SelectionHistoryMode::Undoing;
13923        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13924            self.change_selections(None, window, cx, |s| {
13925                s.select_anchors(entry.selections.to_vec())
13926            });
13927            self.select_next_state = entry.select_next_state;
13928            self.select_prev_state = entry.select_prev_state;
13929            self.add_selections_state = entry.add_selections_state;
13930            self.request_autoscroll(Autoscroll::newest(), cx);
13931        }
13932        self.selection_history.mode = SelectionHistoryMode::Normal;
13933    }
13934
13935    pub fn redo_selection(
13936        &mut self,
13937        _: &RedoSelection,
13938        window: &mut Window,
13939        cx: &mut Context<Self>,
13940    ) {
13941        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13942        self.end_selection(window, cx);
13943        self.selection_history.mode = SelectionHistoryMode::Redoing;
13944        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
13945            self.change_selections(None, window, cx, |s| {
13946                s.select_anchors(entry.selections.to_vec())
13947            });
13948            self.select_next_state = entry.select_next_state;
13949            self.select_prev_state = entry.select_prev_state;
13950            self.add_selections_state = entry.add_selections_state;
13951            self.request_autoscroll(Autoscroll::newest(), cx);
13952        }
13953        self.selection_history.mode = SelectionHistoryMode::Normal;
13954    }
13955
13956    pub fn expand_excerpts(
13957        &mut self,
13958        action: &ExpandExcerpts,
13959        _: &mut Window,
13960        cx: &mut Context<Self>,
13961    ) {
13962        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
13963    }
13964
13965    pub fn expand_excerpts_down(
13966        &mut self,
13967        action: &ExpandExcerptsDown,
13968        _: &mut Window,
13969        cx: &mut Context<Self>,
13970    ) {
13971        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
13972    }
13973
13974    pub fn expand_excerpts_up(
13975        &mut self,
13976        action: &ExpandExcerptsUp,
13977        _: &mut Window,
13978        cx: &mut Context<Self>,
13979    ) {
13980        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
13981    }
13982
13983    pub fn expand_excerpts_for_direction(
13984        &mut self,
13985        lines: u32,
13986        direction: ExpandExcerptDirection,
13987
13988        cx: &mut Context<Self>,
13989    ) {
13990        let selections = self.selections.disjoint_anchors();
13991
13992        let lines = if lines == 0 {
13993            EditorSettings::get_global(cx).expand_excerpt_lines
13994        } else {
13995            lines
13996        };
13997
13998        self.buffer.update(cx, |buffer, cx| {
13999            let snapshot = buffer.snapshot(cx);
14000            let mut excerpt_ids = selections
14001                .iter()
14002                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14003                .collect::<Vec<_>>();
14004            excerpt_ids.sort();
14005            excerpt_ids.dedup();
14006            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14007        })
14008    }
14009
14010    pub fn expand_excerpt(
14011        &mut self,
14012        excerpt: ExcerptId,
14013        direction: ExpandExcerptDirection,
14014        window: &mut Window,
14015        cx: &mut Context<Self>,
14016    ) {
14017        let current_scroll_position = self.scroll_position(cx);
14018        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14019        let mut should_scroll_up = false;
14020
14021        if direction == ExpandExcerptDirection::Down {
14022            let multi_buffer = self.buffer.read(cx);
14023            let snapshot = multi_buffer.snapshot(cx);
14024            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14025                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14026                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14027                        let buffer_snapshot = buffer.read(cx).snapshot();
14028                        let excerpt_end_row =
14029                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14030                        let last_row = buffer_snapshot.max_point().row;
14031                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14032                        should_scroll_up = lines_below >= lines_to_expand;
14033                    }
14034                }
14035            }
14036        }
14037
14038        self.buffer.update(cx, |buffer, cx| {
14039            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14040        });
14041
14042        if should_scroll_up {
14043            let new_scroll_position =
14044                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14045            self.set_scroll_position(new_scroll_position, window, cx);
14046        }
14047    }
14048
14049    pub fn go_to_singleton_buffer_point(
14050        &mut self,
14051        point: Point,
14052        window: &mut Window,
14053        cx: &mut Context<Self>,
14054    ) {
14055        self.go_to_singleton_buffer_range(point..point, window, cx);
14056    }
14057
14058    pub fn go_to_singleton_buffer_range(
14059        &mut self,
14060        range: Range<Point>,
14061        window: &mut Window,
14062        cx: &mut Context<Self>,
14063    ) {
14064        let multibuffer = self.buffer().read(cx);
14065        let Some(buffer) = multibuffer.as_singleton() else {
14066            return;
14067        };
14068        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14069            return;
14070        };
14071        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14072            return;
14073        };
14074        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14075            s.select_anchor_ranges([start..end])
14076        });
14077    }
14078
14079    pub fn go_to_diagnostic(
14080        &mut self,
14081        _: &GoToDiagnostic,
14082        window: &mut Window,
14083        cx: &mut Context<Self>,
14084    ) {
14085        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14086        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14087    }
14088
14089    pub fn go_to_prev_diagnostic(
14090        &mut self,
14091        _: &GoToPreviousDiagnostic,
14092        window: &mut Window,
14093        cx: &mut Context<Self>,
14094    ) {
14095        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14096        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14097    }
14098
14099    pub fn go_to_diagnostic_impl(
14100        &mut self,
14101        direction: Direction,
14102        window: &mut Window,
14103        cx: &mut Context<Self>,
14104    ) {
14105        let buffer = self.buffer.read(cx).snapshot(cx);
14106        let selection = self.selections.newest::<usize>(cx);
14107
14108        let mut active_group_id = None;
14109        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14110            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14111                active_group_id = Some(active_group.group_id);
14112            }
14113        }
14114
14115        fn filtered(
14116            snapshot: EditorSnapshot,
14117            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14118        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14119            diagnostics
14120                .filter(|entry| entry.range.start != entry.range.end)
14121                .filter(|entry| !entry.diagnostic.is_unnecessary)
14122                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14123        }
14124
14125        let snapshot = self.snapshot(window, cx);
14126        let before = filtered(
14127            snapshot.clone(),
14128            buffer
14129                .diagnostics_in_range(0..selection.start)
14130                .filter(|entry| entry.range.start <= selection.start),
14131        );
14132        let after = filtered(
14133            snapshot,
14134            buffer
14135                .diagnostics_in_range(selection.start..buffer.len())
14136                .filter(|entry| entry.range.start >= selection.start),
14137        );
14138
14139        let mut found: Option<DiagnosticEntry<usize>> = None;
14140        if direction == Direction::Prev {
14141            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14142            {
14143                for diagnostic in prev_diagnostics.into_iter().rev() {
14144                    if diagnostic.range.start != selection.start
14145                        || active_group_id
14146                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14147                    {
14148                        found = Some(diagnostic);
14149                        break 'outer;
14150                    }
14151                }
14152            }
14153        } else {
14154            for diagnostic in after.chain(before) {
14155                if diagnostic.range.start != selection.start
14156                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14157                {
14158                    found = Some(diagnostic);
14159                    break;
14160                }
14161            }
14162        }
14163        let Some(next_diagnostic) = found else {
14164            return;
14165        };
14166
14167        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14168            return;
14169        };
14170        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14171            s.select_ranges(vec![
14172                next_diagnostic.range.start..next_diagnostic.range.start,
14173            ])
14174        });
14175        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14176        self.refresh_inline_completion(false, true, window, cx);
14177    }
14178
14179    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14180        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14181        let snapshot = self.snapshot(window, cx);
14182        let selection = self.selections.newest::<Point>(cx);
14183        self.go_to_hunk_before_or_after_position(
14184            &snapshot,
14185            selection.head(),
14186            Direction::Next,
14187            window,
14188            cx,
14189        );
14190    }
14191
14192    pub fn go_to_hunk_before_or_after_position(
14193        &mut self,
14194        snapshot: &EditorSnapshot,
14195        position: Point,
14196        direction: Direction,
14197        window: &mut Window,
14198        cx: &mut Context<Editor>,
14199    ) {
14200        let row = if direction == Direction::Next {
14201            self.hunk_after_position(snapshot, position)
14202                .map(|hunk| hunk.row_range.start)
14203        } else {
14204            self.hunk_before_position(snapshot, position)
14205        };
14206
14207        if let Some(row) = row {
14208            let destination = Point::new(row.0, 0);
14209            let autoscroll = Autoscroll::center();
14210
14211            self.unfold_ranges(&[destination..destination], false, false, cx);
14212            self.change_selections(Some(autoscroll), window, cx, |s| {
14213                s.select_ranges([destination..destination]);
14214            });
14215        }
14216    }
14217
14218    fn hunk_after_position(
14219        &mut self,
14220        snapshot: &EditorSnapshot,
14221        position: Point,
14222    ) -> Option<MultiBufferDiffHunk> {
14223        snapshot
14224            .buffer_snapshot
14225            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14226            .find(|hunk| hunk.row_range.start.0 > position.row)
14227            .or_else(|| {
14228                snapshot
14229                    .buffer_snapshot
14230                    .diff_hunks_in_range(Point::zero()..position)
14231                    .find(|hunk| hunk.row_range.end.0 < position.row)
14232            })
14233    }
14234
14235    fn go_to_prev_hunk(
14236        &mut self,
14237        _: &GoToPreviousHunk,
14238        window: &mut Window,
14239        cx: &mut Context<Self>,
14240    ) {
14241        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14242        let snapshot = self.snapshot(window, cx);
14243        let selection = self.selections.newest::<Point>(cx);
14244        self.go_to_hunk_before_or_after_position(
14245            &snapshot,
14246            selection.head(),
14247            Direction::Prev,
14248            window,
14249            cx,
14250        );
14251    }
14252
14253    fn hunk_before_position(
14254        &mut self,
14255        snapshot: &EditorSnapshot,
14256        position: Point,
14257    ) -> Option<MultiBufferRow> {
14258        snapshot
14259            .buffer_snapshot
14260            .diff_hunk_before(position)
14261            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14262    }
14263
14264    fn go_to_next_change(
14265        &mut self,
14266        _: &GoToNextChange,
14267        window: &mut Window,
14268        cx: &mut Context<Self>,
14269    ) {
14270        if let Some(selections) = self
14271            .change_list
14272            .next_change(1, Direction::Next)
14273            .map(|s| s.to_vec())
14274        {
14275            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14276                let map = s.display_map();
14277                s.select_display_ranges(selections.iter().map(|a| {
14278                    let point = a.to_display_point(&map);
14279                    point..point
14280                }))
14281            })
14282        }
14283    }
14284
14285    fn go_to_previous_change(
14286        &mut self,
14287        _: &GoToPreviousChange,
14288        window: &mut Window,
14289        cx: &mut Context<Self>,
14290    ) {
14291        if let Some(selections) = self
14292            .change_list
14293            .next_change(1, Direction::Prev)
14294            .map(|s| s.to_vec())
14295        {
14296            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14297                let map = s.display_map();
14298                s.select_display_ranges(selections.iter().map(|a| {
14299                    let point = a.to_display_point(&map);
14300                    point..point
14301                }))
14302            })
14303        }
14304    }
14305
14306    fn go_to_line<T: 'static>(
14307        &mut self,
14308        position: Anchor,
14309        highlight_color: Option<Hsla>,
14310        window: &mut Window,
14311        cx: &mut Context<Self>,
14312    ) {
14313        let snapshot = self.snapshot(window, cx).display_snapshot;
14314        let position = position.to_point(&snapshot.buffer_snapshot);
14315        let start = snapshot
14316            .buffer_snapshot
14317            .clip_point(Point::new(position.row, 0), Bias::Left);
14318        let end = start + Point::new(1, 0);
14319        let start = snapshot.buffer_snapshot.anchor_before(start);
14320        let end = snapshot.buffer_snapshot.anchor_before(end);
14321
14322        self.highlight_rows::<T>(
14323            start..end,
14324            highlight_color
14325                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14326            Default::default(),
14327            cx,
14328        );
14329
14330        if self.buffer.read(cx).is_singleton() {
14331            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14332        }
14333    }
14334
14335    pub fn go_to_definition(
14336        &mut self,
14337        _: &GoToDefinition,
14338        window: &mut Window,
14339        cx: &mut Context<Self>,
14340    ) -> Task<Result<Navigated>> {
14341        let definition =
14342            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14343        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14344        cx.spawn_in(window, async move |editor, cx| {
14345            if definition.await? == Navigated::Yes {
14346                return Ok(Navigated::Yes);
14347            }
14348            match fallback_strategy {
14349                GoToDefinitionFallback::None => Ok(Navigated::No),
14350                GoToDefinitionFallback::FindAllReferences => {
14351                    match editor.update_in(cx, |editor, window, cx| {
14352                        editor.find_all_references(&FindAllReferences, window, cx)
14353                    })? {
14354                        Some(references) => references.await,
14355                        None => Ok(Navigated::No),
14356                    }
14357                }
14358            }
14359        })
14360    }
14361
14362    pub fn go_to_declaration(
14363        &mut self,
14364        _: &GoToDeclaration,
14365        window: &mut Window,
14366        cx: &mut Context<Self>,
14367    ) -> Task<Result<Navigated>> {
14368        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14369    }
14370
14371    pub fn go_to_declaration_split(
14372        &mut self,
14373        _: &GoToDeclaration,
14374        window: &mut Window,
14375        cx: &mut Context<Self>,
14376    ) -> Task<Result<Navigated>> {
14377        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14378    }
14379
14380    pub fn go_to_implementation(
14381        &mut self,
14382        _: &GoToImplementation,
14383        window: &mut Window,
14384        cx: &mut Context<Self>,
14385    ) -> Task<Result<Navigated>> {
14386        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14387    }
14388
14389    pub fn go_to_implementation_split(
14390        &mut self,
14391        _: &GoToImplementationSplit,
14392        window: &mut Window,
14393        cx: &mut Context<Self>,
14394    ) -> Task<Result<Navigated>> {
14395        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14396    }
14397
14398    pub fn go_to_type_definition(
14399        &mut self,
14400        _: &GoToTypeDefinition,
14401        window: &mut Window,
14402        cx: &mut Context<Self>,
14403    ) -> Task<Result<Navigated>> {
14404        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14405    }
14406
14407    pub fn go_to_definition_split(
14408        &mut self,
14409        _: &GoToDefinitionSplit,
14410        window: &mut Window,
14411        cx: &mut Context<Self>,
14412    ) -> Task<Result<Navigated>> {
14413        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14414    }
14415
14416    pub fn go_to_type_definition_split(
14417        &mut self,
14418        _: &GoToTypeDefinitionSplit,
14419        window: &mut Window,
14420        cx: &mut Context<Self>,
14421    ) -> Task<Result<Navigated>> {
14422        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14423    }
14424
14425    fn go_to_definition_of_kind(
14426        &mut self,
14427        kind: GotoDefinitionKind,
14428        split: bool,
14429        window: &mut Window,
14430        cx: &mut Context<Self>,
14431    ) -> Task<Result<Navigated>> {
14432        let Some(provider) = self.semantics_provider.clone() else {
14433            return Task::ready(Ok(Navigated::No));
14434        };
14435        let head = self.selections.newest::<usize>(cx).head();
14436        let buffer = self.buffer.read(cx);
14437        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14438            text_anchor
14439        } else {
14440            return Task::ready(Ok(Navigated::No));
14441        };
14442
14443        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14444            return Task::ready(Ok(Navigated::No));
14445        };
14446
14447        cx.spawn_in(window, async move |editor, cx| {
14448            let definitions = definitions.await?;
14449            let navigated = editor
14450                .update_in(cx, |editor, window, cx| {
14451                    editor.navigate_to_hover_links(
14452                        Some(kind),
14453                        definitions
14454                            .into_iter()
14455                            .filter(|location| {
14456                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14457                            })
14458                            .map(HoverLink::Text)
14459                            .collect::<Vec<_>>(),
14460                        split,
14461                        window,
14462                        cx,
14463                    )
14464                })?
14465                .await?;
14466            anyhow::Ok(navigated)
14467        })
14468    }
14469
14470    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14471        let selection = self.selections.newest_anchor();
14472        let head = selection.head();
14473        let tail = selection.tail();
14474
14475        let Some((buffer, start_position)) =
14476            self.buffer.read(cx).text_anchor_for_position(head, cx)
14477        else {
14478            return;
14479        };
14480
14481        let end_position = if head != tail {
14482            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14483                return;
14484            };
14485            Some(pos)
14486        } else {
14487            None
14488        };
14489
14490        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14491            let url = if let Some(end_pos) = end_position {
14492                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14493            } else {
14494                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14495            };
14496
14497            if let Some(url) = url {
14498                editor.update(cx, |_, cx| {
14499                    cx.open_url(&url);
14500                })
14501            } else {
14502                Ok(())
14503            }
14504        });
14505
14506        url_finder.detach();
14507    }
14508
14509    pub fn open_selected_filename(
14510        &mut self,
14511        _: &OpenSelectedFilename,
14512        window: &mut Window,
14513        cx: &mut Context<Self>,
14514    ) {
14515        let Some(workspace) = self.workspace() else {
14516            return;
14517        };
14518
14519        let position = self.selections.newest_anchor().head();
14520
14521        let Some((buffer, buffer_position)) =
14522            self.buffer.read(cx).text_anchor_for_position(position, cx)
14523        else {
14524            return;
14525        };
14526
14527        let project = self.project.clone();
14528
14529        cx.spawn_in(window, async move |_, cx| {
14530            let result = find_file(&buffer, project, buffer_position, cx).await;
14531
14532            if let Some((_, path)) = result {
14533                workspace
14534                    .update_in(cx, |workspace, window, cx| {
14535                        workspace.open_resolved_path(path, window, cx)
14536                    })?
14537                    .await?;
14538            }
14539            anyhow::Ok(())
14540        })
14541        .detach();
14542    }
14543
14544    pub(crate) fn navigate_to_hover_links(
14545        &mut self,
14546        kind: Option<GotoDefinitionKind>,
14547        mut definitions: Vec<HoverLink>,
14548        split: bool,
14549        window: &mut Window,
14550        cx: &mut Context<Editor>,
14551    ) -> Task<Result<Navigated>> {
14552        // If there is one definition, just open it directly
14553        if definitions.len() == 1 {
14554            let definition = definitions.pop().unwrap();
14555
14556            enum TargetTaskResult {
14557                Location(Option<Location>),
14558                AlreadyNavigated,
14559            }
14560
14561            let target_task = match definition {
14562                HoverLink::Text(link) => {
14563                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14564                }
14565                HoverLink::InlayHint(lsp_location, server_id) => {
14566                    let computation =
14567                        self.compute_target_location(lsp_location, server_id, window, cx);
14568                    cx.background_spawn(async move {
14569                        let location = computation.await?;
14570                        Ok(TargetTaskResult::Location(location))
14571                    })
14572                }
14573                HoverLink::Url(url) => {
14574                    cx.open_url(&url);
14575                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14576                }
14577                HoverLink::File(path) => {
14578                    if let Some(workspace) = self.workspace() {
14579                        cx.spawn_in(window, async move |_, cx| {
14580                            workspace
14581                                .update_in(cx, |workspace, window, cx| {
14582                                    workspace.open_resolved_path(path, window, cx)
14583                                })?
14584                                .await
14585                                .map(|_| TargetTaskResult::AlreadyNavigated)
14586                        })
14587                    } else {
14588                        Task::ready(Ok(TargetTaskResult::Location(None)))
14589                    }
14590                }
14591            };
14592            cx.spawn_in(window, async move |editor, cx| {
14593                let target = match target_task.await.context("target resolution task")? {
14594                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14595                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14596                    TargetTaskResult::Location(Some(target)) => target,
14597                };
14598
14599                editor.update_in(cx, |editor, window, cx| {
14600                    let Some(workspace) = editor.workspace() else {
14601                        return Navigated::No;
14602                    };
14603                    let pane = workspace.read(cx).active_pane().clone();
14604
14605                    let range = target.range.to_point(target.buffer.read(cx));
14606                    let range = editor.range_for_match(&range);
14607                    let range = collapse_multiline_range(range);
14608
14609                    if !split
14610                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14611                    {
14612                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14613                    } else {
14614                        window.defer(cx, move |window, cx| {
14615                            let target_editor: Entity<Self> =
14616                                workspace.update(cx, |workspace, cx| {
14617                                    let pane = if split {
14618                                        workspace.adjacent_pane(window, cx)
14619                                    } else {
14620                                        workspace.active_pane().clone()
14621                                    };
14622
14623                                    workspace.open_project_item(
14624                                        pane,
14625                                        target.buffer.clone(),
14626                                        true,
14627                                        true,
14628                                        window,
14629                                        cx,
14630                                    )
14631                                });
14632                            target_editor.update(cx, |target_editor, cx| {
14633                                // When selecting a definition in a different buffer, disable the nav history
14634                                // to avoid creating a history entry at the previous cursor location.
14635                                pane.update(cx, |pane, _| pane.disable_history());
14636                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14637                                pane.update(cx, |pane, _| pane.enable_history());
14638                            });
14639                        });
14640                    }
14641                    Navigated::Yes
14642                })
14643            })
14644        } else if !definitions.is_empty() {
14645            cx.spawn_in(window, async move |editor, cx| {
14646                let (title, location_tasks, workspace) = editor
14647                    .update_in(cx, |editor, window, cx| {
14648                        let tab_kind = match kind {
14649                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14650                            _ => "Definitions",
14651                        };
14652                        let title = definitions
14653                            .iter()
14654                            .find_map(|definition| match definition {
14655                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14656                                    let buffer = origin.buffer.read(cx);
14657                                    format!(
14658                                        "{} for {}",
14659                                        tab_kind,
14660                                        buffer
14661                                            .text_for_range(origin.range.clone())
14662                                            .collect::<String>()
14663                                    )
14664                                }),
14665                                HoverLink::InlayHint(_, _) => None,
14666                                HoverLink::Url(_) => None,
14667                                HoverLink::File(_) => None,
14668                            })
14669                            .unwrap_or(tab_kind.to_string());
14670                        let location_tasks = definitions
14671                            .into_iter()
14672                            .map(|definition| match definition {
14673                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14674                                HoverLink::InlayHint(lsp_location, server_id) => editor
14675                                    .compute_target_location(lsp_location, server_id, window, cx),
14676                                HoverLink::Url(_) => Task::ready(Ok(None)),
14677                                HoverLink::File(_) => Task::ready(Ok(None)),
14678                            })
14679                            .collect::<Vec<_>>();
14680                        (title, location_tasks, editor.workspace().clone())
14681                    })
14682                    .context("location tasks preparation")?;
14683
14684                let locations = future::join_all(location_tasks)
14685                    .await
14686                    .into_iter()
14687                    .filter_map(|location| location.transpose())
14688                    .collect::<Result<_>>()
14689                    .context("location tasks")?;
14690
14691                let Some(workspace) = workspace else {
14692                    return Ok(Navigated::No);
14693                };
14694                let opened = workspace
14695                    .update_in(cx, |workspace, window, cx| {
14696                        Self::open_locations_in_multibuffer(
14697                            workspace,
14698                            locations,
14699                            title,
14700                            split,
14701                            MultibufferSelectionMode::First,
14702                            window,
14703                            cx,
14704                        )
14705                    })
14706                    .ok();
14707
14708                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14709            })
14710        } else {
14711            Task::ready(Ok(Navigated::No))
14712        }
14713    }
14714
14715    fn compute_target_location(
14716        &self,
14717        lsp_location: lsp::Location,
14718        server_id: LanguageServerId,
14719        window: &mut Window,
14720        cx: &mut Context<Self>,
14721    ) -> Task<anyhow::Result<Option<Location>>> {
14722        let Some(project) = self.project.clone() else {
14723            return Task::ready(Ok(None));
14724        };
14725
14726        cx.spawn_in(window, async move |editor, cx| {
14727            let location_task = editor.update(cx, |_, cx| {
14728                project.update(cx, |project, cx| {
14729                    let language_server_name = project
14730                        .language_server_statuses(cx)
14731                        .find(|(id, _)| server_id == *id)
14732                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14733                    language_server_name.map(|language_server_name| {
14734                        project.open_local_buffer_via_lsp(
14735                            lsp_location.uri.clone(),
14736                            server_id,
14737                            language_server_name,
14738                            cx,
14739                        )
14740                    })
14741                })
14742            })?;
14743            let location = match location_task {
14744                Some(task) => Some({
14745                    let target_buffer_handle = task.await.context("open local buffer")?;
14746                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
14747                        let target_start = target_buffer
14748                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14749                        let target_end = target_buffer
14750                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14751                        target_buffer.anchor_after(target_start)
14752                            ..target_buffer.anchor_before(target_end)
14753                    })?;
14754                    Location {
14755                        buffer: target_buffer_handle,
14756                        range,
14757                    }
14758                }),
14759                None => None,
14760            };
14761            Ok(location)
14762        })
14763    }
14764
14765    pub fn find_all_references(
14766        &mut self,
14767        _: &FindAllReferences,
14768        window: &mut Window,
14769        cx: &mut Context<Self>,
14770    ) -> Option<Task<Result<Navigated>>> {
14771        let selection = self.selections.newest::<usize>(cx);
14772        let multi_buffer = self.buffer.read(cx);
14773        let head = selection.head();
14774
14775        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14776        let head_anchor = multi_buffer_snapshot.anchor_at(
14777            head,
14778            if head < selection.tail() {
14779                Bias::Right
14780            } else {
14781                Bias::Left
14782            },
14783        );
14784
14785        match self
14786            .find_all_references_task_sources
14787            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14788        {
14789            Ok(_) => {
14790                log::info!(
14791                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14792                );
14793                return None;
14794            }
14795            Err(i) => {
14796                self.find_all_references_task_sources.insert(i, head_anchor);
14797            }
14798        }
14799
14800        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14801        let workspace = self.workspace()?;
14802        let project = workspace.read(cx).project().clone();
14803        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14804        Some(cx.spawn_in(window, async move |editor, cx| {
14805            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14806                if let Ok(i) = editor
14807                    .find_all_references_task_sources
14808                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14809                {
14810                    editor.find_all_references_task_sources.remove(i);
14811                }
14812            });
14813
14814            let locations = references.await?;
14815            if locations.is_empty() {
14816                return anyhow::Ok(Navigated::No);
14817            }
14818
14819            workspace.update_in(cx, |workspace, window, cx| {
14820                let title = locations
14821                    .first()
14822                    .as_ref()
14823                    .map(|location| {
14824                        let buffer = location.buffer.read(cx);
14825                        format!(
14826                            "References to `{}`",
14827                            buffer
14828                                .text_for_range(location.range.clone())
14829                                .collect::<String>()
14830                        )
14831                    })
14832                    .unwrap();
14833                Self::open_locations_in_multibuffer(
14834                    workspace,
14835                    locations,
14836                    title,
14837                    false,
14838                    MultibufferSelectionMode::First,
14839                    window,
14840                    cx,
14841                );
14842                Navigated::Yes
14843            })
14844        }))
14845    }
14846
14847    /// Opens a multibuffer with the given project locations in it
14848    pub fn open_locations_in_multibuffer(
14849        workspace: &mut Workspace,
14850        mut locations: Vec<Location>,
14851        title: String,
14852        split: bool,
14853        multibuffer_selection_mode: MultibufferSelectionMode,
14854        window: &mut Window,
14855        cx: &mut Context<Workspace>,
14856    ) {
14857        // If there are multiple definitions, open them in a multibuffer
14858        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14859        let mut locations = locations.into_iter().peekable();
14860        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14861        let capability = workspace.project().read(cx).capability();
14862
14863        let excerpt_buffer = cx.new(|cx| {
14864            let mut multibuffer = MultiBuffer::new(capability);
14865            while let Some(location) = locations.next() {
14866                let buffer = location.buffer.read(cx);
14867                let mut ranges_for_buffer = Vec::new();
14868                let range = location.range.to_point(buffer);
14869                ranges_for_buffer.push(range.clone());
14870
14871                while let Some(next_location) = locations.peek() {
14872                    if next_location.buffer == location.buffer {
14873                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14874                        locations.next();
14875                    } else {
14876                        break;
14877                    }
14878                }
14879
14880                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14881                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14882                    PathKey::for_buffer(&location.buffer, cx),
14883                    location.buffer.clone(),
14884                    ranges_for_buffer,
14885                    DEFAULT_MULTIBUFFER_CONTEXT,
14886                    cx,
14887                );
14888                ranges.extend(new_ranges)
14889            }
14890
14891            multibuffer.with_title(title)
14892        });
14893
14894        let editor = cx.new(|cx| {
14895            Editor::for_multibuffer(
14896                excerpt_buffer,
14897                Some(workspace.project().clone()),
14898                window,
14899                cx,
14900            )
14901        });
14902        editor.update(cx, |editor, cx| {
14903            match multibuffer_selection_mode {
14904                MultibufferSelectionMode::First => {
14905                    if let Some(first_range) = ranges.first() {
14906                        editor.change_selections(None, window, cx, |selections| {
14907                            selections.clear_disjoint();
14908                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14909                        });
14910                    }
14911                    editor.highlight_background::<Self>(
14912                        &ranges,
14913                        |theme| theme.editor_highlighted_line_background,
14914                        cx,
14915                    );
14916                }
14917                MultibufferSelectionMode::All => {
14918                    editor.change_selections(None, window, cx, |selections| {
14919                        selections.clear_disjoint();
14920                        selections.select_anchor_ranges(ranges);
14921                    });
14922                }
14923            }
14924            editor.register_buffers_with_language_servers(cx);
14925        });
14926
14927        let item = Box::new(editor);
14928        let item_id = item.item_id();
14929
14930        if split {
14931            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14932        } else {
14933            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14934                let (preview_item_id, preview_item_idx) =
14935                    workspace.active_pane().read_with(cx, |pane, _| {
14936                        (pane.preview_item_id(), pane.preview_item_idx())
14937                    });
14938
14939                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14940
14941                if let Some(preview_item_id) = preview_item_id {
14942                    workspace.active_pane().update(cx, |pane, cx| {
14943                        pane.remove_item(preview_item_id, false, false, window, cx);
14944                    });
14945                }
14946            } else {
14947                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
14948            }
14949        }
14950        workspace.active_pane().update(cx, |pane, cx| {
14951            pane.set_preview_item_id(Some(item_id), cx);
14952        });
14953    }
14954
14955    pub fn rename(
14956        &mut self,
14957        _: &Rename,
14958        window: &mut Window,
14959        cx: &mut Context<Self>,
14960    ) -> Option<Task<Result<()>>> {
14961        use language::ToOffset as _;
14962
14963        let provider = self.semantics_provider.clone()?;
14964        let selection = self.selections.newest_anchor().clone();
14965        let (cursor_buffer, cursor_buffer_position) = self
14966            .buffer
14967            .read(cx)
14968            .text_anchor_for_position(selection.head(), cx)?;
14969        let (tail_buffer, cursor_buffer_position_end) = self
14970            .buffer
14971            .read(cx)
14972            .text_anchor_for_position(selection.tail(), cx)?;
14973        if tail_buffer != cursor_buffer {
14974            return None;
14975        }
14976
14977        let snapshot = cursor_buffer.read(cx).snapshot();
14978        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
14979        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
14980        let prepare_rename = provider
14981            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
14982            .unwrap_or_else(|| Task::ready(Ok(None)));
14983        drop(snapshot);
14984
14985        Some(cx.spawn_in(window, async move |this, cx| {
14986            let rename_range = if let Some(range) = prepare_rename.await? {
14987                Some(range)
14988            } else {
14989                this.update(cx, |this, cx| {
14990                    let buffer = this.buffer.read(cx).snapshot(cx);
14991                    let mut buffer_highlights = this
14992                        .document_highlights_for_position(selection.head(), &buffer)
14993                        .filter(|highlight| {
14994                            highlight.start.excerpt_id == selection.head().excerpt_id
14995                                && highlight.end.excerpt_id == selection.head().excerpt_id
14996                        });
14997                    buffer_highlights
14998                        .next()
14999                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15000                })?
15001            };
15002            if let Some(rename_range) = rename_range {
15003                this.update_in(cx, |this, window, cx| {
15004                    let snapshot = cursor_buffer.read(cx).snapshot();
15005                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15006                    let cursor_offset_in_rename_range =
15007                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15008                    let cursor_offset_in_rename_range_end =
15009                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15010
15011                    this.take_rename(false, window, cx);
15012                    let buffer = this.buffer.read(cx).read(cx);
15013                    let cursor_offset = selection.head().to_offset(&buffer);
15014                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15015                    let rename_end = rename_start + rename_buffer_range.len();
15016                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15017                    let mut old_highlight_id = None;
15018                    let old_name: Arc<str> = buffer
15019                        .chunks(rename_start..rename_end, true)
15020                        .map(|chunk| {
15021                            if old_highlight_id.is_none() {
15022                                old_highlight_id = chunk.syntax_highlight_id;
15023                            }
15024                            chunk.text
15025                        })
15026                        .collect::<String>()
15027                        .into();
15028
15029                    drop(buffer);
15030
15031                    // Position the selection in the rename editor so that it matches the current selection.
15032                    this.show_local_selections = false;
15033                    let rename_editor = cx.new(|cx| {
15034                        let mut editor = Editor::single_line(window, cx);
15035                        editor.buffer.update(cx, |buffer, cx| {
15036                            buffer.edit([(0..0, old_name.clone())], None, cx)
15037                        });
15038                        let rename_selection_range = match cursor_offset_in_rename_range
15039                            .cmp(&cursor_offset_in_rename_range_end)
15040                        {
15041                            Ordering::Equal => {
15042                                editor.select_all(&SelectAll, window, cx);
15043                                return editor;
15044                            }
15045                            Ordering::Less => {
15046                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15047                            }
15048                            Ordering::Greater => {
15049                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15050                            }
15051                        };
15052                        if rename_selection_range.end > old_name.len() {
15053                            editor.select_all(&SelectAll, window, cx);
15054                        } else {
15055                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15056                                s.select_ranges([rename_selection_range]);
15057                            });
15058                        }
15059                        editor
15060                    });
15061                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15062                        if e == &EditorEvent::Focused {
15063                            cx.emit(EditorEvent::FocusedIn)
15064                        }
15065                    })
15066                    .detach();
15067
15068                    let write_highlights =
15069                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15070                    let read_highlights =
15071                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15072                    let ranges = write_highlights
15073                        .iter()
15074                        .flat_map(|(_, ranges)| ranges.iter())
15075                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15076                        .cloned()
15077                        .collect();
15078
15079                    this.highlight_text::<Rename>(
15080                        ranges,
15081                        HighlightStyle {
15082                            fade_out: Some(0.6),
15083                            ..Default::default()
15084                        },
15085                        cx,
15086                    );
15087                    let rename_focus_handle = rename_editor.focus_handle(cx);
15088                    window.focus(&rename_focus_handle);
15089                    let block_id = this.insert_blocks(
15090                        [BlockProperties {
15091                            style: BlockStyle::Flex,
15092                            placement: BlockPlacement::Below(range.start),
15093                            height: Some(1),
15094                            render: Arc::new({
15095                                let rename_editor = rename_editor.clone();
15096                                move |cx: &mut BlockContext| {
15097                                    let mut text_style = cx.editor_style.text.clone();
15098                                    if let Some(highlight_style) = old_highlight_id
15099                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15100                                    {
15101                                        text_style = text_style.highlight(highlight_style);
15102                                    }
15103                                    div()
15104                                        .block_mouse_except_scroll()
15105                                        .pl(cx.anchor_x)
15106                                        .child(EditorElement::new(
15107                                            &rename_editor,
15108                                            EditorStyle {
15109                                                background: cx.theme().system().transparent,
15110                                                local_player: cx.editor_style.local_player,
15111                                                text: text_style,
15112                                                scrollbar_width: cx.editor_style.scrollbar_width,
15113                                                syntax: cx.editor_style.syntax.clone(),
15114                                                status: cx.editor_style.status.clone(),
15115                                                inlay_hints_style: HighlightStyle {
15116                                                    font_weight: Some(FontWeight::BOLD),
15117                                                    ..make_inlay_hints_style(cx.app)
15118                                                },
15119                                                inline_completion_styles: make_suggestion_styles(
15120                                                    cx.app,
15121                                                ),
15122                                                ..EditorStyle::default()
15123                                            },
15124                                        ))
15125                                        .into_any_element()
15126                                }
15127                            }),
15128                            priority: 0,
15129                            render_in_minimap: true,
15130                        }],
15131                        Some(Autoscroll::fit()),
15132                        cx,
15133                    )[0];
15134                    this.pending_rename = Some(RenameState {
15135                        range,
15136                        old_name,
15137                        editor: rename_editor,
15138                        block_id,
15139                    });
15140                })?;
15141            }
15142
15143            Ok(())
15144        }))
15145    }
15146
15147    pub fn confirm_rename(
15148        &mut self,
15149        _: &ConfirmRename,
15150        window: &mut Window,
15151        cx: &mut Context<Self>,
15152    ) -> Option<Task<Result<()>>> {
15153        let rename = self.take_rename(false, window, cx)?;
15154        let workspace = self.workspace()?.downgrade();
15155        let (buffer, start) = self
15156            .buffer
15157            .read(cx)
15158            .text_anchor_for_position(rename.range.start, cx)?;
15159        let (end_buffer, _) = self
15160            .buffer
15161            .read(cx)
15162            .text_anchor_for_position(rename.range.end, cx)?;
15163        if buffer != end_buffer {
15164            return None;
15165        }
15166
15167        let old_name = rename.old_name;
15168        let new_name = rename.editor.read(cx).text(cx);
15169
15170        let rename = self.semantics_provider.as_ref()?.perform_rename(
15171            &buffer,
15172            start,
15173            new_name.clone(),
15174            cx,
15175        )?;
15176
15177        Some(cx.spawn_in(window, async move |editor, cx| {
15178            let project_transaction = rename.await?;
15179            Self::open_project_transaction(
15180                &editor,
15181                workspace,
15182                project_transaction,
15183                format!("Rename: {}{}", old_name, new_name),
15184                cx,
15185            )
15186            .await?;
15187
15188            editor.update(cx, |editor, cx| {
15189                editor.refresh_document_highlights(cx);
15190            })?;
15191            Ok(())
15192        }))
15193    }
15194
15195    fn take_rename(
15196        &mut self,
15197        moving_cursor: bool,
15198        window: &mut Window,
15199        cx: &mut Context<Self>,
15200    ) -> Option<RenameState> {
15201        let rename = self.pending_rename.take()?;
15202        if rename.editor.focus_handle(cx).is_focused(window) {
15203            window.focus(&self.focus_handle);
15204        }
15205
15206        self.remove_blocks(
15207            [rename.block_id].into_iter().collect(),
15208            Some(Autoscroll::fit()),
15209            cx,
15210        );
15211        self.clear_highlights::<Rename>(cx);
15212        self.show_local_selections = true;
15213
15214        if moving_cursor {
15215            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15216                editor.selections.newest::<usize>(cx).head()
15217            });
15218
15219            // Update the selection to match the position of the selection inside
15220            // the rename editor.
15221            let snapshot = self.buffer.read(cx).read(cx);
15222            let rename_range = rename.range.to_offset(&snapshot);
15223            let cursor_in_editor = snapshot
15224                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15225                .min(rename_range.end);
15226            drop(snapshot);
15227
15228            self.change_selections(None, window, cx, |s| {
15229                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15230            });
15231        } else {
15232            self.refresh_document_highlights(cx);
15233        }
15234
15235        Some(rename)
15236    }
15237
15238    pub fn pending_rename(&self) -> Option<&RenameState> {
15239        self.pending_rename.as_ref()
15240    }
15241
15242    fn format(
15243        &mut self,
15244        _: &Format,
15245        window: &mut Window,
15246        cx: &mut Context<Self>,
15247    ) -> Option<Task<Result<()>>> {
15248        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15249
15250        let project = match &self.project {
15251            Some(project) => project.clone(),
15252            None => return None,
15253        };
15254
15255        Some(self.perform_format(
15256            project,
15257            FormatTrigger::Manual,
15258            FormatTarget::Buffers,
15259            window,
15260            cx,
15261        ))
15262    }
15263
15264    fn format_selections(
15265        &mut self,
15266        _: &FormatSelections,
15267        window: &mut Window,
15268        cx: &mut Context<Self>,
15269    ) -> Option<Task<Result<()>>> {
15270        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15271
15272        let project = match &self.project {
15273            Some(project) => project.clone(),
15274            None => return None,
15275        };
15276
15277        let ranges = self
15278            .selections
15279            .all_adjusted(cx)
15280            .into_iter()
15281            .map(|selection| selection.range())
15282            .collect_vec();
15283
15284        Some(self.perform_format(
15285            project,
15286            FormatTrigger::Manual,
15287            FormatTarget::Ranges(ranges),
15288            window,
15289            cx,
15290        ))
15291    }
15292
15293    fn perform_format(
15294        &mut self,
15295        project: Entity<Project>,
15296        trigger: FormatTrigger,
15297        target: FormatTarget,
15298        window: &mut Window,
15299        cx: &mut Context<Self>,
15300    ) -> Task<Result<()>> {
15301        let buffer = self.buffer.clone();
15302        let (buffers, target) = match target {
15303            FormatTarget::Buffers => {
15304                let mut buffers = buffer.read(cx).all_buffers();
15305                if trigger == FormatTrigger::Save {
15306                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15307                }
15308                (buffers, LspFormatTarget::Buffers)
15309            }
15310            FormatTarget::Ranges(selection_ranges) => {
15311                let multi_buffer = buffer.read(cx);
15312                let snapshot = multi_buffer.read(cx);
15313                let mut buffers = HashSet::default();
15314                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15315                    BTreeMap::new();
15316                for selection_range in selection_ranges {
15317                    for (buffer, buffer_range, _) in
15318                        snapshot.range_to_buffer_ranges(selection_range)
15319                    {
15320                        let buffer_id = buffer.remote_id();
15321                        let start = buffer.anchor_before(buffer_range.start);
15322                        let end = buffer.anchor_after(buffer_range.end);
15323                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15324                        buffer_id_to_ranges
15325                            .entry(buffer_id)
15326                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15327                            .or_insert_with(|| vec![start..end]);
15328                    }
15329                }
15330                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15331            }
15332        };
15333
15334        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15335        let selections_prev = transaction_id_prev
15336            .and_then(|transaction_id_prev| {
15337                // default to selections as they were after the last edit, if we have them,
15338                // instead of how they are now.
15339                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15340                // will take you back to where you made the last edit, instead of staying where you scrolled
15341                self.selection_history
15342                    .transaction(transaction_id_prev)
15343                    .map(|t| t.0.clone())
15344            })
15345            .unwrap_or_else(|| {
15346                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15347                self.selections.disjoint_anchors()
15348            });
15349
15350        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15351        let format = project.update(cx, |project, cx| {
15352            project.format(buffers, target, true, trigger, cx)
15353        });
15354
15355        cx.spawn_in(window, async move |editor, cx| {
15356            let transaction = futures::select_biased! {
15357                transaction = format.log_err().fuse() => transaction,
15358                () = timeout => {
15359                    log::warn!("timed out waiting for formatting");
15360                    None
15361                }
15362            };
15363
15364            buffer
15365                .update(cx, |buffer, cx| {
15366                    if let Some(transaction) = transaction {
15367                        if !buffer.is_singleton() {
15368                            buffer.push_transaction(&transaction.0, cx);
15369                        }
15370                    }
15371                    cx.notify();
15372                })
15373                .ok();
15374
15375            if let Some(transaction_id_now) =
15376                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15377            {
15378                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15379                if has_new_transaction {
15380                    _ = editor.update(cx, |editor, _| {
15381                        editor
15382                            .selection_history
15383                            .insert_transaction(transaction_id_now, selections_prev);
15384                    });
15385                }
15386            }
15387
15388            Ok(())
15389        })
15390    }
15391
15392    fn organize_imports(
15393        &mut self,
15394        _: &OrganizeImports,
15395        window: &mut Window,
15396        cx: &mut Context<Self>,
15397    ) -> Option<Task<Result<()>>> {
15398        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15399        let project = match &self.project {
15400            Some(project) => project.clone(),
15401            None => return None,
15402        };
15403        Some(self.perform_code_action_kind(
15404            project,
15405            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15406            window,
15407            cx,
15408        ))
15409    }
15410
15411    fn perform_code_action_kind(
15412        &mut self,
15413        project: Entity<Project>,
15414        kind: CodeActionKind,
15415        window: &mut Window,
15416        cx: &mut Context<Self>,
15417    ) -> Task<Result<()>> {
15418        let buffer = self.buffer.clone();
15419        let buffers = buffer.read(cx).all_buffers();
15420        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15421        let apply_action = project.update(cx, |project, cx| {
15422            project.apply_code_action_kind(buffers, kind, true, cx)
15423        });
15424        cx.spawn_in(window, async move |_, cx| {
15425            let transaction = futures::select_biased! {
15426                () = timeout => {
15427                    log::warn!("timed out waiting for executing code action");
15428                    None
15429                }
15430                transaction = apply_action.log_err().fuse() => transaction,
15431            };
15432            buffer
15433                .update(cx, |buffer, cx| {
15434                    // check if we need this
15435                    if let Some(transaction) = transaction {
15436                        if !buffer.is_singleton() {
15437                            buffer.push_transaction(&transaction.0, cx);
15438                        }
15439                    }
15440                    cx.notify();
15441                })
15442                .ok();
15443            Ok(())
15444        })
15445    }
15446
15447    fn restart_language_server(
15448        &mut self,
15449        _: &RestartLanguageServer,
15450        _: &mut Window,
15451        cx: &mut Context<Self>,
15452    ) {
15453        if let Some(project) = self.project.clone() {
15454            self.buffer.update(cx, |multi_buffer, cx| {
15455                project.update(cx, |project, cx| {
15456                    project.restart_language_servers_for_buffers(
15457                        multi_buffer.all_buffers().into_iter().collect(),
15458                        cx,
15459                    );
15460                });
15461            })
15462        }
15463    }
15464
15465    fn stop_language_server(
15466        &mut self,
15467        _: &StopLanguageServer,
15468        _: &mut Window,
15469        cx: &mut Context<Self>,
15470    ) {
15471        if let Some(project) = self.project.clone() {
15472            self.buffer.update(cx, |multi_buffer, cx| {
15473                project.update(cx, |project, cx| {
15474                    project.stop_language_servers_for_buffers(
15475                        multi_buffer.all_buffers().into_iter().collect(),
15476                        cx,
15477                    );
15478                    cx.emit(project::Event::RefreshInlayHints);
15479                });
15480            });
15481        }
15482    }
15483
15484    fn cancel_language_server_work(
15485        workspace: &mut Workspace,
15486        _: &actions::CancelLanguageServerWork,
15487        _: &mut Window,
15488        cx: &mut Context<Workspace>,
15489    ) {
15490        let project = workspace.project();
15491        let buffers = workspace
15492            .active_item(cx)
15493            .and_then(|item| item.act_as::<Editor>(cx))
15494            .map_or(HashSet::default(), |editor| {
15495                editor.read(cx).buffer.read(cx).all_buffers()
15496            });
15497        project.update(cx, |project, cx| {
15498            project.cancel_language_server_work_for_buffers(buffers, cx);
15499        });
15500    }
15501
15502    fn show_character_palette(
15503        &mut self,
15504        _: &ShowCharacterPalette,
15505        window: &mut Window,
15506        _: &mut Context<Self>,
15507    ) {
15508        window.show_character_palette();
15509    }
15510
15511    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15512        if self.mode.is_minimap() {
15513            return;
15514        }
15515
15516        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15517            let buffer = self.buffer.read(cx).snapshot(cx);
15518            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15519            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15520            let is_valid = buffer
15521                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15522                .any(|entry| {
15523                    entry.diagnostic.is_primary
15524                        && !entry.range.is_empty()
15525                        && entry.range.start == primary_range_start
15526                        && entry.diagnostic.message == active_diagnostics.active_message
15527                });
15528
15529            if !is_valid {
15530                self.dismiss_diagnostics(cx);
15531            }
15532        }
15533    }
15534
15535    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15536        match &self.active_diagnostics {
15537            ActiveDiagnostic::Group(group) => Some(group),
15538            _ => None,
15539        }
15540    }
15541
15542    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15543        self.dismiss_diagnostics(cx);
15544        self.active_diagnostics = ActiveDiagnostic::All;
15545    }
15546
15547    fn activate_diagnostics(
15548        &mut self,
15549        buffer_id: BufferId,
15550        diagnostic: DiagnosticEntry<usize>,
15551        window: &mut Window,
15552        cx: &mut Context<Self>,
15553    ) {
15554        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15555            return;
15556        }
15557        self.dismiss_diagnostics(cx);
15558        let snapshot = self.snapshot(window, cx);
15559        let buffer = self.buffer.read(cx).snapshot(cx);
15560        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15561            return;
15562        };
15563
15564        let diagnostic_group = buffer
15565            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15566            .collect::<Vec<_>>();
15567
15568        let blocks =
15569            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15570
15571        let blocks = self.display_map.update(cx, |display_map, cx| {
15572            display_map.insert_blocks(blocks, cx).into_iter().collect()
15573        });
15574        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15575            active_range: buffer.anchor_before(diagnostic.range.start)
15576                ..buffer.anchor_after(diagnostic.range.end),
15577            active_message: diagnostic.diagnostic.message.clone(),
15578            group_id: diagnostic.diagnostic.group_id,
15579            blocks,
15580        });
15581        cx.notify();
15582    }
15583
15584    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15585        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15586            return;
15587        };
15588
15589        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15590        if let ActiveDiagnostic::Group(group) = prev {
15591            self.display_map.update(cx, |display_map, cx| {
15592                display_map.remove_blocks(group.blocks, cx);
15593            });
15594            cx.notify();
15595        }
15596    }
15597
15598    /// Disable inline diagnostics rendering for this editor.
15599    pub fn disable_inline_diagnostics(&mut self) {
15600        self.inline_diagnostics_enabled = false;
15601        self.inline_diagnostics_update = Task::ready(());
15602        self.inline_diagnostics.clear();
15603    }
15604
15605    pub fn diagnostics_enabled(&self) -> bool {
15606        self.mode.is_full()
15607    }
15608
15609    pub fn inline_diagnostics_enabled(&self) -> bool {
15610        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15611    }
15612
15613    pub fn show_inline_diagnostics(&self) -> bool {
15614        self.show_inline_diagnostics
15615    }
15616
15617    pub fn toggle_inline_diagnostics(
15618        &mut self,
15619        _: &ToggleInlineDiagnostics,
15620        window: &mut Window,
15621        cx: &mut Context<Editor>,
15622    ) {
15623        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15624        self.refresh_inline_diagnostics(false, window, cx);
15625    }
15626
15627    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15628        self.diagnostics_max_severity = severity;
15629        self.display_map.update(cx, |display_map, _| {
15630            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15631        });
15632    }
15633
15634    pub fn toggle_diagnostics(
15635        &mut self,
15636        _: &ToggleDiagnostics,
15637        window: &mut Window,
15638        cx: &mut Context<Editor>,
15639    ) {
15640        if !self.diagnostics_enabled() {
15641            return;
15642        }
15643
15644        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15645            EditorSettings::get_global(cx)
15646                .diagnostics_max_severity
15647                .filter(|severity| severity != &DiagnosticSeverity::Off)
15648                .unwrap_or(DiagnosticSeverity::Hint)
15649        } else {
15650            DiagnosticSeverity::Off
15651        };
15652        self.set_max_diagnostics_severity(new_severity, cx);
15653        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15654            self.active_diagnostics = ActiveDiagnostic::None;
15655            self.inline_diagnostics_update = Task::ready(());
15656            self.inline_diagnostics.clear();
15657        } else {
15658            self.refresh_inline_diagnostics(false, window, cx);
15659        }
15660
15661        cx.notify();
15662    }
15663
15664    pub fn toggle_minimap(
15665        &mut self,
15666        _: &ToggleMinimap,
15667        window: &mut Window,
15668        cx: &mut Context<Editor>,
15669    ) {
15670        if self.supports_minimap(cx) {
15671            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15672        }
15673    }
15674
15675    fn refresh_inline_diagnostics(
15676        &mut self,
15677        debounce: bool,
15678        window: &mut Window,
15679        cx: &mut Context<Self>,
15680    ) {
15681        let max_severity = ProjectSettings::get_global(cx)
15682            .diagnostics
15683            .inline
15684            .max_severity
15685            .unwrap_or(self.diagnostics_max_severity);
15686
15687        if !self.inline_diagnostics_enabled()
15688            || !self.show_inline_diagnostics
15689            || max_severity == DiagnosticSeverity::Off
15690        {
15691            self.inline_diagnostics_update = Task::ready(());
15692            self.inline_diagnostics.clear();
15693            return;
15694        }
15695
15696        let debounce_ms = ProjectSettings::get_global(cx)
15697            .diagnostics
15698            .inline
15699            .update_debounce_ms;
15700        let debounce = if debounce && debounce_ms > 0 {
15701            Some(Duration::from_millis(debounce_ms))
15702        } else {
15703            None
15704        };
15705        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15706            if let Some(debounce) = debounce {
15707                cx.background_executor().timer(debounce).await;
15708            }
15709            let Some(snapshot) = editor.upgrade().and_then(|editor| {
15710                editor
15711                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15712                    .ok()
15713            }) else {
15714                return;
15715            };
15716
15717            let new_inline_diagnostics = cx
15718                .background_spawn(async move {
15719                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15720                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15721                        let message = diagnostic_entry
15722                            .diagnostic
15723                            .message
15724                            .split_once('\n')
15725                            .map(|(line, _)| line)
15726                            .map(SharedString::new)
15727                            .unwrap_or_else(|| {
15728                                SharedString::from(diagnostic_entry.diagnostic.message)
15729                            });
15730                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15731                        let (Ok(i) | Err(i)) = inline_diagnostics
15732                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15733                        inline_diagnostics.insert(
15734                            i,
15735                            (
15736                                start_anchor,
15737                                InlineDiagnostic {
15738                                    message,
15739                                    group_id: diagnostic_entry.diagnostic.group_id,
15740                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15741                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15742                                    severity: diagnostic_entry.diagnostic.severity,
15743                                },
15744                            ),
15745                        );
15746                    }
15747                    inline_diagnostics
15748                })
15749                .await;
15750
15751            editor
15752                .update(cx, |editor, cx| {
15753                    editor.inline_diagnostics = new_inline_diagnostics;
15754                    cx.notify();
15755                })
15756                .ok();
15757        });
15758    }
15759
15760    pub fn set_selections_from_remote(
15761        &mut self,
15762        selections: Vec<Selection<Anchor>>,
15763        pending_selection: Option<Selection<Anchor>>,
15764        window: &mut Window,
15765        cx: &mut Context<Self>,
15766    ) {
15767        let old_cursor_position = self.selections.newest_anchor().head();
15768        self.selections.change_with(cx, |s| {
15769            s.select_anchors(selections);
15770            if let Some(pending_selection) = pending_selection {
15771                s.set_pending(pending_selection, SelectMode::Character);
15772            } else {
15773                s.clear_pending();
15774            }
15775        });
15776        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15777    }
15778
15779    pub fn transact(
15780        &mut self,
15781        window: &mut Window,
15782        cx: &mut Context<Self>,
15783        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15784    ) -> Option<TransactionId> {
15785        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15786            this.start_transaction_at(Instant::now(), window, cx);
15787            update(this, window, cx);
15788            this.end_transaction_at(Instant::now(), cx)
15789        })
15790    }
15791
15792    pub fn start_transaction_at(
15793        &mut self,
15794        now: Instant,
15795        window: &mut Window,
15796        cx: &mut Context<Self>,
15797    ) {
15798        self.end_selection(window, cx);
15799        if let Some(tx_id) = self
15800            .buffer
15801            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15802        {
15803            self.selection_history
15804                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15805            cx.emit(EditorEvent::TransactionBegun {
15806                transaction_id: tx_id,
15807            })
15808        }
15809    }
15810
15811    pub fn end_transaction_at(
15812        &mut self,
15813        now: Instant,
15814        cx: &mut Context<Self>,
15815    ) -> Option<TransactionId> {
15816        if let Some(transaction_id) = self
15817            .buffer
15818            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15819        {
15820            if let Some((_, end_selections)) =
15821                self.selection_history.transaction_mut(transaction_id)
15822            {
15823                *end_selections = Some(self.selections.disjoint_anchors());
15824            } else {
15825                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15826            }
15827
15828            cx.emit(EditorEvent::Edited { transaction_id });
15829            Some(transaction_id)
15830        } else {
15831            None
15832        }
15833    }
15834
15835    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15836        if self.selection_mark_mode {
15837            self.change_selections(None, window, cx, |s| {
15838                s.move_with(|_, sel| {
15839                    sel.collapse_to(sel.head(), SelectionGoal::None);
15840                });
15841            })
15842        }
15843        self.selection_mark_mode = true;
15844        cx.notify();
15845    }
15846
15847    pub fn swap_selection_ends(
15848        &mut self,
15849        _: &actions::SwapSelectionEnds,
15850        window: &mut Window,
15851        cx: &mut Context<Self>,
15852    ) {
15853        self.change_selections(None, window, cx, |s| {
15854            s.move_with(|_, sel| {
15855                if sel.start != sel.end {
15856                    sel.reversed = !sel.reversed
15857                }
15858            });
15859        });
15860        self.request_autoscroll(Autoscroll::newest(), cx);
15861        cx.notify();
15862    }
15863
15864    pub fn toggle_fold(
15865        &mut self,
15866        _: &actions::ToggleFold,
15867        window: &mut Window,
15868        cx: &mut Context<Self>,
15869    ) {
15870        if self.is_singleton(cx) {
15871            let selection = self.selections.newest::<Point>(cx);
15872
15873            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15874            let range = if selection.is_empty() {
15875                let point = selection.head().to_display_point(&display_map);
15876                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15877                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15878                    .to_point(&display_map);
15879                start..end
15880            } else {
15881                selection.range()
15882            };
15883            if display_map.folds_in_range(range).next().is_some() {
15884                self.unfold_lines(&Default::default(), window, cx)
15885            } else {
15886                self.fold(&Default::default(), window, cx)
15887            }
15888        } else {
15889            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15890            let buffer_ids: HashSet<_> = self
15891                .selections
15892                .disjoint_anchor_ranges()
15893                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15894                .collect();
15895
15896            let should_unfold = buffer_ids
15897                .iter()
15898                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15899
15900            for buffer_id in buffer_ids {
15901                if should_unfold {
15902                    self.unfold_buffer(buffer_id, cx);
15903                } else {
15904                    self.fold_buffer(buffer_id, cx);
15905                }
15906            }
15907        }
15908    }
15909
15910    pub fn toggle_fold_recursive(
15911        &mut self,
15912        _: &actions::ToggleFoldRecursive,
15913        window: &mut Window,
15914        cx: &mut Context<Self>,
15915    ) {
15916        let selection = self.selections.newest::<Point>(cx);
15917
15918        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15919        let range = if selection.is_empty() {
15920            let point = selection.head().to_display_point(&display_map);
15921            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15922            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15923                .to_point(&display_map);
15924            start..end
15925        } else {
15926            selection.range()
15927        };
15928        if display_map.folds_in_range(range).next().is_some() {
15929            self.unfold_recursive(&Default::default(), window, cx)
15930        } else {
15931            self.fold_recursive(&Default::default(), window, cx)
15932        }
15933    }
15934
15935    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15936        if self.is_singleton(cx) {
15937            let mut to_fold = Vec::new();
15938            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15939            let selections = self.selections.all_adjusted(cx);
15940
15941            for selection in selections {
15942                let range = selection.range().sorted();
15943                let buffer_start_row = range.start.row;
15944
15945                if range.start.row != range.end.row {
15946                    let mut found = false;
15947                    let mut row = range.start.row;
15948                    while row <= range.end.row {
15949                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15950                        {
15951                            found = true;
15952                            row = crease.range().end.row + 1;
15953                            to_fold.push(crease);
15954                        } else {
15955                            row += 1
15956                        }
15957                    }
15958                    if found {
15959                        continue;
15960                    }
15961                }
15962
15963                for row in (0..=range.start.row).rev() {
15964                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15965                        if crease.range().end.row >= buffer_start_row {
15966                            to_fold.push(crease);
15967                            if row <= range.start.row {
15968                                break;
15969                            }
15970                        }
15971                    }
15972                }
15973            }
15974
15975            self.fold_creases(to_fold, true, window, cx);
15976        } else {
15977            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15978            let buffer_ids = self
15979                .selections
15980                .disjoint_anchor_ranges()
15981                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15982                .collect::<HashSet<_>>();
15983            for buffer_id in buffer_ids {
15984                self.fold_buffer(buffer_id, cx);
15985            }
15986        }
15987    }
15988
15989    fn fold_at_level(
15990        &mut self,
15991        fold_at: &FoldAtLevel,
15992        window: &mut Window,
15993        cx: &mut Context<Self>,
15994    ) {
15995        if !self.buffer.read(cx).is_singleton() {
15996            return;
15997        }
15998
15999        let fold_at_level = fold_at.0;
16000        let snapshot = self.buffer.read(cx).snapshot(cx);
16001        let mut to_fold = Vec::new();
16002        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16003
16004        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16005            while start_row < end_row {
16006                match self
16007                    .snapshot(window, cx)
16008                    .crease_for_buffer_row(MultiBufferRow(start_row))
16009                {
16010                    Some(crease) => {
16011                        let nested_start_row = crease.range().start.row + 1;
16012                        let nested_end_row = crease.range().end.row;
16013
16014                        if current_level < fold_at_level {
16015                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16016                        } else if current_level == fold_at_level {
16017                            to_fold.push(crease);
16018                        }
16019
16020                        start_row = nested_end_row + 1;
16021                    }
16022                    None => start_row += 1,
16023                }
16024            }
16025        }
16026
16027        self.fold_creases(to_fold, true, window, cx);
16028    }
16029
16030    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16031        if self.buffer.read(cx).is_singleton() {
16032            let mut fold_ranges = Vec::new();
16033            let snapshot = self.buffer.read(cx).snapshot(cx);
16034
16035            for row in 0..snapshot.max_row().0 {
16036                if let Some(foldable_range) = self
16037                    .snapshot(window, cx)
16038                    .crease_for_buffer_row(MultiBufferRow(row))
16039                {
16040                    fold_ranges.push(foldable_range);
16041                }
16042            }
16043
16044            self.fold_creases(fold_ranges, true, window, cx);
16045        } else {
16046            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16047                editor
16048                    .update_in(cx, |editor, _, cx| {
16049                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16050                            editor.fold_buffer(buffer_id, cx);
16051                        }
16052                    })
16053                    .ok();
16054            });
16055        }
16056    }
16057
16058    pub fn fold_function_bodies(
16059        &mut self,
16060        _: &actions::FoldFunctionBodies,
16061        window: &mut Window,
16062        cx: &mut Context<Self>,
16063    ) {
16064        let snapshot = self.buffer.read(cx).snapshot(cx);
16065
16066        let ranges = snapshot
16067            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16068            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16069            .collect::<Vec<_>>();
16070
16071        let creases = ranges
16072            .into_iter()
16073            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16074            .collect();
16075
16076        self.fold_creases(creases, true, window, cx);
16077    }
16078
16079    pub fn fold_recursive(
16080        &mut self,
16081        _: &actions::FoldRecursive,
16082        window: &mut Window,
16083        cx: &mut Context<Self>,
16084    ) {
16085        let mut to_fold = Vec::new();
16086        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16087        let selections = self.selections.all_adjusted(cx);
16088
16089        for selection in selections {
16090            let range = selection.range().sorted();
16091            let buffer_start_row = range.start.row;
16092
16093            if range.start.row != range.end.row {
16094                let mut found = false;
16095                for row in range.start.row..=range.end.row {
16096                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16097                        found = true;
16098                        to_fold.push(crease);
16099                    }
16100                }
16101                if found {
16102                    continue;
16103                }
16104            }
16105
16106            for row in (0..=range.start.row).rev() {
16107                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16108                    if crease.range().end.row >= buffer_start_row {
16109                        to_fold.push(crease);
16110                    } else {
16111                        break;
16112                    }
16113                }
16114            }
16115        }
16116
16117        self.fold_creases(to_fold, true, window, cx);
16118    }
16119
16120    pub fn fold_at(
16121        &mut self,
16122        buffer_row: MultiBufferRow,
16123        window: &mut Window,
16124        cx: &mut Context<Self>,
16125    ) {
16126        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16127
16128        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16129            let autoscroll = self
16130                .selections
16131                .all::<Point>(cx)
16132                .iter()
16133                .any(|selection| crease.range().overlaps(&selection.range()));
16134
16135            self.fold_creases(vec![crease], autoscroll, window, cx);
16136        }
16137    }
16138
16139    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16140        if self.is_singleton(cx) {
16141            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16142            let buffer = &display_map.buffer_snapshot;
16143            let selections = self.selections.all::<Point>(cx);
16144            let ranges = selections
16145                .iter()
16146                .map(|s| {
16147                    let range = s.display_range(&display_map).sorted();
16148                    let mut start = range.start.to_point(&display_map);
16149                    let mut end = range.end.to_point(&display_map);
16150                    start.column = 0;
16151                    end.column = buffer.line_len(MultiBufferRow(end.row));
16152                    start..end
16153                })
16154                .collect::<Vec<_>>();
16155
16156            self.unfold_ranges(&ranges, true, true, cx);
16157        } else {
16158            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16159            let buffer_ids = self
16160                .selections
16161                .disjoint_anchor_ranges()
16162                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16163                .collect::<HashSet<_>>();
16164            for buffer_id in buffer_ids {
16165                self.unfold_buffer(buffer_id, cx);
16166            }
16167        }
16168    }
16169
16170    pub fn unfold_recursive(
16171        &mut self,
16172        _: &UnfoldRecursive,
16173        _window: &mut Window,
16174        cx: &mut Context<Self>,
16175    ) {
16176        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16177        let selections = self.selections.all::<Point>(cx);
16178        let ranges = selections
16179            .iter()
16180            .map(|s| {
16181                let mut range = s.display_range(&display_map).sorted();
16182                *range.start.column_mut() = 0;
16183                *range.end.column_mut() = display_map.line_len(range.end.row());
16184                let start = range.start.to_point(&display_map);
16185                let end = range.end.to_point(&display_map);
16186                start..end
16187            })
16188            .collect::<Vec<_>>();
16189
16190        self.unfold_ranges(&ranges, true, true, cx);
16191    }
16192
16193    pub fn unfold_at(
16194        &mut self,
16195        buffer_row: MultiBufferRow,
16196        _window: &mut Window,
16197        cx: &mut Context<Self>,
16198    ) {
16199        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16200
16201        let intersection_range = Point::new(buffer_row.0, 0)
16202            ..Point::new(
16203                buffer_row.0,
16204                display_map.buffer_snapshot.line_len(buffer_row),
16205            );
16206
16207        let autoscroll = self
16208            .selections
16209            .all::<Point>(cx)
16210            .iter()
16211            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16212
16213        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16214    }
16215
16216    pub fn unfold_all(
16217        &mut self,
16218        _: &actions::UnfoldAll,
16219        _window: &mut Window,
16220        cx: &mut Context<Self>,
16221    ) {
16222        if self.buffer.read(cx).is_singleton() {
16223            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16224            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16225        } else {
16226            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16227                editor
16228                    .update(cx, |editor, cx| {
16229                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16230                            editor.unfold_buffer(buffer_id, cx);
16231                        }
16232                    })
16233                    .ok();
16234            });
16235        }
16236    }
16237
16238    pub fn fold_selected_ranges(
16239        &mut self,
16240        _: &FoldSelectedRanges,
16241        window: &mut Window,
16242        cx: &mut Context<Self>,
16243    ) {
16244        let selections = self.selections.all_adjusted(cx);
16245        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16246        let ranges = selections
16247            .into_iter()
16248            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16249            .collect::<Vec<_>>();
16250        self.fold_creases(ranges, true, window, cx);
16251    }
16252
16253    pub fn fold_ranges<T: ToOffset + Clone>(
16254        &mut self,
16255        ranges: Vec<Range<T>>,
16256        auto_scroll: bool,
16257        window: &mut Window,
16258        cx: &mut Context<Self>,
16259    ) {
16260        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16261        let ranges = ranges
16262            .into_iter()
16263            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16264            .collect::<Vec<_>>();
16265        self.fold_creases(ranges, auto_scroll, window, cx);
16266    }
16267
16268    pub fn fold_creases<T: ToOffset + Clone>(
16269        &mut self,
16270        creases: Vec<Crease<T>>,
16271        auto_scroll: bool,
16272        _window: &mut Window,
16273        cx: &mut Context<Self>,
16274    ) {
16275        if creases.is_empty() {
16276            return;
16277        }
16278
16279        let mut buffers_affected = HashSet::default();
16280        let multi_buffer = self.buffer().read(cx);
16281        for crease in &creases {
16282            if let Some((_, buffer, _)) =
16283                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16284            {
16285                buffers_affected.insert(buffer.read(cx).remote_id());
16286            };
16287        }
16288
16289        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16290
16291        if auto_scroll {
16292            self.request_autoscroll(Autoscroll::fit(), cx);
16293        }
16294
16295        cx.notify();
16296
16297        self.scrollbar_marker_state.dirty = true;
16298        self.folds_did_change(cx);
16299    }
16300
16301    /// Removes any folds whose ranges intersect any of the given ranges.
16302    pub fn unfold_ranges<T: ToOffset + Clone>(
16303        &mut self,
16304        ranges: &[Range<T>],
16305        inclusive: bool,
16306        auto_scroll: bool,
16307        cx: &mut Context<Self>,
16308    ) {
16309        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16310            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16311        });
16312        self.folds_did_change(cx);
16313    }
16314
16315    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16316        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16317            return;
16318        }
16319        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16320        self.display_map.update(cx, |display_map, cx| {
16321            display_map.fold_buffers([buffer_id], cx)
16322        });
16323        cx.emit(EditorEvent::BufferFoldToggled {
16324            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16325            folded: true,
16326        });
16327        cx.notify();
16328    }
16329
16330    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16331        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16332            return;
16333        }
16334        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16335        self.display_map.update(cx, |display_map, cx| {
16336            display_map.unfold_buffers([buffer_id], cx);
16337        });
16338        cx.emit(EditorEvent::BufferFoldToggled {
16339            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16340            folded: false,
16341        });
16342        cx.notify();
16343    }
16344
16345    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16346        self.display_map.read(cx).is_buffer_folded(buffer)
16347    }
16348
16349    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16350        self.display_map.read(cx).folded_buffers()
16351    }
16352
16353    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16354        self.display_map.update(cx, |display_map, cx| {
16355            display_map.disable_header_for_buffer(buffer_id, cx);
16356        });
16357        cx.notify();
16358    }
16359
16360    /// Removes any folds with the given ranges.
16361    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16362        &mut self,
16363        ranges: &[Range<T>],
16364        type_id: TypeId,
16365        auto_scroll: bool,
16366        cx: &mut Context<Self>,
16367    ) {
16368        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16369            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16370        });
16371        self.folds_did_change(cx);
16372    }
16373
16374    fn remove_folds_with<T: ToOffset + Clone>(
16375        &mut self,
16376        ranges: &[Range<T>],
16377        auto_scroll: bool,
16378        cx: &mut Context<Self>,
16379        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16380    ) {
16381        if ranges.is_empty() {
16382            return;
16383        }
16384
16385        let mut buffers_affected = HashSet::default();
16386        let multi_buffer = self.buffer().read(cx);
16387        for range in ranges {
16388            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16389                buffers_affected.insert(buffer.read(cx).remote_id());
16390            };
16391        }
16392
16393        self.display_map.update(cx, update);
16394
16395        if auto_scroll {
16396            self.request_autoscroll(Autoscroll::fit(), cx);
16397        }
16398
16399        cx.notify();
16400        self.scrollbar_marker_state.dirty = true;
16401        self.active_indent_guides_state.dirty = true;
16402    }
16403
16404    pub fn update_fold_widths(
16405        &mut self,
16406        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16407        cx: &mut Context<Self>,
16408    ) -> bool {
16409        self.display_map
16410            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16411    }
16412
16413    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16414        self.display_map.read(cx).fold_placeholder.clone()
16415    }
16416
16417    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16418        self.buffer.update(cx, |buffer, cx| {
16419            buffer.set_all_diff_hunks_expanded(cx);
16420        });
16421    }
16422
16423    pub fn expand_all_diff_hunks(
16424        &mut self,
16425        _: &ExpandAllDiffHunks,
16426        _window: &mut Window,
16427        cx: &mut Context<Self>,
16428    ) {
16429        self.buffer.update(cx, |buffer, cx| {
16430            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16431        });
16432    }
16433
16434    pub fn toggle_selected_diff_hunks(
16435        &mut self,
16436        _: &ToggleSelectedDiffHunks,
16437        _window: &mut Window,
16438        cx: &mut Context<Self>,
16439    ) {
16440        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16441        self.toggle_diff_hunks_in_ranges(ranges, cx);
16442    }
16443
16444    pub fn diff_hunks_in_ranges<'a>(
16445        &'a self,
16446        ranges: &'a [Range<Anchor>],
16447        buffer: &'a MultiBufferSnapshot,
16448    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16449        ranges.iter().flat_map(move |range| {
16450            let end_excerpt_id = range.end.excerpt_id;
16451            let range = range.to_point(buffer);
16452            let mut peek_end = range.end;
16453            if range.end.row < buffer.max_row().0 {
16454                peek_end = Point::new(range.end.row + 1, 0);
16455            }
16456            buffer
16457                .diff_hunks_in_range(range.start..peek_end)
16458                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16459        })
16460    }
16461
16462    pub fn has_stageable_diff_hunks_in_ranges(
16463        &self,
16464        ranges: &[Range<Anchor>],
16465        snapshot: &MultiBufferSnapshot,
16466    ) -> bool {
16467        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16468        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16469    }
16470
16471    pub fn toggle_staged_selected_diff_hunks(
16472        &mut self,
16473        _: &::git::ToggleStaged,
16474        _: &mut Window,
16475        cx: &mut Context<Self>,
16476    ) {
16477        let snapshot = self.buffer.read(cx).snapshot(cx);
16478        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16479        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16480        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16481    }
16482
16483    pub fn set_render_diff_hunk_controls(
16484        &mut self,
16485        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16486        cx: &mut Context<Self>,
16487    ) {
16488        self.render_diff_hunk_controls = render_diff_hunk_controls;
16489        cx.notify();
16490    }
16491
16492    pub fn stage_and_next(
16493        &mut self,
16494        _: &::git::StageAndNext,
16495        window: &mut Window,
16496        cx: &mut Context<Self>,
16497    ) {
16498        self.do_stage_or_unstage_and_next(true, window, cx);
16499    }
16500
16501    pub fn unstage_and_next(
16502        &mut self,
16503        _: &::git::UnstageAndNext,
16504        window: &mut Window,
16505        cx: &mut Context<Self>,
16506    ) {
16507        self.do_stage_or_unstage_and_next(false, window, cx);
16508    }
16509
16510    pub fn stage_or_unstage_diff_hunks(
16511        &mut self,
16512        stage: bool,
16513        ranges: Vec<Range<Anchor>>,
16514        cx: &mut Context<Self>,
16515    ) {
16516        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16517        cx.spawn(async move |this, cx| {
16518            task.await?;
16519            this.update(cx, |this, cx| {
16520                let snapshot = this.buffer.read(cx).snapshot(cx);
16521                let chunk_by = this
16522                    .diff_hunks_in_ranges(&ranges, &snapshot)
16523                    .chunk_by(|hunk| hunk.buffer_id);
16524                for (buffer_id, hunks) in &chunk_by {
16525                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16526                }
16527            })
16528        })
16529        .detach_and_log_err(cx);
16530    }
16531
16532    fn save_buffers_for_ranges_if_needed(
16533        &mut self,
16534        ranges: &[Range<Anchor>],
16535        cx: &mut Context<Editor>,
16536    ) -> Task<Result<()>> {
16537        let multibuffer = self.buffer.read(cx);
16538        let snapshot = multibuffer.read(cx);
16539        let buffer_ids: HashSet<_> = ranges
16540            .iter()
16541            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16542            .collect();
16543        drop(snapshot);
16544
16545        let mut buffers = HashSet::default();
16546        for buffer_id in buffer_ids {
16547            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16548                let buffer = buffer_entity.read(cx);
16549                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16550                {
16551                    buffers.insert(buffer_entity);
16552                }
16553            }
16554        }
16555
16556        if let Some(project) = &self.project {
16557            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16558        } else {
16559            Task::ready(Ok(()))
16560        }
16561    }
16562
16563    fn do_stage_or_unstage_and_next(
16564        &mut self,
16565        stage: bool,
16566        window: &mut Window,
16567        cx: &mut Context<Self>,
16568    ) {
16569        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16570
16571        if ranges.iter().any(|range| range.start != range.end) {
16572            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16573            return;
16574        }
16575
16576        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16577        let snapshot = self.snapshot(window, cx);
16578        let position = self.selections.newest::<Point>(cx).head();
16579        let mut row = snapshot
16580            .buffer_snapshot
16581            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16582            .find(|hunk| hunk.row_range.start.0 > position.row)
16583            .map(|hunk| hunk.row_range.start);
16584
16585        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16586        // Outside of the project diff editor, wrap around to the beginning.
16587        if !all_diff_hunks_expanded {
16588            row = row.or_else(|| {
16589                snapshot
16590                    .buffer_snapshot
16591                    .diff_hunks_in_range(Point::zero()..position)
16592                    .find(|hunk| hunk.row_range.end.0 < position.row)
16593                    .map(|hunk| hunk.row_range.start)
16594            });
16595        }
16596
16597        if let Some(row) = row {
16598            let destination = Point::new(row.0, 0);
16599            let autoscroll = Autoscroll::center();
16600
16601            self.unfold_ranges(&[destination..destination], false, false, cx);
16602            self.change_selections(Some(autoscroll), window, cx, |s| {
16603                s.select_ranges([destination..destination]);
16604            });
16605        }
16606    }
16607
16608    fn do_stage_or_unstage(
16609        &self,
16610        stage: bool,
16611        buffer_id: BufferId,
16612        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16613        cx: &mut App,
16614    ) -> Option<()> {
16615        let project = self.project.as_ref()?;
16616        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16617        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16618        let buffer_snapshot = buffer.read(cx).snapshot();
16619        let file_exists = buffer_snapshot
16620            .file()
16621            .is_some_and(|file| file.disk_state().exists());
16622        diff.update(cx, |diff, cx| {
16623            diff.stage_or_unstage_hunks(
16624                stage,
16625                &hunks
16626                    .map(|hunk| buffer_diff::DiffHunk {
16627                        buffer_range: hunk.buffer_range,
16628                        diff_base_byte_range: hunk.diff_base_byte_range,
16629                        secondary_status: hunk.secondary_status,
16630                        range: Point::zero()..Point::zero(), // unused
16631                    })
16632                    .collect::<Vec<_>>(),
16633                &buffer_snapshot,
16634                file_exists,
16635                cx,
16636            )
16637        });
16638        None
16639    }
16640
16641    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16642        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16643        self.buffer
16644            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16645    }
16646
16647    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16648        self.buffer.update(cx, |buffer, cx| {
16649            let ranges = vec![Anchor::min()..Anchor::max()];
16650            if !buffer.all_diff_hunks_expanded()
16651                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16652            {
16653                buffer.collapse_diff_hunks(ranges, cx);
16654                true
16655            } else {
16656                false
16657            }
16658        })
16659    }
16660
16661    fn toggle_diff_hunks_in_ranges(
16662        &mut self,
16663        ranges: Vec<Range<Anchor>>,
16664        cx: &mut Context<Editor>,
16665    ) {
16666        self.buffer.update(cx, |buffer, cx| {
16667            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16668            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16669        })
16670    }
16671
16672    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16673        self.buffer.update(cx, |buffer, cx| {
16674            let snapshot = buffer.snapshot(cx);
16675            let excerpt_id = range.end.excerpt_id;
16676            let point_range = range.to_point(&snapshot);
16677            let expand = !buffer.single_hunk_is_expanded(range, cx);
16678            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16679        })
16680    }
16681
16682    pub(crate) fn apply_all_diff_hunks(
16683        &mut self,
16684        _: &ApplyAllDiffHunks,
16685        window: &mut Window,
16686        cx: &mut Context<Self>,
16687    ) {
16688        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16689
16690        let buffers = self.buffer.read(cx).all_buffers();
16691        for branch_buffer in buffers {
16692            branch_buffer.update(cx, |branch_buffer, cx| {
16693                branch_buffer.merge_into_base(Vec::new(), cx);
16694            });
16695        }
16696
16697        if let Some(project) = self.project.clone() {
16698            self.save(true, project, window, cx).detach_and_log_err(cx);
16699        }
16700    }
16701
16702    pub(crate) fn apply_selected_diff_hunks(
16703        &mut self,
16704        _: &ApplyDiffHunk,
16705        window: &mut Window,
16706        cx: &mut Context<Self>,
16707    ) {
16708        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16709        let snapshot = self.snapshot(window, cx);
16710        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16711        let mut ranges_by_buffer = HashMap::default();
16712        self.transact(window, cx, |editor, _window, cx| {
16713            for hunk in hunks {
16714                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16715                    ranges_by_buffer
16716                        .entry(buffer.clone())
16717                        .or_insert_with(Vec::new)
16718                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16719                }
16720            }
16721
16722            for (buffer, ranges) in ranges_by_buffer {
16723                buffer.update(cx, |buffer, cx| {
16724                    buffer.merge_into_base(ranges, cx);
16725                });
16726            }
16727        });
16728
16729        if let Some(project) = self.project.clone() {
16730            self.save(true, project, window, cx).detach_and_log_err(cx);
16731        }
16732    }
16733
16734    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16735        if hovered != self.gutter_hovered {
16736            self.gutter_hovered = hovered;
16737            cx.notify();
16738        }
16739    }
16740
16741    pub fn insert_blocks(
16742        &mut self,
16743        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16744        autoscroll: Option<Autoscroll>,
16745        cx: &mut Context<Self>,
16746    ) -> Vec<CustomBlockId> {
16747        let blocks = self
16748            .display_map
16749            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16750        if let Some(autoscroll) = autoscroll {
16751            self.request_autoscroll(autoscroll, cx);
16752        }
16753        cx.notify();
16754        blocks
16755    }
16756
16757    pub fn resize_blocks(
16758        &mut self,
16759        heights: HashMap<CustomBlockId, u32>,
16760        autoscroll: Option<Autoscroll>,
16761        cx: &mut Context<Self>,
16762    ) {
16763        self.display_map
16764            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16765        if let Some(autoscroll) = autoscroll {
16766            self.request_autoscroll(autoscroll, cx);
16767        }
16768        cx.notify();
16769    }
16770
16771    pub fn replace_blocks(
16772        &mut self,
16773        renderers: HashMap<CustomBlockId, RenderBlock>,
16774        autoscroll: Option<Autoscroll>,
16775        cx: &mut Context<Self>,
16776    ) {
16777        self.display_map
16778            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16779        if let Some(autoscroll) = autoscroll {
16780            self.request_autoscroll(autoscroll, cx);
16781        }
16782        cx.notify();
16783    }
16784
16785    pub fn remove_blocks(
16786        &mut self,
16787        block_ids: HashSet<CustomBlockId>,
16788        autoscroll: Option<Autoscroll>,
16789        cx: &mut Context<Self>,
16790    ) {
16791        self.display_map.update(cx, |display_map, cx| {
16792            display_map.remove_blocks(block_ids, cx)
16793        });
16794        if let Some(autoscroll) = autoscroll {
16795            self.request_autoscroll(autoscroll, cx);
16796        }
16797        cx.notify();
16798    }
16799
16800    pub fn row_for_block(
16801        &self,
16802        block_id: CustomBlockId,
16803        cx: &mut Context<Self>,
16804    ) -> Option<DisplayRow> {
16805        self.display_map
16806            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16807    }
16808
16809    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16810        self.focused_block = Some(focused_block);
16811    }
16812
16813    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16814        self.focused_block.take()
16815    }
16816
16817    pub fn insert_creases(
16818        &mut self,
16819        creases: impl IntoIterator<Item = Crease<Anchor>>,
16820        cx: &mut Context<Self>,
16821    ) -> Vec<CreaseId> {
16822        self.display_map
16823            .update(cx, |map, cx| map.insert_creases(creases, cx))
16824    }
16825
16826    pub fn remove_creases(
16827        &mut self,
16828        ids: impl IntoIterator<Item = CreaseId>,
16829        cx: &mut Context<Self>,
16830    ) -> Vec<(CreaseId, Range<Anchor>)> {
16831        self.display_map
16832            .update(cx, |map, cx| map.remove_creases(ids, cx))
16833    }
16834
16835    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16836        self.display_map
16837            .update(cx, |map, cx| map.snapshot(cx))
16838            .longest_row()
16839    }
16840
16841    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16842        self.display_map
16843            .update(cx, |map, cx| map.snapshot(cx))
16844            .max_point()
16845    }
16846
16847    pub fn text(&self, cx: &App) -> String {
16848        self.buffer.read(cx).read(cx).text()
16849    }
16850
16851    pub fn is_empty(&self, cx: &App) -> bool {
16852        self.buffer.read(cx).read(cx).is_empty()
16853    }
16854
16855    pub fn text_option(&self, cx: &App) -> Option<String> {
16856        let text = self.text(cx);
16857        let text = text.trim();
16858
16859        if text.is_empty() {
16860            return None;
16861        }
16862
16863        Some(text.to_string())
16864    }
16865
16866    pub fn set_text(
16867        &mut self,
16868        text: impl Into<Arc<str>>,
16869        window: &mut Window,
16870        cx: &mut Context<Self>,
16871    ) {
16872        self.transact(window, cx, |this, _, cx| {
16873            this.buffer
16874                .read(cx)
16875                .as_singleton()
16876                .expect("you can only call set_text on editors for singleton buffers")
16877                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16878        });
16879    }
16880
16881    pub fn display_text(&self, cx: &mut App) -> String {
16882        self.display_map
16883            .update(cx, |map, cx| map.snapshot(cx))
16884            .text()
16885    }
16886
16887    fn create_minimap(
16888        &self,
16889        minimap_settings: MinimapSettings,
16890        window: &mut Window,
16891        cx: &mut Context<Self>,
16892    ) -> Option<Entity<Self>> {
16893        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16894            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16895    }
16896
16897    fn initialize_new_minimap(
16898        &self,
16899        minimap_settings: MinimapSettings,
16900        window: &mut Window,
16901        cx: &mut Context<Self>,
16902    ) -> Entity<Self> {
16903        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16904
16905        let mut minimap = Editor::new_internal(
16906            EditorMode::Minimap {
16907                parent: cx.weak_entity(),
16908            },
16909            self.buffer.clone(),
16910            self.project.clone(),
16911            Some(self.display_map.clone()),
16912            window,
16913            cx,
16914        );
16915        minimap.scroll_manager.clone_state(&self.scroll_manager);
16916        minimap.set_text_style_refinement(TextStyleRefinement {
16917            font_size: Some(MINIMAP_FONT_SIZE),
16918            font_weight: Some(MINIMAP_FONT_WEIGHT),
16919            ..Default::default()
16920        });
16921        minimap.update_minimap_configuration(minimap_settings, cx);
16922        cx.new(|_| minimap)
16923    }
16924
16925    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
16926        let current_line_highlight = minimap_settings
16927            .current_line_highlight
16928            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
16929        self.set_current_line_highlight(Some(current_line_highlight));
16930    }
16931
16932    pub fn minimap(&self) -> Option<&Entity<Self>> {
16933        self.minimap
16934            .as_ref()
16935            .filter(|_| self.minimap_visibility.visible())
16936    }
16937
16938    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16939        let mut wrap_guides = smallvec![];
16940
16941        if self.show_wrap_guides == Some(false) {
16942            return wrap_guides;
16943        }
16944
16945        let settings = self.buffer.read(cx).language_settings(cx);
16946        if settings.show_wrap_guides {
16947            match self.soft_wrap_mode(cx) {
16948                SoftWrap::Column(soft_wrap) => {
16949                    wrap_guides.push((soft_wrap as usize, true));
16950                }
16951                SoftWrap::Bounded(soft_wrap) => {
16952                    wrap_guides.push((soft_wrap as usize, true));
16953                }
16954                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
16955            }
16956            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
16957        }
16958
16959        wrap_guides
16960    }
16961
16962    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16963        let settings = self.buffer.read(cx).language_settings(cx);
16964        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16965        match mode {
16966            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16967                SoftWrap::None
16968            }
16969            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16970            language_settings::SoftWrap::PreferredLineLength => {
16971                SoftWrap::Column(settings.preferred_line_length)
16972            }
16973            language_settings::SoftWrap::Bounded => {
16974                SoftWrap::Bounded(settings.preferred_line_length)
16975            }
16976        }
16977    }
16978
16979    pub fn set_soft_wrap_mode(
16980        &mut self,
16981        mode: language_settings::SoftWrap,
16982
16983        cx: &mut Context<Self>,
16984    ) {
16985        self.soft_wrap_mode_override = Some(mode);
16986        cx.notify();
16987    }
16988
16989    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16990        self.hard_wrap = hard_wrap;
16991        cx.notify();
16992    }
16993
16994    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16995        self.text_style_refinement = Some(style);
16996    }
16997
16998    /// called by the Element so we know what style we were most recently rendered with.
16999    pub(crate) fn set_style(
17000        &mut self,
17001        style: EditorStyle,
17002        window: &mut Window,
17003        cx: &mut Context<Self>,
17004    ) {
17005        // We intentionally do not inform the display map about the minimap style
17006        // so that wrapping is not recalculated and stays consistent for the editor
17007        // and its linked minimap.
17008        if !self.mode.is_minimap() {
17009            let rem_size = window.rem_size();
17010            self.display_map.update(cx, |map, cx| {
17011                map.set_font(
17012                    style.text.font(),
17013                    style.text.font_size.to_pixels(rem_size),
17014                    cx,
17015                )
17016            });
17017        }
17018        self.style = Some(style);
17019    }
17020
17021    pub fn style(&self) -> Option<&EditorStyle> {
17022        self.style.as_ref()
17023    }
17024
17025    // Called by the element. This method is not designed to be called outside of the editor
17026    // element's layout code because it does not notify when rewrapping is computed synchronously.
17027    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17028        self.display_map
17029            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17030    }
17031
17032    pub fn set_soft_wrap(&mut self) {
17033        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17034    }
17035
17036    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17037        if self.soft_wrap_mode_override.is_some() {
17038            self.soft_wrap_mode_override.take();
17039        } else {
17040            let soft_wrap = match self.soft_wrap_mode(cx) {
17041                SoftWrap::GitDiff => return,
17042                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17043                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17044                    language_settings::SoftWrap::None
17045                }
17046            };
17047            self.soft_wrap_mode_override = Some(soft_wrap);
17048        }
17049        cx.notify();
17050    }
17051
17052    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17053        let Some(workspace) = self.workspace() else {
17054            return;
17055        };
17056        let fs = workspace.read(cx).app_state().fs.clone();
17057        let current_show = TabBarSettings::get_global(cx).show;
17058        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17059            setting.show = Some(!current_show);
17060        });
17061    }
17062
17063    pub fn toggle_indent_guides(
17064        &mut self,
17065        _: &ToggleIndentGuides,
17066        _: &mut Window,
17067        cx: &mut Context<Self>,
17068    ) {
17069        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17070            self.buffer
17071                .read(cx)
17072                .language_settings(cx)
17073                .indent_guides
17074                .enabled
17075        });
17076        self.show_indent_guides = Some(!currently_enabled);
17077        cx.notify();
17078    }
17079
17080    fn should_show_indent_guides(&self) -> Option<bool> {
17081        self.show_indent_guides
17082    }
17083
17084    pub fn toggle_line_numbers(
17085        &mut self,
17086        _: &ToggleLineNumbers,
17087        _: &mut Window,
17088        cx: &mut Context<Self>,
17089    ) {
17090        let mut editor_settings = EditorSettings::get_global(cx).clone();
17091        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17092        EditorSettings::override_global(editor_settings, cx);
17093    }
17094
17095    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17096        if let Some(show_line_numbers) = self.show_line_numbers {
17097            return show_line_numbers;
17098        }
17099        EditorSettings::get_global(cx).gutter.line_numbers
17100    }
17101
17102    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17103        self.use_relative_line_numbers
17104            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17105    }
17106
17107    pub fn toggle_relative_line_numbers(
17108        &mut self,
17109        _: &ToggleRelativeLineNumbers,
17110        _: &mut Window,
17111        cx: &mut Context<Self>,
17112    ) {
17113        let is_relative = self.should_use_relative_line_numbers(cx);
17114        self.set_relative_line_number(Some(!is_relative), cx)
17115    }
17116
17117    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17118        self.use_relative_line_numbers = is_relative;
17119        cx.notify();
17120    }
17121
17122    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17123        self.show_gutter = show_gutter;
17124        cx.notify();
17125    }
17126
17127    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17128        self.show_scrollbars = ScrollbarAxes {
17129            horizontal: show,
17130            vertical: show,
17131        };
17132        cx.notify();
17133    }
17134
17135    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17136        self.show_scrollbars.vertical = show;
17137        cx.notify();
17138    }
17139
17140    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17141        self.show_scrollbars.horizontal = show;
17142        cx.notify();
17143    }
17144
17145    pub fn set_minimap_visibility(
17146        &mut self,
17147        minimap_visibility: MinimapVisibility,
17148        window: &mut Window,
17149        cx: &mut Context<Self>,
17150    ) {
17151        if self.minimap_visibility != minimap_visibility {
17152            if minimap_visibility.visible() && self.minimap.is_none() {
17153                let minimap_settings = EditorSettings::get_global(cx).minimap;
17154                self.minimap =
17155                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17156            }
17157            self.minimap_visibility = minimap_visibility;
17158            cx.notify();
17159        }
17160    }
17161
17162    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17163        self.set_show_scrollbars(false, cx);
17164        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17165    }
17166
17167    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17168        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17169    }
17170
17171    /// Normally the text in full mode and auto height editors is padded on the
17172    /// left side by roughly half a character width for improved hit testing.
17173    ///
17174    /// Use this method to disable this for cases where this is not wanted (e.g.
17175    /// if you want to align the editor text with some other text above or below)
17176    /// or if you want to add this padding to single-line editors.
17177    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17178        self.offset_content = offset_content;
17179        cx.notify();
17180    }
17181
17182    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17183        self.show_line_numbers = Some(show_line_numbers);
17184        cx.notify();
17185    }
17186
17187    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17188        self.disable_expand_excerpt_buttons = true;
17189        cx.notify();
17190    }
17191
17192    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17193        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17194        cx.notify();
17195    }
17196
17197    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17198        self.show_code_actions = Some(show_code_actions);
17199        cx.notify();
17200    }
17201
17202    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17203        self.show_runnables = Some(show_runnables);
17204        cx.notify();
17205    }
17206
17207    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17208        self.show_breakpoints = Some(show_breakpoints);
17209        cx.notify();
17210    }
17211
17212    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17213        if self.display_map.read(cx).masked != masked {
17214            self.display_map.update(cx, |map, _| map.masked = masked);
17215        }
17216        cx.notify()
17217    }
17218
17219    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17220        self.show_wrap_guides = Some(show_wrap_guides);
17221        cx.notify();
17222    }
17223
17224    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17225        self.show_indent_guides = Some(show_indent_guides);
17226        cx.notify();
17227    }
17228
17229    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17230        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17231            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17232                if let Some(dir) = file.abs_path(cx).parent() {
17233                    return Some(dir.to_owned());
17234                }
17235            }
17236
17237            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17238                return Some(project_path.path.to_path_buf());
17239            }
17240        }
17241
17242        None
17243    }
17244
17245    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17246        self.active_excerpt(cx)?
17247            .1
17248            .read(cx)
17249            .file()
17250            .and_then(|f| f.as_local())
17251    }
17252
17253    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17254        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17255            let buffer = buffer.read(cx);
17256            if let Some(project_path) = buffer.project_path(cx) {
17257                let project = self.project.as_ref()?.read(cx);
17258                project.absolute_path(&project_path, cx)
17259            } else {
17260                buffer
17261                    .file()
17262                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17263            }
17264        })
17265    }
17266
17267    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17268        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17269            let project_path = buffer.read(cx).project_path(cx)?;
17270            let project = self.project.as_ref()?.read(cx);
17271            let entry = project.entry_for_path(&project_path, cx)?;
17272            let path = entry.path.to_path_buf();
17273            Some(path)
17274        })
17275    }
17276
17277    pub fn reveal_in_finder(
17278        &mut self,
17279        _: &RevealInFileManager,
17280        _window: &mut Window,
17281        cx: &mut Context<Self>,
17282    ) {
17283        if let Some(target) = self.target_file(cx) {
17284            cx.reveal_path(&target.abs_path(cx));
17285        }
17286    }
17287
17288    pub fn copy_path(
17289        &mut self,
17290        _: &zed_actions::workspace::CopyPath,
17291        _window: &mut Window,
17292        cx: &mut Context<Self>,
17293    ) {
17294        if let Some(path) = self.target_file_abs_path(cx) {
17295            if let Some(path) = path.to_str() {
17296                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17297            }
17298        }
17299    }
17300
17301    pub fn copy_relative_path(
17302        &mut self,
17303        _: &zed_actions::workspace::CopyRelativePath,
17304        _window: &mut Window,
17305        cx: &mut Context<Self>,
17306    ) {
17307        if let Some(path) = self.target_file_path(cx) {
17308            if let Some(path) = path.to_str() {
17309                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17310            }
17311        }
17312    }
17313
17314    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17315        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17316            buffer.read(cx).project_path(cx)
17317        } else {
17318            None
17319        }
17320    }
17321
17322    // Returns true if the editor handled a go-to-line request
17323    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17324        maybe!({
17325            let breakpoint_store = self.breakpoint_store.as_ref()?;
17326
17327            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17328            else {
17329                self.clear_row_highlights::<ActiveDebugLine>();
17330                return None;
17331            };
17332
17333            let position = active_stack_frame.position;
17334            let buffer_id = position.buffer_id?;
17335            let snapshot = self
17336                .project
17337                .as_ref()?
17338                .read(cx)
17339                .buffer_for_id(buffer_id, cx)?
17340                .read(cx)
17341                .snapshot();
17342
17343            let mut handled = false;
17344            for (id, ExcerptRange { context, .. }) in
17345                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17346            {
17347                if context.start.cmp(&position, &snapshot).is_ge()
17348                    || context.end.cmp(&position, &snapshot).is_lt()
17349                {
17350                    continue;
17351                }
17352                let snapshot = self.buffer.read(cx).snapshot(cx);
17353                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17354
17355                handled = true;
17356                self.clear_row_highlights::<ActiveDebugLine>();
17357
17358                self.go_to_line::<ActiveDebugLine>(
17359                    multibuffer_anchor,
17360                    Some(cx.theme().colors().editor_debugger_active_line_background),
17361                    window,
17362                    cx,
17363                );
17364
17365                cx.notify();
17366            }
17367
17368            handled.then_some(())
17369        })
17370        .is_some()
17371    }
17372
17373    pub fn copy_file_name_without_extension(
17374        &mut self,
17375        _: &CopyFileNameWithoutExtension,
17376        _: &mut Window,
17377        cx: &mut Context<Self>,
17378    ) {
17379        if let Some(file) = self.target_file(cx) {
17380            if let Some(file_stem) = file.path().file_stem() {
17381                if let Some(name) = file_stem.to_str() {
17382                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17383                }
17384            }
17385        }
17386    }
17387
17388    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17389        if let Some(file) = self.target_file(cx) {
17390            if let Some(file_name) = file.path().file_name() {
17391                if let Some(name) = file_name.to_str() {
17392                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17393                }
17394            }
17395        }
17396    }
17397
17398    pub fn toggle_git_blame(
17399        &mut self,
17400        _: &::git::Blame,
17401        window: &mut Window,
17402        cx: &mut Context<Self>,
17403    ) {
17404        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17405
17406        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17407            self.start_git_blame(true, window, cx);
17408        }
17409
17410        cx.notify();
17411    }
17412
17413    pub fn toggle_git_blame_inline(
17414        &mut self,
17415        _: &ToggleGitBlameInline,
17416        window: &mut Window,
17417        cx: &mut Context<Self>,
17418    ) {
17419        self.toggle_git_blame_inline_internal(true, window, cx);
17420        cx.notify();
17421    }
17422
17423    pub fn open_git_blame_commit(
17424        &mut self,
17425        _: &OpenGitBlameCommit,
17426        window: &mut Window,
17427        cx: &mut Context<Self>,
17428    ) {
17429        self.open_git_blame_commit_internal(window, cx);
17430    }
17431
17432    fn open_git_blame_commit_internal(
17433        &mut self,
17434        window: &mut Window,
17435        cx: &mut Context<Self>,
17436    ) -> Option<()> {
17437        let blame = self.blame.as_ref()?;
17438        let snapshot = self.snapshot(window, cx);
17439        let cursor = self.selections.newest::<Point>(cx).head();
17440        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17441        let blame_entry = blame
17442            .update(cx, |blame, cx| {
17443                blame
17444                    .blame_for_rows(
17445                        &[RowInfo {
17446                            buffer_id: Some(buffer.remote_id()),
17447                            buffer_row: Some(point.row),
17448                            ..Default::default()
17449                        }],
17450                        cx,
17451                    )
17452                    .next()
17453            })
17454            .flatten()?;
17455        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17456        let repo = blame.read(cx).repository(cx)?;
17457        let workspace = self.workspace()?.downgrade();
17458        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17459        None
17460    }
17461
17462    pub fn git_blame_inline_enabled(&self) -> bool {
17463        self.git_blame_inline_enabled
17464    }
17465
17466    pub fn toggle_selection_menu(
17467        &mut self,
17468        _: &ToggleSelectionMenu,
17469        _: &mut Window,
17470        cx: &mut Context<Self>,
17471    ) {
17472        self.show_selection_menu = self
17473            .show_selection_menu
17474            .map(|show_selections_menu| !show_selections_menu)
17475            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17476
17477        cx.notify();
17478    }
17479
17480    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17481        self.show_selection_menu
17482            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17483    }
17484
17485    fn start_git_blame(
17486        &mut self,
17487        user_triggered: bool,
17488        window: &mut Window,
17489        cx: &mut Context<Self>,
17490    ) {
17491        if let Some(project) = self.project.as_ref() {
17492            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17493                return;
17494            };
17495
17496            if buffer.read(cx).file().is_none() {
17497                return;
17498            }
17499
17500            let focused = self.focus_handle(cx).contains_focused(window, cx);
17501
17502            let project = project.clone();
17503            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17504            self.blame_subscription =
17505                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17506            self.blame = Some(blame);
17507        }
17508    }
17509
17510    fn toggle_git_blame_inline_internal(
17511        &mut self,
17512        user_triggered: bool,
17513        window: &mut Window,
17514        cx: &mut Context<Self>,
17515    ) {
17516        if self.git_blame_inline_enabled {
17517            self.git_blame_inline_enabled = false;
17518            self.show_git_blame_inline = false;
17519            self.show_git_blame_inline_delay_task.take();
17520        } else {
17521            self.git_blame_inline_enabled = true;
17522            self.start_git_blame_inline(user_triggered, window, cx);
17523        }
17524
17525        cx.notify();
17526    }
17527
17528    fn start_git_blame_inline(
17529        &mut self,
17530        user_triggered: bool,
17531        window: &mut Window,
17532        cx: &mut Context<Self>,
17533    ) {
17534        self.start_git_blame(user_triggered, window, cx);
17535
17536        if ProjectSettings::get_global(cx)
17537            .git
17538            .inline_blame_delay()
17539            .is_some()
17540        {
17541            self.start_inline_blame_timer(window, cx);
17542        } else {
17543            self.show_git_blame_inline = true
17544        }
17545    }
17546
17547    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17548        self.blame.as_ref()
17549    }
17550
17551    pub fn show_git_blame_gutter(&self) -> bool {
17552        self.show_git_blame_gutter
17553    }
17554
17555    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17556        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17557    }
17558
17559    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17560        self.show_git_blame_inline
17561            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17562            && !self.newest_selection_head_on_empty_line(cx)
17563            && self.has_blame_entries(cx)
17564    }
17565
17566    fn has_blame_entries(&self, cx: &App) -> bool {
17567        self.blame()
17568            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17569    }
17570
17571    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17572        let cursor_anchor = self.selections.newest_anchor().head();
17573
17574        let snapshot = self.buffer.read(cx).snapshot(cx);
17575        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17576
17577        snapshot.line_len(buffer_row) == 0
17578    }
17579
17580    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17581        let buffer_and_selection = maybe!({
17582            let selection = self.selections.newest::<Point>(cx);
17583            let selection_range = selection.range();
17584
17585            let multi_buffer = self.buffer().read(cx);
17586            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17587            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17588
17589            let (buffer, range, _) = if selection.reversed {
17590                buffer_ranges.first()
17591            } else {
17592                buffer_ranges.last()
17593            }?;
17594
17595            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17596                ..text::ToPoint::to_point(&range.end, &buffer).row;
17597            Some((
17598                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17599                selection,
17600            ))
17601        });
17602
17603        let Some((buffer, selection)) = buffer_and_selection else {
17604            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17605        };
17606
17607        let Some(project) = self.project.as_ref() else {
17608            return Task::ready(Err(anyhow!("editor does not have project")));
17609        };
17610
17611        project.update(cx, |project, cx| {
17612            project.get_permalink_to_line(&buffer, selection, cx)
17613        })
17614    }
17615
17616    pub fn copy_permalink_to_line(
17617        &mut self,
17618        _: &CopyPermalinkToLine,
17619        window: &mut Window,
17620        cx: &mut Context<Self>,
17621    ) {
17622        let permalink_task = self.get_permalink_to_line(cx);
17623        let workspace = self.workspace();
17624
17625        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17626            Ok(permalink) => {
17627                cx.update(|_, cx| {
17628                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17629                })
17630                .ok();
17631            }
17632            Err(err) => {
17633                let message = format!("Failed to copy permalink: {err}");
17634
17635                anyhow::Result::<()>::Err(err).log_err();
17636
17637                if let Some(workspace) = workspace {
17638                    workspace
17639                        .update_in(cx, |workspace, _, cx| {
17640                            struct CopyPermalinkToLine;
17641
17642                            workspace.show_toast(
17643                                Toast::new(
17644                                    NotificationId::unique::<CopyPermalinkToLine>(),
17645                                    message,
17646                                ),
17647                                cx,
17648                            )
17649                        })
17650                        .ok();
17651                }
17652            }
17653        })
17654        .detach();
17655    }
17656
17657    pub fn copy_file_location(
17658        &mut self,
17659        _: &CopyFileLocation,
17660        _: &mut Window,
17661        cx: &mut Context<Self>,
17662    ) {
17663        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17664        if let Some(file) = self.target_file(cx) {
17665            if let Some(path) = file.path().to_str() {
17666                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17667            }
17668        }
17669    }
17670
17671    pub fn open_permalink_to_line(
17672        &mut self,
17673        _: &OpenPermalinkToLine,
17674        window: &mut Window,
17675        cx: &mut Context<Self>,
17676    ) {
17677        let permalink_task = self.get_permalink_to_line(cx);
17678        let workspace = self.workspace();
17679
17680        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17681            Ok(permalink) => {
17682                cx.update(|_, cx| {
17683                    cx.open_url(permalink.as_ref());
17684                })
17685                .ok();
17686            }
17687            Err(err) => {
17688                let message = format!("Failed to open permalink: {err}");
17689
17690                anyhow::Result::<()>::Err(err).log_err();
17691
17692                if let Some(workspace) = workspace {
17693                    workspace
17694                        .update(cx, |workspace, cx| {
17695                            struct OpenPermalinkToLine;
17696
17697                            workspace.show_toast(
17698                                Toast::new(
17699                                    NotificationId::unique::<OpenPermalinkToLine>(),
17700                                    message,
17701                                ),
17702                                cx,
17703                            )
17704                        })
17705                        .ok();
17706                }
17707            }
17708        })
17709        .detach();
17710    }
17711
17712    pub fn insert_uuid_v4(
17713        &mut self,
17714        _: &InsertUuidV4,
17715        window: &mut Window,
17716        cx: &mut Context<Self>,
17717    ) {
17718        self.insert_uuid(UuidVersion::V4, window, cx);
17719    }
17720
17721    pub fn insert_uuid_v7(
17722        &mut self,
17723        _: &InsertUuidV7,
17724        window: &mut Window,
17725        cx: &mut Context<Self>,
17726    ) {
17727        self.insert_uuid(UuidVersion::V7, window, cx);
17728    }
17729
17730    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17731        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17732        self.transact(window, cx, |this, window, cx| {
17733            let edits = this
17734                .selections
17735                .all::<Point>(cx)
17736                .into_iter()
17737                .map(|selection| {
17738                    let uuid = match version {
17739                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17740                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17741                    };
17742
17743                    (selection.range(), uuid.to_string())
17744                });
17745            this.edit(edits, cx);
17746            this.refresh_inline_completion(true, false, window, cx);
17747        });
17748    }
17749
17750    pub fn open_selections_in_multibuffer(
17751        &mut self,
17752        _: &OpenSelectionsInMultibuffer,
17753        window: &mut Window,
17754        cx: &mut Context<Self>,
17755    ) {
17756        let multibuffer = self.buffer.read(cx);
17757
17758        let Some(buffer) = multibuffer.as_singleton() else {
17759            return;
17760        };
17761
17762        let Some(workspace) = self.workspace() else {
17763            return;
17764        };
17765
17766        let locations = self
17767            .selections
17768            .disjoint_anchors()
17769            .iter()
17770            .map(|selection| {
17771                let range = if selection.reversed {
17772                    selection.end.text_anchor..selection.start.text_anchor
17773                } else {
17774                    selection.start.text_anchor..selection.end.text_anchor
17775                };
17776                Location {
17777                    buffer: buffer.clone(),
17778                    range,
17779                }
17780            })
17781            .collect::<Vec<_>>();
17782
17783        let title = multibuffer.title(cx).to_string();
17784
17785        cx.spawn_in(window, async move |_, cx| {
17786            workspace.update_in(cx, |workspace, window, cx| {
17787                Self::open_locations_in_multibuffer(
17788                    workspace,
17789                    locations,
17790                    format!("Selections for '{title}'"),
17791                    false,
17792                    MultibufferSelectionMode::All,
17793                    window,
17794                    cx,
17795                );
17796            })
17797        })
17798        .detach();
17799    }
17800
17801    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17802    /// last highlight added will be used.
17803    ///
17804    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17805    pub fn highlight_rows<T: 'static>(
17806        &mut self,
17807        range: Range<Anchor>,
17808        color: Hsla,
17809        options: RowHighlightOptions,
17810        cx: &mut Context<Self>,
17811    ) {
17812        let snapshot = self.buffer().read(cx).snapshot(cx);
17813        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17814        let ix = row_highlights.binary_search_by(|highlight| {
17815            Ordering::Equal
17816                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17817                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17818        });
17819
17820        if let Err(mut ix) = ix {
17821            let index = post_inc(&mut self.highlight_order);
17822
17823            // If this range intersects with the preceding highlight, then merge it with
17824            // the preceding highlight. Otherwise insert a new highlight.
17825            let mut merged = false;
17826            if ix > 0 {
17827                let prev_highlight = &mut row_highlights[ix - 1];
17828                if prev_highlight
17829                    .range
17830                    .end
17831                    .cmp(&range.start, &snapshot)
17832                    .is_ge()
17833                {
17834                    ix -= 1;
17835                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17836                        prev_highlight.range.end = range.end;
17837                    }
17838                    merged = true;
17839                    prev_highlight.index = index;
17840                    prev_highlight.color = color;
17841                    prev_highlight.options = options;
17842                }
17843            }
17844
17845            if !merged {
17846                row_highlights.insert(
17847                    ix,
17848                    RowHighlight {
17849                        range: range.clone(),
17850                        index,
17851                        color,
17852                        options,
17853                        type_id: TypeId::of::<T>(),
17854                    },
17855                );
17856            }
17857
17858            // If any of the following highlights intersect with this one, merge them.
17859            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17860                let highlight = &row_highlights[ix];
17861                if next_highlight
17862                    .range
17863                    .start
17864                    .cmp(&highlight.range.end, &snapshot)
17865                    .is_le()
17866                {
17867                    if next_highlight
17868                        .range
17869                        .end
17870                        .cmp(&highlight.range.end, &snapshot)
17871                        .is_gt()
17872                    {
17873                        row_highlights[ix].range.end = next_highlight.range.end;
17874                    }
17875                    row_highlights.remove(ix + 1);
17876                } else {
17877                    break;
17878                }
17879            }
17880        }
17881    }
17882
17883    /// Remove any highlighted row ranges of the given type that intersect the
17884    /// given ranges.
17885    pub fn remove_highlighted_rows<T: 'static>(
17886        &mut self,
17887        ranges_to_remove: Vec<Range<Anchor>>,
17888        cx: &mut Context<Self>,
17889    ) {
17890        let snapshot = self.buffer().read(cx).snapshot(cx);
17891        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17892        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17893        row_highlights.retain(|highlight| {
17894            while let Some(range_to_remove) = ranges_to_remove.peek() {
17895                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17896                    Ordering::Less | Ordering::Equal => {
17897                        ranges_to_remove.next();
17898                    }
17899                    Ordering::Greater => {
17900                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17901                            Ordering::Less | Ordering::Equal => {
17902                                return false;
17903                            }
17904                            Ordering::Greater => break,
17905                        }
17906                    }
17907                }
17908            }
17909
17910            true
17911        })
17912    }
17913
17914    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17915    pub fn clear_row_highlights<T: 'static>(&mut self) {
17916        self.highlighted_rows.remove(&TypeId::of::<T>());
17917    }
17918
17919    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17920    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17921        self.highlighted_rows
17922            .get(&TypeId::of::<T>())
17923            .map_or(&[] as &[_], |vec| vec.as_slice())
17924            .iter()
17925            .map(|highlight| (highlight.range.clone(), highlight.color))
17926    }
17927
17928    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17929    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17930    /// Allows to ignore certain kinds of highlights.
17931    pub fn highlighted_display_rows(
17932        &self,
17933        window: &mut Window,
17934        cx: &mut App,
17935    ) -> BTreeMap<DisplayRow, LineHighlight> {
17936        let snapshot = self.snapshot(window, cx);
17937        let mut used_highlight_orders = HashMap::default();
17938        self.highlighted_rows
17939            .iter()
17940            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17941            .fold(
17942                BTreeMap::<DisplayRow, LineHighlight>::new(),
17943                |mut unique_rows, highlight| {
17944                    let start = highlight.range.start.to_display_point(&snapshot);
17945                    let end = highlight.range.end.to_display_point(&snapshot);
17946                    let start_row = start.row().0;
17947                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
17948                        && end.column() == 0
17949                    {
17950                        end.row().0.saturating_sub(1)
17951                    } else {
17952                        end.row().0
17953                    };
17954                    for row in start_row..=end_row {
17955                        let used_index =
17956                            used_highlight_orders.entry(row).or_insert(highlight.index);
17957                        if highlight.index >= *used_index {
17958                            *used_index = highlight.index;
17959                            unique_rows.insert(
17960                                DisplayRow(row),
17961                                LineHighlight {
17962                                    include_gutter: highlight.options.include_gutter,
17963                                    border: None,
17964                                    background: highlight.color.into(),
17965                                    type_id: Some(highlight.type_id),
17966                                },
17967                            );
17968                        }
17969                    }
17970                    unique_rows
17971                },
17972            )
17973    }
17974
17975    pub fn highlighted_display_row_for_autoscroll(
17976        &self,
17977        snapshot: &DisplaySnapshot,
17978    ) -> Option<DisplayRow> {
17979        self.highlighted_rows
17980            .values()
17981            .flat_map(|highlighted_rows| highlighted_rows.iter())
17982            .filter_map(|highlight| {
17983                if highlight.options.autoscroll {
17984                    Some(highlight.range.start.to_display_point(snapshot).row())
17985                } else {
17986                    None
17987                }
17988            })
17989            .min()
17990    }
17991
17992    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
17993        self.highlight_background::<SearchWithinRange>(
17994            ranges,
17995            |colors| colors.editor_document_highlight_read_background,
17996            cx,
17997        )
17998    }
17999
18000    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18001        self.breadcrumb_header = Some(new_header);
18002    }
18003
18004    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18005        self.clear_background_highlights::<SearchWithinRange>(cx);
18006    }
18007
18008    pub fn highlight_background<T: 'static>(
18009        &mut self,
18010        ranges: &[Range<Anchor>],
18011        color_fetcher: fn(&ThemeColors) -> Hsla,
18012        cx: &mut Context<Self>,
18013    ) {
18014        self.background_highlights
18015            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18016        self.scrollbar_marker_state.dirty = true;
18017        cx.notify();
18018    }
18019
18020    pub fn clear_background_highlights<T: 'static>(
18021        &mut self,
18022        cx: &mut Context<Self>,
18023    ) -> Option<BackgroundHighlight> {
18024        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18025        if !text_highlights.1.is_empty() {
18026            self.scrollbar_marker_state.dirty = true;
18027            cx.notify();
18028        }
18029        Some(text_highlights)
18030    }
18031
18032    pub fn highlight_gutter<T: 'static>(
18033        &mut self,
18034        ranges: &[Range<Anchor>],
18035        color_fetcher: fn(&App) -> Hsla,
18036        cx: &mut Context<Self>,
18037    ) {
18038        self.gutter_highlights
18039            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18040        cx.notify();
18041    }
18042
18043    pub fn clear_gutter_highlights<T: 'static>(
18044        &mut self,
18045        cx: &mut Context<Self>,
18046    ) -> Option<GutterHighlight> {
18047        cx.notify();
18048        self.gutter_highlights.remove(&TypeId::of::<T>())
18049    }
18050
18051    #[cfg(feature = "test-support")]
18052    pub fn all_text_background_highlights(
18053        &self,
18054        window: &mut Window,
18055        cx: &mut Context<Self>,
18056    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18057        let snapshot = self.snapshot(window, cx);
18058        let buffer = &snapshot.buffer_snapshot;
18059        let start = buffer.anchor_before(0);
18060        let end = buffer.anchor_after(buffer.len());
18061        let theme = cx.theme().colors();
18062        self.background_highlights_in_range(start..end, &snapshot, theme)
18063    }
18064
18065    #[cfg(feature = "test-support")]
18066    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18067        let snapshot = self.buffer().read(cx).snapshot(cx);
18068
18069        let highlights = self
18070            .background_highlights
18071            .get(&TypeId::of::<items::BufferSearchHighlights>());
18072
18073        if let Some((_color, ranges)) = highlights {
18074            ranges
18075                .iter()
18076                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18077                .collect_vec()
18078        } else {
18079            vec![]
18080        }
18081    }
18082
18083    fn document_highlights_for_position<'a>(
18084        &'a self,
18085        position: Anchor,
18086        buffer: &'a MultiBufferSnapshot,
18087    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18088        let read_highlights = self
18089            .background_highlights
18090            .get(&TypeId::of::<DocumentHighlightRead>())
18091            .map(|h| &h.1);
18092        let write_highlights = self
18093            .background_highlights
18094            .get(&TypeId::of::<DocumentHighlightWrite>())
18095            .map(|h| &h.1);
18096        let left_position = position.bias_left(buffer);
18097        let right_position = position.bias_right(buffer);
18098        read_highlights
18099            .into_iter()
18100            .chain(write_highlights)
18101            .flat_map(move |ranges| {
18102                let start_ix = match ranges.binary_search_by(|probe| {
18103                    let cmp = probe.end.cmp(&left_position, buffer);
18104                    if cmp.is_ge() {
18105                        Ordering::Greater
18106                    } else {
18107                        Ordering::Less
18108                    }
18109                }) {
18110                    Ok(i) | Err(i) => i,
18111                };
18112
18113                ranges[start_ix..]
18114                    .iter()
18115                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18116            })
18117    }
18118
18119    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18120        self.background_highlights
18121            .get(&TypeId::of::<T>())
18122            .map_or(false, |(_, highlights)| !highlights.is_empty())
18123    }
18124
18125    pub fn background_highlights_in_range(
18126        &self,
18127        search_range: Range<Anchor>,
18128        display_snapshot: &DisplaySnapshot,
18129        theme: &ThemeColors,
18130    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18131        let mut results = Vec::new();
18132        for (color_fetcher, ranges) in self.background_highlights.values() {
18133            let color = color_fetcher(theme);
18134            let start_ix = match ranges.binary_search_by(|probe| {
18135                let cmp = probe
18136                    .end
18137                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18138                if cmp.is_gt() {
18139                    Ordering::Greater
18140                } else {
18141                    Ordering::Less
18142                }
18143            }) {
18144                Ok(i) | Err(i) => i,
18145            };
18146            for range in &ranges[start_ix..] {
18147                if range
18148                    .start
18149                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18150                    .is_ge()
18151                {
18152                    break;
18153                }
18154
18155                let start = range.start.to_display_point(display_snapshot);
18156                let end = range.end.to_display_point(display_snapshot);
18157                results.push((start..end, color))
18158            }
18159        }
18160        results
18161    }
18162
18163    pub fn background_highlight_row_ranges<T: 'static>(
18164        &self,
18165        search_range: Range<Anchor>,
18166        display_snapshot: &DisplaySnapshot,
18167        count: usize,
18168    ) -> Vec<RangeInclusive<DisplayPoint>> {
18169        let mut results = Vec::new();
18170        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18171            return vec![];
18172        };
18173
18174        let start_ix = match ranges.binary_search_by(|probe| {
18175            let cmp = probe
18176                .end
18177                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18178            if cmp.is_gt() {
18179                Ordering::Greater
18180            } else {
18181                Ordering::Less
18182            }
18183        }) {
18184            Ok(i) | Err(i) => i,
18185        };
18186        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18187            if let (Some(start_display), Some(end_display)) = (start, end) {
18188                results.push(
18189                    start_display.to_display_point(display_snapshot)
18190                        ..=end_display.to_display_point(display_snapshot),
18191                );
18192            }
18193        };
18194        let mut start_row: Option<Point> = None;
18195        let mut end_row: Option<Point> = None;
18196        if ranges.len() > count {
18197            return Vec::new();
18198        }
18199        for range in &ranges[start_ix..] {
18200            if range
18201                .start
18202                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18203                .is_ge()
18204            {
18205                break;
18206            }
18207            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18208            if let Some(current_row) = &end_row {
18209                if end.row == current_row.row {
18210                    continue;
18211                }
18212            }
18213            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18214            if start_row.is_none() {
18215                assert_eq!(end_row, None);
18216                start_row = Some(start);
18217                end_row = Some(end);
18218                continue;
18219            }
18220            if let Some(current_end) = end_row.as_mut() {
18221                if start.row > current_end.row + 1 {
18222                    push_region(start_row, end_row);
18223                    start_row = Some(start);
18224                    end_row = Some(end);
18225                } else {
18226                    // Merge two hunks.
18227                    *current_end = end;
18228                }
18229            } else {
18230                unreachable!();
18231            }
18232        }
18233        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18234        push_region(start_row, end_row);
18235        results
18236    }
18237
18238    pub fn gutter_highlights_in_range(
18239        &self,
18240        search_range: Range<Anchor>,
18241        display_snapshot: &DisplaySnapshot,
18242        cx: &App,
18243    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18244        let mut results = Vec::new();
18245        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18246            let color = color_fetcher(cx);
18247            let start_ix = match ranges.binary_search_by(|probe| {
18248                let cmp = probe
18249                    .end
18250                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18251                if cmp.is_gt() {
18252                    Ordering::Greater
18253                } else {
18254                    Ordering::Less
18255                }
18256            }) {
18257                Ok(i) | Err(i) => i,
18258            };
18259            for range in &ranges[start_ix..] {
18260                if range
18261                    .start
18262                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18263                    .is_ge()
18264                {
18265                    break;
18266                }
18267
18268                let start = range.start.to_display_point(display_snapshot);
18269                let end = range.end.to_display_point(display_snapshot);
18270                results.push((start..end, color))
18271            }
18272        }
18273        results
18274    }
18275
18276    /// Get the text ranges corresponding to the redaction query
18277    pub fn redacted_ranges(
18278        &self,
18279        search_range: Range<Anchor>,
18280        display_snapshot: &DisplaySnapshot,
18281        cx: &App,
18282    ) -> Vec<Range<DisplayPoint>> {
18283        display_snapshot
18284            .buffer_snapshot
18285            .redacted_ranges(search_range, |file| {
18286                if let Some(file) = file {
18287                    file.is_private()
18288                        && EditorSettings::get(
18289                            Some(SettingsLocation {
18290                                worktree_id: file.worktree_id(cx),
18291                                path: file.path().as_ref(),
18292                            }),
18293                            cx,
18294                        )
18295                        .redact_private_values
18296                } else {
18297                    false
18298                }
18299            })
18300            .map(|range| {
18301                range.start.to_display_point(display_snapshot)
18302                    ..range.end.to_display_point(display_snapshot)
18303            })
18304            .collect()
18305    }
18306
18307    pub fn highlight_text<T: 'static>(
18308        &mut self,
18309        ranges: Vec<Range<Anchor>>,
18310        style: HighlightStyle,
18311        cx: &mut Context<Self>,
18312    ) {
18313        self.display_map.update(cx, |map, _| {
18314            map.highlight_text(TypeId::of::<T>(), ranges, style)
18315        });
18316        cx.notify();
18317    }
18318
18319    pub(crate) fn highlight_inlays<T: 'static>(
18320        &mut self,
18321        highlights: Vec<InlayHighlight>,
18322        style: HighlightStyle,
18323        cx: &mut Context<Self>,
18324    ) {
18325        self.display_map.update(cx, |map, _| {
18326            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18327        });
18328        cx.notify();
18329    }
18330
18331    pub fn text_highlights<'a, T: 'static>(
18332        &'a self,
18333        cx: &'a App,
18334    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18335        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18336    }
18337
18338    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18339        let cleared = self
18340            .display_map
18341            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18342        if cleared {
18343            cx.notify();
18344        }
18345    }
18346
18347    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18348        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18349            && self.focus_handle.is_focused(window)
18350    }
18351
18352    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18353        self.show_cursor_when_unfocused = is_enabled;
18354        cx.notify();
18355    }
18356
18357    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18358        cx.notify();
18359    }
18360
18361    fn on_debug_session_event(
18362        &mut self,
18363        _session: Entity<Session>,
18364        event: &SessionEvent,
18365        cx: &mut Context<Self>,
18366    ) {
18367        match event {
18368            SessionEvent::InvalidateInlineValue => {
18369                self.refresh_inline_values(cx);
18370            }
18371            _ => {}
18372        }
18373    }
18374
18375    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18376        let Some(project) = self.project.clone() else {
18377            return;
18378        };
18379
18380        if !self.inline_value_cache.enabled {
18381            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18382            self.splice_inlays(&inlays, Vec::new(), cx);
18383            return;
18384        }
18385
18386        let current_execution_position = self
18387            .highlighted_rows
18388            .get(&TypeId::of::<ActiveDebugLine>())
18389            .and_then(|lines| lines.last().map(|line| line.range.start));
18390
18391        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18392            let inline_values = editor
18393                .update(cx, |editor, cx| {
18394                    let Some(current_execution_position) = current_execution_position else {
18395                        return Some(Task::ready(Ok(Vec::new())));
18396                    };
18397
18398                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18399                        let snapshot = buffer.snapshot(cx);
18400
18401                        let excerpt = snapshot.excerpt_containing(
18402                            current_execution_position..current_execution_position,
18403                        )?;
18404
18405                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18406                    })?;
18407
18408                    let range =
18409                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18410
18411                    project.inline_values(buffer, range, cx)
18412                })
18413                .ok()
18414                .flatten()?
18415                .await
18416                .context("refreshing debugger inlays")
18417                .log_err()?;
18418
18419            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18420
18421            for (buffer_id, inline_value) in inline_values
18422                .into_iter()
18423                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18424            {
18425                buffer_inline_values
18426                    .entry(buffer_id)
18427                    .or_default()
18428                    .push(inline_value);
18429            }
18430
18431            editor
18432                .update(cx, |editor, cx| {
18433                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18434                    let mut new_inlays = Vec::default();
18435
18436                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18437                        let buffer_id = buffer_snapshot.remote_id();
18438                        buffer_inline_values
18439                            .get(&buffer_id)
18440                            .into_iter()
18441                            .flatten()
18442                            .for_each(|hint| {
18443                                let inlay = Inlay::debugger_hint(
18444                                    post_inc(&mut editor.next_inlay_id),
18445                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18446                                    hint.text(),
18447                                );
18448
18449                                new_inlays.push(inlay);
18450                            });
18451                    }
18452
18453                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18454                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18455
18456                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18457                })
18458                .ok()?;
18459            Some(())
18460        });
18461    }
18462
18463    fn on_buffer_event(
18464        &mut self,
18465        multibuffer: &Entity<MultiBuffer>,
18466        event: &multi_buffer::Event,
18467        window: &mut Window,
18468        cx: &mut Context<Self>,
18469    ) {
18470        match event {
18471            multi_buffer::Event::Edited {
18472                singleton_buffer_edited,
18473                edited_buffer: buffer_edited,
18474            } => {
18475                self.scrollbar_marker_state.dirty = true;
18476                self.active_indent_guides_state.dirty = true;
18477                self.refresh_active_diagnostics(cx);
18478                self.refresh_code_actions(window, cx);
18479                self.refresh_selected_text_highlights(true, window, cx);
18480                refresh_matching_bracket_highlights(self, window, cx);
18481                if self.has_active_inline_completion() {
18482                    self.update_visible_inline_completion(window, cx);
18483                }
18484                if let Some(buffer) = buffer_edited {
18485                    let buffer_id = buffer.read(cx).remote_id();
18486                    if !self.registered_buffers.contains_key(&buffer_id) {
18487                        if let Some(project) = self.project.as_ref() {
18488                            project.update(cx, |project, cx| {
18489                                self.registered_buffers.insert(
18490                                    buffer_id,
18491                                    project.register_buffer_with_language_servers(&buffer, cx),
18492                                );
18493                            })
18494                        }
18495                    }
18496                }
18497                cx.emit(EditorEvent::BufferEdited);
18498                cx.emit(SearchEvent::MatchesInvalidated);
18499                if *singleton_buffer_edited {
18500                    if let Some(project) = &self.project {
18501                        #[allow(clippy::mutable_key_type)]
18502                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18503                            multibuffer
18504                                .all_buffers()
18505                                .into_iter()
18506                                .filter_map(|buffer| {
18507                                    buffer.update(cx, |buffer, cx| {
18508                                        let language = buffer.language()?;
18509                                        let should_discard = project.update(cx, |project, cx| {
18510                                            project.is_local()
18511                                                && !project.has_language_servers_for(buffer, cx)
18512                                        });
18513                                        should_discard.not().then_some(language.clone())
18514                                    })
18515                                })
18516                                .collect::<HashSet<_>>()
18517                        });
18518                        if !languages_affected.is_empty() {
18519                            self.refresh_inlay_hints(
18520                                InlayHintRefreshReason::BufferEdited(languages_affected),
18521                                cx,
18522                            );
18523                        }
18524                    }
18525                }
18526
18527                let Some(project) = &self.project else { return };
18528                let (telemetry, is_via_ssh) = {
18529                    let project = project.read(cx);
18530                    let telemetry = project.client().telemetry().clone();
18531                    let is_via_ssh = project.is_via_ssh();
18532                    (telemetry, is_via_ssh)
18533                };
18534                refresh_linked_ranges(self, window, cx);
18535                telemetry.log_edit_event("editor", is_via_ssh);
18536            }
18537            multi_buffer::Event::ExcerptsAdded {
18538                buffer,
18539                predecessor,
18540                excerpts,
18541            } => {
18542                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18543                let buffer_id = buffer.read(cx).remote_id();
18544                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18545                    if let Some(project) = &self.project {
18546                        update_uncommitted_diff_for_buffer(
18547                            cx.entity(),
18548                            project,
18549                            [buffer.clone()],
18550                            self.buffer.clone(),
18551                            cx,
18552                        )
18553                        .detach();
18554                    }
18555                }
18556                cx.emit(EditorEvent::ExcerptsAdded {
18557                    buffer: buffer.clone(),
18558                    predecessor: *predecessor,
18559                    excerpts: excerpts.clone(),
18560                });
18561                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18562            }
18563            multi_buffer::Event::ExcerptsRemoved {
18564                ids,
18565                removed_buffer_ids,
18566            } => {
18567                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18568                let buffer = self.buffer.read(cx);
18569                self.registered_buffers
18570                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18571                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18572                cx.emit(EditorEvent::ExcerptsRemoved {
18573                    ids: ids.clone(),
18574                    removed_buffer_ids: removed_buffer_ids.clone(),
18575                })
18576            }
18577            multi_buffer::Event::ExcerptsEdited {
18578                excerpt_ids,
18579                buffer_ids,
18580            } => {
18581                self.display_map.update(cx, |map, cx| {
18582                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18583                });
18584                cx.emit(EditorEvent::ExcerptsEdited {
18585                    ids: excerpt_ids.clone(),
18586                })
18587            }
18588            multi_buffer::Event::ExcerptsExpanded { ids } => {
18589                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18590                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18591            }
18592            multi_buffer::Event::Reparsed(buffer_id) => {
18593                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18594                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18595
18596                cx.emit(EditorEvent::Reparsed(*buffer_id));
18597            }
18598            multi_buffer::Event::DiffHunksToggled => {
18599                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18600            }
18601            multi_buffer::Event::LanguageChanged(buffer_id) => {
18602                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18603                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18604                cx.emit(EditorEvent::Reparsed(*buffer_id));
18605                cx.notify();
18606            }
18607            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18608            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18609            multi_buffer::Event::FileHandleChanged
18610            | multi_buffer::Event::Reloaded
18611            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18612            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18613            multi_buffer::Event::DiagnosticsUpdated => {
18614                self.refresh_active_diagnostics(cx);
18615                self.refresh_inline_diagnostics(true, window, cx);
18616                self.scrollbar_marker_state.dirty = true;
18617                cx.notify();
18618            }
18619            _ => {}
18620        };
18621    }
18622
18623    pub fn start_temporary_diff_override(&mut self) {
18624        self.load_diff_task.take();
18625        self.temporary_diff_override = true;
18626    }
18627
18628    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18629        self.temporary_diff_override = false;
18630        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18631        self.buffer.update(cx, |buffer, cx| {
18632            buffer.set_all_diff_hunks_collapsed(cx);
18633        });
18634
18635        if let Some(project) = self.project.clone() {
18636            self.load_diff_task = Some(
18637                update_uncommitted_diff_for_buffer(
18638                    cx.entity(),
18639                    &project,
18640                    self.buffer.read(cx).all_buffers(),
18641                    self.buffer.clone(),
18642                    cx,
18643                )
18644                .shared(),
18645            );
18646        }
18647    }
18648
18649    fn on_display_map_changed(
18650        &mut self,
18651        _: Entity<DisplayMap>,
18652        _: &mut Window,
18653        cx: &mut Context<Self>,
18654    ) {
18655        cx.notify();
18656    }
18657
18658    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18659        let new_severity = if self.diagnostics_enabled() {
18660            EditorSettings::get_global(cx)
18661                .diagnostics_max_severity
18662                .unwrap_or(DiagnosticSeverity::Hint)
18663        } else {
18664            DiagnosticSeverity::Off
18665        };
18666        self.set_max_diagnostics_severity(new_severity, cx);
18667        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18668        self.update_edit_prediction_settings(cx);
18669        self.refresh_inline_completion(true, false, window, cx);
18670        self.refresh_inlay_hints(
18671            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18672                self.selections.newest_anchor().head(),
18673                &self.buffer.read(cx).snapshot(cx),
18674                cx,
18675            )),
18676            cx,
18677        );
18678
18679        let old_cursor_shape = self.cursor_shape;
18680
18681        {
18682            let editor_settings = EditorSettings::get_global(cx);
18683            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18684            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18685            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18686            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18687        }
18688
18689        if old_cursor_shape != self.cursor_shape {
18690            cx.emit(EditorEvent::CursorShapeChanged);
18691        }
18692
18693        let project_settings = ProjectSettings::get_global(cx);
18694        self.serialize_dirty_buffers =
18695            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18696
18697        if self.mode.is_full() {
18698            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18699            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18700            if self.show_inline_diagnostics != show_inline_diagnostics {
18701                self.show_inline_diagnostics = show_inline_diagnostics;
18702                self.refresh_inline_diagnostics(false, window, cx);
18703            }
18704
18705            if self.git_blame_inline_enabled != inline_blame_enabled {
18706                self.toggle_git_blame_inline_internal(false, window, cx);
18707            }
18708
18709            let minimap_settings = EditorSettings::get_global(cx).minimap;
18710            if self.minimap_visibility != MinimapVisibility::Disabled {
18711                if self.minimap_visibility.settings_visibility()
18712                    != minimap_settings.minimap_enabled()
18713                {
18714                    self.set_minimap_visibility(
18715                        MinimapVisibility::for_mode(self.mode(), cx),
18716                        window,
18717                        cx,
18718                    );
18719                } else if let Some(minimap_entity) = self.minimap.as_ref() {
18720                    minimap_entity.update(cx, |minimap_editor, cx| {
18721                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
18722                    })
18723                }
18724            }
18725        }
18726
18727        cx.notify();
18728    }
18729
18730    pub fn set_searchable(&mut self, searchable: bool) {
18731        self.searchable = searchable;
18732    }
18733
18734    pub fn searchable(&self) -> bool {
18735        self.searchable
18736    }
18737
18738    fn open_proposed_changes_editor(
18739        &mut self,
18740        _: &OpenProposedChangesEditor,
18741        window: &mut Window,
18742        cx: &mut Context<Self>,
18743    ) {
18744        let Some(workspace) = self.workspace() else {
18745            cx.propagate();
18746            return;
18747        };
18748
18749        let selections = self.selections.all::<usize>(cx);
18750        let multi_buffer = self.buffer.read(cx);
18751        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18752        let mut new_selections_by_buffer = HashMap::default();
18753        for selection in selections {
18754            for (buffer, range, _) in
18755                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18756            {
18757                let mut range = range.to_point(buffer);
18758                range.start.column = 0;
18759                range.end.column = buffer.line_len(range.end.row);
18760                new_selections_by_buffer
18761                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18762                    .or_insert(Vec::new())
18763                    .push(range)
18764            }
18765        }
18766
18767        let proposed_changes_buffers = new_selections_by_buffer
18768            .into_iter()
18769            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18770            .collect::<Vec<_>>();
18771        let proposed_changes_editor = cx.new(|cx| {
18772            ProposedChangesEditor::new(
18773                "Proposed changes",
18774                proposed_changes_buffers,
18775                self.project.clone(),
18776                window,
18777                cx,
18778            )
18779        });
18780
18781        window.defer(cx, move |window, cx| {
18782            workspace.update(cx, |workspace, cx| {
18783                workspace.active_pane().update(cx, |pane, cx| {
18784                    pane.add_item(
18785                        Box::new(proposed_changes_editor),
18786                        true,
18787                        true,
18788                        None,
18789                        window,
18790                        cx,
18791                    );
18792                });
18793            });
18794        });
18795    }
18796
18797    pub fn open_excerpts_in_split(
18798        &mut self,
18799        _: &OpenExcerptsSplit,
18800        window: &mut Window,
18801        cx: &mut Context<Self>,
18802    ) {
18803        self.open_excerpts_common(None, true, window, cx)
18804    }
18805
18806    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18807        self.open_excerpts_common(None, false, window, cx)
18808    }
18809
18810    fn open_excerpts_common(
18811        &mut self,
18812        jump_data: Option<JumpData>,
18813        split: bool,
18814        window: &mut Window,
18815        cx: &mut Context<Self>,
18816    ) {
18817        let Some(workspace) = self.workspace() else {
18818            cx.propagate();
18819            return;
18820        };
18821
18822        if self.buffer.read(cx).is_singleton() {
18823            cx.propagate();
18824            return;
18825        }
18826
18827        let mut new_selections_by_buffer = HashMap::default();
18828        match &jump_data {
18829            Some(JumpData::MultiBufferPoint {
18830                excerpt_id,
18831                position,
18832                anchor,
18833                line_offset_from_top,
18834            }) => {
18835                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18836                if let Some(buffer) = multi_buffer_snapshot
18837                    .buffer_id_for_excerpt(*excerpt_id)
18838                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18839                {
18840                    let buffer_snapshot = buffer.read(cx).snapshot();
18841                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18842                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18843                    } else {
18844                        buffer_snapshot.clip_point(*position, Bias::Left)
18845                    };
18846                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18847                    new_selections_by_buffer.insert(
18848                        buffer,
18849                        (
18850                            vec![jump_to_offset..jump_to_offset],
18851                            Some(*line_offset_from_top),
18852                        ),
18853                    );
18854                }
18855            }
18856            Some(JumpData::MultiBufferRow {
18857                row,
18858                line_offset_from_top,
18859            }) => {
18860                let point = MultiBufferPoint::new(row.0, 0);
18861                if let Some((buffer, buffer_point, _)) =
18862                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18863                {
18864                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18865                    new_selections_by_buffer
18866                        .entry(buffer)
18867                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18868                        .0
18869                        .push(buffer_offset..buffer_offset)
18870                }
18871            }
18872            None => {
18873                let selections = self.selections.all::<usize>(cx);
18874                let multi_buffer = self.buffer.read(cx);
18875                for selection in selections {
18876                    for (snapshot, range, _, anchor) in multi_buffer
18877                        .snapshot(cx)
18878                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18879                    {
18880                        if let Some(anchor) = anchor {
18881                            // selection is in a deleted hunk
18882                            let Some(buffer_id) = anchor.buffer_id else {
18883                                continue;
18884                            };
18885                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18886                                continue;
18887                            };
18888                            let offset = text::ToOffset::to_offset(
18889                                &anchor.text_anchor,
18890                                &buffer_handle.read(cx).snapshot(),
18891                            );
18892                            let range = offset..offset;
18893                            new_selections_by_buffer
18894                                .entry(buffer_handle)
18895                                .or_insert((Vec::new(), None))
18896                                .0
18897                                .push(range)
18898                        } else {
18899                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18900                            else {
18901                                continue;
18902                            };
18903                            new_selections_by_buffer
18904                                .entry(buffer_handle)
18905                                .or_insert((Vec::new(), None))
18906                                .0
18907                                .push(range)
18908                        }
18909                    }
18910                }
18911            }
18912        }
18913
18914        new_selections_by_buffer
18915            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18916
18917        if new_selections_by_buffer.is_empty() {
18918            return;
18919        }
18920
18921        // We defer the pane interaction because we ourselves are a workspace item
18922        // and activating a new item causes the pane to call a method on us reentrantly,
18923        // which panics if we're on the stack.
18924        window.defer(cx, move |window, cx| {
18925            workspace.update(cx, |workspace, cx| {
18926                let pane = if split {
18927                    workspace.adjacent_pane(window, cx)
18928                } else {
18929                    workspace.active_pane().clone()
18930                };
18931
18932                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
18933                    let editor = buffer
18934                        .read(cx)
18935                        .file()
18936                        .is_none()
18937                        .then(|| {
18938                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
18939                            // so `workspace.open_project_item` will never find them, always opening a new editor.
18940                            // Instead, we try to activate the existing editor in the pane first.
18941                            let (editor, pane_item_index) =
18942                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
18943                                    let editor = item.downcast::<Editor>()?;
18944                                    let singleton_buffer =
18945                                        editor.read(cx).buffer().read(cx).as_singleton()?;
18946                                    if singleton_buffer == buffer {
18947                                        Some((editor, i))
18948                                    } else {
18949                                        None
18950                                    }
18951                                })?;
18952                            pane.update(cx, |pane, cx| {
18953                                pane.activate_item(pane_item_index, true, true, window, cx)
18954                            });
18955                            Some(editor)
18956                        })
18957                        .flatten()
18958                        .unwrap_or_else(|| {
18959                            workspace.open_project_item::<Self>(
18960                                pane.clone(),
18961                                buffer,
18962                                true,
18963                                true,
18964                                window,
18965                                cx,
18966                            )
18967                        });
18968
18969                    editor.update(cx, |editor, cx| {
18970                        let autoscroll = match scroll_offset {
18971                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
18972                            None => Autoscroll::newest(),
18973                        };
18974                        let nav_history = editor.nav_history.take();
18975                        editor.change_selections(Some(autoscroll), window, cx, |s| {
18976                            s.select_ranges(ranges);
18977                        });
18978                        editor.nav_history = nav_history;
18979                    });
18980                }
18981            })
18982        });
18983    }
18984
18985    // For now, don't allow opening excerpts in buffers that aren't backed by
18986    // regular project files.
18987    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
18988        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
18989    }
18990
18991    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
18992        let snapshot = self.buffer.read(cx).read(cx);
18993        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
18994        Some(
18995            ranges
18996                .iter()
18997                .map(move |range| {
18998                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
18999                })
19000                .collect(),
19001        )
19002    }
19003
19004    fn selection_replacement_ranges(
19005        &self,
19006        range: Range<OffsetUtf16>,
19007        cx: &mut App,
19008    ) -> Vec<Range<OffsetUtf16>> {
19009        let selections = self.selections.all::<OffsetUtf16>(cx);
19010        let newest_selection = selections
19011            .iter()
19012            .max_by_key(|selection| selection.id)
19013            .unwrap();
19014        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19015        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19016        let snapshot = self.buffer.read(cx).read(cx);
19017        selections
19018            .into_iter()
19019            .map(|mut selection| {
19020                selection.start.0 =
19021                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19022                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19023                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19024                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19025            })
19026            .collect()
19027    }
19028
19029    fn report_editor_event(
19030        &self,
19031        event_type: &'static str,
19032        file_extension: Option<String>,
19033        cx: &App,
19034    ) {
19035        if cfg!(any(test, feature = "test-support")) {
19036            return;
19037        }
19038
19039        let Some(project) = &self.project else { return };
19040
19041        // If None, we are in a file without an extension
19042        let file = self
19043            .buffer
19044            .read(cx)
19045            .as_singleton()
19046            .and_then(|b| b.read(cx).file());
19047        let file_extension = file_extension.or(file
19048            .as_ref()
19049            .and_then(|file| Path::new(file.file_name(cx)).extension())
19050            .and_then(|e| e.to_str())
19051            .map(|a| a.to_string()));
19052
19053        let vim_mode = vim_enabled(cx);
19054
19055        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19056        let copilot_enabled = edit_predictions_provider
19057            == language::language_settings::EditPredictionProvider::Copilot;
19058        let copilot_enabled_for_language = self
19059            .buffer
19060            .read(cx)
19061            .language_settings(cx)
19062            .show_edit_predictions;
19063
19064        let project = project.read(cx);
19065        telemetry::event!(
19066            event_type,
19067            file_extension,
19068            vim_mode,
19069            copilot_enabled,
19070            copilot_enabled_for_language,
19071            edit_predictions_provider,
19072            is_via_ssh = project.is_via_ssh(),
19073        );
19074    }
19075
19076    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19077    /// with each line being an array of {text, highlight} objects.
19078    fn copy_highlight_json(
19079        &mut self,
19080        _: &CopyHighlightJson,
19081        window: &mut Window,
19082        cx: &mut Context<Self>,
19083    ) {
19084        #[derive(Serialize)]
19085        struct Chunk<'a> {
19086            text: String,
19087            highlight: Option<&'a str>,
19088        }
19089
19090        let snapshot = self.buffer.read(cx).snapshot(cx);
19091        let range = self
19092            .selected_text_range(false, window, cx)
19093            .and_then(|selection| {
19094                if selection.range.is_empty() {
19095                    None
19096                } else {
19097                    Some(selection.range)
19098                }
19099            })
19100            .unwrap_or_else(|| 0..snapshot.len());
19101
19102        let chunks = snapshot.chunks(range, true);
19103        let mut lines = Vec::new();
19104        let mut line: VecDeque<Chunk> = VecDeque::new();
19105
19106        let Some(style) = self.style.as_ref() else {
19107            return;
19108        };
19109
19110        for chunk in chunks {
19111            let highlight = chunk
19112                .syntax_highlight_id
19113                .and_then(|id| id.name(&style.syntax));
19114            let mut chunk_lines = chunk.text.split('\n').peekable();
19115            while let Some(text) = chunk_lines.next() {
19116                let mut merged_with_last_token = false;
19117                if let Some(last_token) = line.back_mut() {
19118                    if last_token.highlight == highlight {
19119                        last_token.text.push_str(text);
19120                        merged_with_last_token = true;
19121                    }
19122                }
19123
19124                if !merged_with_last_token {
19125                    line.push_back(Chunk {
19126                        text: text.into(),
19127                        highlight,
19128                    });
19129                }
19130
19131                if chunk_lines.peek().is_some() {
19132                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19133                        line.pop_front();
19134                    }
19135                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19136                        line.pop_back();
19137                    }
19138
19139                    lines.push(mem::take(&mut line));
19140                }
19141            }
19142        }
19143
19144        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19145            return;
19146        };
19147        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19148    }
19149
19150    pub fn open_context_menu(
19151        &mut self,
19152        _: &OpenContextMenu,
19153        window: &mut Window,
19154        cx: &mut Context<Self>,
19155    ) {
19156        self.request_autoscroll(Autoscroll::newest(), cx);
19157        let position = self.selections.newest_display(cx).start;
19158        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19159    }
19160
19161    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19162        &self.inlay_hint_cache
19163    }
19164
19165    pub fn replay_insert_event(
19166        &mut self,
19167        text: &str,
19168        relative_utf16_range: Option<Range<isize>>,
19169        window: &mut Window,
19170        cx: &mut Context<Self>,
19171    ) {
19172        if !self.input_enabled {
19173            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19174            return;
19175        }
19176        if let Some(relative_utf16_range) = relative_utf16_range {
19177            let selections = self.selections.all::<OffsetUtf16>(cx);
19178            self.change_selections(None, window, cx, |s| {
19179                let new_ranges = selections.into_iter().map(|range| {
19180                    let start = OffsetUtf16(
19181                        range
19182                            .head()
19183                            .0
19184                            .saturating_add_signed(relative_utf16_range.start),
19185                    );
19186                    let end = OffsetUtf16(
19187                        range
19188                            .head()
19189                            .0
19190                            .saturating_add_signed(relative_utf16_range.end),
19191                    );
19192                    start..end
19193                });
19194                s.select_ranges(new_ranges);
19195            });
19196        }
19197
19198        self.handle_input(text, window, cx);
19199    }
19200
19201    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19202        let Some(provider) = self.semantics_provider.as_ref() else {
19203            return false;
19204        };
19205
19206        let mut supports = false;
19207        self.buffer().update(cx, |this, cx| {
19208            this.for_each_buffer(|buffer| {
19209                supports |= provider.supports_inlay_hints(buffer, cx);
19210            });
19211        });
19212
19213        supports
19214    }
19215
19216    pub fn is_focused(&self, window: &Window) -> bool {
19217        self.focus_handle.is_focused(window)
19218    }
19219
19220    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19221        cx.emit(EditorEvent::Focused);
19222
19223        if let Some(descendant) = self
19224            .last_focused_descendant
19225            .take()
19226            .and_then(|descendant| descendant.upgrade())
19227        {
19228            window.focus(&descendant);
19229        } else {
19230            if let Some(blame) = self.blame.as_ref() {
19231                blame.update(cx, GitBlame::focus)
19232            }
19233
19234            self.blink_manager.update(cx, BlinkManager::enable);
19235            self.show_cursor_names(window, cx);
19236            self.buffer.update(cx, |buffer, cx| {
19237                buffer.finalize_last_transaction(cx);
19238                if self.leader_id.is_none() {
19239                    buffer.set_active_selections(
19240                        &self.selections.disjoint_anchors(),
19241                        self.selections.line_mode,
19242                        self.cursor_shape,
19243                        cx,
19244                    );
19245                }
19246            });
19247        }
19248    }
19249
19250    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19251        cx.emit(EditorEvent::FocusedIn)
19252    }
19253
19254    fn handle_focus_out(
19255        &mut self,
19256        event: FocusOutEvent,
19257        _window: &mut Window,
19258        cx: &mut Context<Self>,
19259    ) {
19260        if event.blurred != self.focus_handle {
19261            self.last_focused_descendant = Some(event.blurred);
19262        }
19263        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19264    }
19265
19266    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19267        self.blink_manager.update(cx, BlinkManager::disable);
19268        self.buffer
19269            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19270
19271        if let Some(blame) = self.blame.as_ref() {
19272            blame.update(cx, GitBlame::blur)
19273        }
19274        if !self.hover_state.focused(window, cx) {
19275            hide_hover(self, cx);
19276        }
19277        if !self
19278            .context_menu
19279            .borrow()
19280            .as_ref()
19281            .is_some_and(|context_menu| context_menu.focused(window, cx))
19282        {
19283            self.hide_context_menu(window, cx);
19284        }
19285        self.discard_inline_completion(false, cx);
19286        cx.emit(EditorEvent::Blurred);
19287        cx.notify();
19288    }
19289
19290    pub fn register_action<A: Action>(
19291        &mut self,
19292        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19293    ) -> Subscription {
19294        let id = self.next_editor_action_id.post_inc();
19295        let listener = Arc::new(listener);
19296        self.editor_actions.borrow_mut().insert(
19297            id,
19298            Box::new(move |window, _| {
19299                let listener = listener.clone();
19300                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19301                    let action = action.downcast_ref().unwrap();
19302                    if phase == DispatchPhase::Bubble {
19303                        listener(action, window, cx)
19304                    }
19305                })
19306            }),
19307        );
19308
19309        let editor_actions = self.editor_actions.clone();
19310        Subscription::new(move || {
19311            editor_actions.borrow_mut().remove(&id);
19312        })
19313    }
19314
19315    pub fn file_header_size(&self) -> u32 {
19316        FILE_HEADER_HEIGHT
19317    }
19318
19319    pub fn restore(
19320        &mut self,
19321        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19322        window: &mut Window,
19323        cx: &mut Context<Self>,
19324    ) {
19325        let workspace = self.workspace();
19326        let project = self.project.as_ref();
19327        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19328            let mut tasks = Vec::new();
19329            for (buffer_id, changes) in revert_changes {
19330                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19331                    buffer.update(cx, |buffer, cx| {
19332                        buffer.edit(
19333                            changes
19334                                .into_iter()
19335                                .map(|(range, text)| (range, text.to_string())),
19336                            None,
19337                            cx,
19338                        );
19339                    });
19340
19341                    if let Some(project) =
19342                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19343                    {
19344                        project.update(cx, |project, cx| {
19345                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19346                        })
19347                    }
19348                }
19349            }
19350            tasks
19351        });
19352        cx.spawn_in(window, async move |_, cx| {
19353            for (buffer, task) in save_tasks {
19354                let result = task.await;
19355                if result.is_err() {
19356                    let Some(path) = buffer
19357                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19358                        .ok()
19359                    else {
19360                        continue;
19361                    };
19362                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19363                        let Some(task) = cx
19364                            .update_window_entity(&workspace, |workspace, window, cx| {
19365                                workspace
19366                                    .open_path_preview(path, None, false, false, false, window, cx)
19367                            })
19368                            .ok()
19369                        else {
19370                            continue;
19371                        };
19372                        task.await.log_err();
19373                    }
19374                }
19375            }
19376        })
19377        .detach();
19378        self.change_selections(None, window, cx, |selections| selections.refresh());
19379    }
19380
19381    pub fn to_pixel_point(
19382        &self,
19383        source: multi_buffer::Anchor,
19384        editor_snapshot: &EditorSnapshot,
19385        window: &mut Window,
19386    ) -> Option<gpui::Point<Pixels>> {
19387        let source_point = source.to_display_point(editor_snapshot);
19388        self.display_to_pixel_point(source_point, editor_snapshot, window)
19389    }
19390
19391    pub fn display_to_pixel_point(
19392        &self,
19393        source: DisplayPoint,
19394        editor_snapshot: &EditorSnapshot,
19395        window: &mut Window,
19396    ) -> Option<gpui::Point<Pixels>> {
19397        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19398        let text_layout_details = self.text_layout_details(window);
19399        let scroll_top = text_layout_details
19400            .scroll_anchor
19401            .scroll_position(editor_snapshot)
19402            .y;
19403
19404        if source.row().as_f32() < scroll_top.floor() {
19405            return None;
19406        }
19407        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19408        let source_y = line_height * (source.row().as_f32() - scroll_top);
19409        Some(gpui::Point::new(source_x, source_y))
19410    }
19411
19412    pub fn has_visible_completions_menu(&self) -> bool {
19413        !self.edit_prediction_preview_is_active()
19414            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19415                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19416            })
19417    }
19418
19419    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19420        if self.mode.is_minimap() {
19421            return;
19422        }
19423        self.addons
19424            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19425    }
19426
19427    pub fn unregister_addon<T: Addon>(&mut self) {
19428        self.addons.remove(&std::any::TypeId::of::<T>());
19429    }
19430
19431    pub fn addon<T: Addon>(&self) -> Option<&T> {
19432        let type_id = std::any::TypeId::of::<T>();
19433        self.addons
19434            .get(&type_id)
19435            .and_then(|item| item.to_any().downcast_ref::<T>())
19436    }
19437
19438    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19439        let type_id = std::any::TypeId::of::<T>();
19440        self.addons
19441            .get_mut(&type_id)
19442            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19443    }
19444
19445    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19446        let text_layout_details = self.text_layout_details(window);
19447        let style = &text_layout_details.editor_style;
19448        let font_id = window.text_system().resolve_font(&style.text.font());
19449        let font_size = style.text.font_size.to_pixels(window.rem_size());
19450        let line_height = style.text.line_height_in_pixels(window.rem_size());
19451        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19452
19453        gpui::Size::new(em_width, line_height)
19454    }
19455
19456    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19457        self.load_diff_task.clone()
19458    }
19459
19460    fn read_metadata_from_db(
19461        &mut self,
19462        item_id: u64,
19463        workspace_id: WorkspaceId,
19464        window: &mut Window,
19465        cx: &mut Context<Editor>,
19466    ) {
19467        if self.is_singleton(cx)
19468            && !self.mode.is_minimap()
19469            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19470        {
19471            let buffer_snapshot = OnceCell::new();
19472
19473            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19474                if !folds.is_empty() {
19475                    let snapshot =
19476                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19477                    self.fold_ranges(
19478                        folds
19479                            .into_iter()
19480                            .map(|(start, end)| {
19481                                snapshot.clip_offset(start, Bias::Left)
19482                                    ..snapshot.clip_offset(end, Bias::Right)
19483                            })
19484                            .collect(),
19485                        false,
19486                        window,
19487                        cx,
19488                    );
19489                }
19490            }
19491
19492            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19493                if !selections.is_empty() {
19494                    let snapshot =
19495                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19496                    self.change_selections(None, window, cx, |s| {
19497                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19498                            snapshot.clip_offset(start, Bias::Left)
19499                                ..snapshot.clip_offset(end, Bias::Right)
19500                        }));
19501                    });
19502                }
19503            };
19504        }
19505
19506        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19507    }
19508}
19509
19510fn vim_enabled(cx: &App) -> bool {
19511    cx.global::<SettingsStore>()
19512        .raw_user_settings()
19513        .get("vim_mode")
19514        == Some(&serde_json::Value::Bool(true))
19515}
19516
19517// Consider user intent and default settings
19518fn choose_completion_range(
19519    completion: &Completion,
19520    intent: CompletionIntent,
19521    buffer: &Entity<Buffer>,
19522    cx: &mut Context<Editor>,
19523) -> Range<usize> {
19524    fn should_replace(
19525        completion: &Completion,
19526        insert_range: &Range<text::Anchor>,
19527        intent: CompletionIntent,
19528        completion_mode_setting: LspInsertMode,
19529        buffer: &Buffer,
19530    ) -> bool {
19531        // specific actions take precedence over settings
19532        match intent {
19533            CompletionIntent::CompleteWithInsert => return false,
19534            CompletionIntent::CompleteWithReplace => return true,
19535            CompletionIntent::Complete | CompletionIntent::Compose => {}
19536        }
19537
19538        match completion_mode_setting {
19539            LspInsertMode::Insert => false,
19540            LspInsertMode::Replace => true,
19541            LspInsertMode::ReplaceSubsequence => {
19542                let mut text_to_replace = buffer.chars_for_range(
19543                    buffer.anchor_before(completion.replace_range.start)
19544                        ..buffer.anchor_after(completion.replace_range.end),
19545                );
19546                let mut completion_text = completion.new_text.chars();
19547
19548                // is `text_to_replace` a subsequence of `completion_text`
19549                text_to_replace
19550                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
19551            }
19552            LspInsertMode::ReplaceSuffix => {
19553                let range_after_cursor = insert_range.end..completion.replace_range.end;
19554
19555                let text_after_cursor = buffer
19556                    .text_for_range(
19557                        buffer.anchor_before(range_after_cursor.start)
19558                            ..buffer.anchor_after(range_after_cursor.end),
19559                    )
19560                    .collect::<String>();
19561                completion.new_text.ends_with(&text_after_cursor)
19562            }
19563        }
19564    }
19565
19566    let buffer = buffer.read(cx);
19567
19568    if let CompletionSource::Lsp {
19569        insert_range: Some(insert_range),
19570        ..
19571    } = &completion.source
19572    {
19573        let completion_mode_setting =
19574            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19575                .completions
19576                .lsp_insert_mode;
19577
19578        if !should_replace(
19579            completion,
19580            &insert_range,
19581            intent,
19582            completion_mode_setting,
19583            buffer,
19584        ) {
19585            return insert_range.to_offset(buffer);
19586        }
19587    }
19588
19589    completion.replace_range.to_offset(buffer)
19590}
19591
19592fn insert_extra_newline_brackets(
19593    buffer: &MultiBufferSnapshot,
19594    range: Range<usize>,
19595    language: &language::LanguageScope,
19596) -> bool {
19597    let leading_whitespace_len = buffer
19598        .reversed_chars_at(range.start)
19599        .take_while(|c| c.is_whitespace() && *c != '\n')
19600        .map(|c| c.len_utf8())
19601        .sum::<usize>();
19602    let trailing_whitespace_len = buffer
19603        .chars_at(range.end)
19604        .take_while(|c| c.is_whitespace() && *c != '\n')
19605        .map(|c| c.len_utf8())
19606        .sum::<usize>();
19607    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19608
19609    language.brackets().any(|(pair, enabled)| {
19610        let pair_start = pair.start.trim_end();
19611        let pair_end = pair.end.trim_start();
19612
19613        enabled
19614            && pair.newline
19615            && buffer.contains_str_at(range.end, pair_end)
19616            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19617    })
19618}
19619
19620fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19621    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19622        [(buffer, range, _)] => (*buffer, range.clone()),
19623        _ => return false,
19624    };
19625    let pair = {
19626        let mut result: Option<BracketMatch> = None;
19627
19628        for pair in buffer
19629            .all_bracket_ranges(range.clone())
19630            .filter(move |pair| {
19631                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19632            })
19633        {
19634            let len = pair.close_range.end - pair.open_range.start;
19635
19636            if let Some(existing) = &result {
19637                let existing_len = existing.close_range.end - existing.open_range.start;
19638                if len > existing_len {
19639                    continue;
19640                }
19641            }
19642
19643            result = Some(pair);
19644        }
19645
19646        result
19647    };
19648    let Some(pair) = pair else {
19649        return false;
19650    };
19651    pair.newline_only
19652        && buffer
19653            .chars_for_range(pair.open_range.end..range.start)
19654            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19655            .all(|c| c.is_whitespace() && c != '\n')
19656}
19657
19658fn update_uncommitted_diff_for_buffer(
19659    editor: Entity<Editor>,
19660    project: &Entity<Project>,
19661    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19662    buffer: Entity<MultiBuffer>,
19663    cx: &mut App,
19664) -> Task<()> {
19665    let mut tasks = Vec::new();
19666    project.update(cx, |project, cx| {
19667        for buffer in buffers {
19668            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19669                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19670            }
19671        }
19672    });
19673    cx.spawn(async move |cx| {
19674        let diffs = future::join_all(tasks).await;
19675        if editor
19676            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19677            .unwrap_or(false)
19678        {
19679            return;
19680        }
19681
19682        buffer
19683            .update(cx, |buffer, cx| {
19684                for diff in diffs.into_iter().flatten() {
19685                    buffer.add_diff(diff, cx);
19686                }
19687            })
19688            .ok();
19689    })
19690}
19691
19692fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
19693    let tab_size = tab_size.get() as usize;
19694    let mut width = offset;
19695
19696    for ch in text.chars() {
19697        width += if ch == '\t' {
19698            tab_size - (width % tab_size)
19699        } else {
19700            1
19701        };
19702    }
19703
19704    width - offset
19705}
19706
19707#[cfg(test)]
19708mod tests {
19709    use super::*;
19710
19711    #[test]
19712    fn test_string_size_with_expanded_tabs() {
19713        let nz = |val| NonZeroU32::new(val).unwrap();
19714        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
19715        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
19716        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
19717        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
19718        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
19719        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
19720        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
19721        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
19722    }
19723}
19724
19725/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
19726struct WordBreakingTokenizer<'a> {
19727    input: &'a str,
19728}
19729
19730impl<'a> WordBreakingTokenizer<'a> {
19731    fn new(input: &'a str) -> Self {
19732        Self { input }
19733    }
19734}
19735
19736fn is_char_ideographic(ch: char) -> bool {
19737    use unicode_script::Script::*;
19738    use unicode_script::UnicodeScript;
19739    matches!(ch.script(), Han | Tangut | Yi)
19740}
19741
19742fn is_grapheme_ideographic(text: &str) -> bool {
19743    text.chars().any(is_char_ideographic)
19744}
19745
19746fn is_grapheme_whitespace(text: &str) -> bool {
19747    text.chars().any(|x| x.is_whitespace())
19748}
19749
19750fn should_stay_with_preceding_ideograph(text: &str) -> bool {
19751    text.chars().next().map_or(false, |ch| {
19752        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
19753    })
19754}
19755
19756#[derive(PartialEq, Eq, Debug, Clone, Copy)]
19757enum WordBreakToken<'a> {
19758    Word { token: &'a str, grapheme_len: usize },
19759    InlineWhitespace { token: &'a str, grapheme_len: usize },
19760    Newline,
19761}
19762
19763impl<'a> Iterator for WordBreakingTokenizer<'a> {
19764    /// Yields a span, the count of graphemes in the token, and whether it was
19765    /// whitespace. Note that it also breaks at word boundaries.
19766    type Item = WordBreakToken<'a>;
19767
19768    fn next(&mut self) -> Option<Self::Item> {
19769        use unicode_segmentation::UnicodeSegmentation;
19770        if self.input.is_empty() {
19771            return None;
19772        }
19773
19774        let mut iter = self.input.graphemes(true).peekable();
19775        let mut offset = 0;
19776        let mut grapheme_len = 0;
19777        if let Some(first_grapheme) = iter.next() {
19778            let is_newline = first_grapheme == "\n";
19779            let is_whitespace = is_grapheme_whitespace(first_grapheme);
19780            offset += first_grapheme.len();
19781            grapheme_len += 1;
19782            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
19783                if let Some(grapheme) = iter.peek().copied() {
19784                    if should_stay_with_preceding_ideograph(grapheme) {
19785                        offset += grapheme.len();
19786                        grapheme_len += 1;
19787                    }
19788                }
19789            } else {
19790                let mut words = self.input[offset..].split_word_bound_indices().peekable();
19791                let mut next_word_bound = words.peek().copied();
19792                if next_word_bound.map_or(false, |(i, _)| i == 0) {
19793                    next_word_bound = words.next();
19794                }
19795                while let Some(grapheme) = iter.peek().copied() {
19796                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
19797                        break;
19798                    };
19799                    if is_grapheme_whitespace(grapheme) != is_whitespace
19800                        || (grapheme == "\n") != is_newline
19801                    {
19802                        break;
19803                    };
19804                    offset += grapheme.len();
19805                    grapheme_len += 1;
19806                    iter.next();
19807                }
19808            }
19809            let token = &self.input[..offset];
19810            self.input = &self.input[offset..];
19811            if token == "\n" {
19812                Some(WordBreakToken::Newline)
19813            } else if is_whitespace {
19814                Some(WordBreakToken::InlineWhitespace {
19815                    token,
19816                    grapheme_len,
19817                })
19818            } else {
19819                Some(WordBreakToken::Word {
19820                    token,
19821                    grapheme_len,
19822                })
19823            }
19824        } else {
19825            None
19826        }
19827    }
19828}
19829
19830#[test]
19831fn test_word_breaking_tokenizer() {
19832    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
19833        ("", &[]),
19834        ("  ", &[whitespace("  ", 2)]),
19835        ("Ʒ", &[word("Ʒ", 1)]),
19836        ("Ǽ", &[word("Ǽ", 1)]),
19837        ("", &[word("", 1)]),
19838        ("⋑⋑", &[word("⋑⋑", 2)]),
19839        (
19840            "原理,进而",
19841            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
19842        ),
19843        (
19844            "hello world",
19845            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
19846        ),
19847        (
19848            "hello, world",
19849            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
19850        ),
19851        (
19852            "  hello world",
19853            &[
19854                whitespace("  ", 2),
19855                word("hello", 5),
19856                whitespace(" ", 1),
19857                word("world", 5),
19858            ],
19859        ),
19860        (
19861            "这是什么 \n 钢笔",
19862            &[
19863                word("", 1),
19864                word("", 1),
19865                word("", 1),
19866                word("", 1),
19867                whitespace(" ", 1),
19868                newline(),
19869                whitespace(" ", 1),
19870                word("", 1),
19871                word("", 1),
19872            ],
19873        ),
19874        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
19875    ];
19876
19877    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19878        WordBreakToken::Word {
19879            token,
19880            grapheme_len,
19881        }
19882    }
19883
19884    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19885        WordBreakToken::InlineWhitespace {
19886            token,
19887            grapheme_len,
19888        }
19889    }
19890
19891    fn newline() -> WordBreakToken<'static> {
19892        WordBreakToken::Newline
19893    }
19894
19895    for (input, result) in tests {
19896        assert_eq!(
19897            WordBreakingTokenizer::new(input)
19898                .collect::<Vec<_>>()
19899                .as_slice(),
19900            *result,
19901        );
19902    }
19903}
19904
19905fn wrap_with_prefix(
19906    line_prefix: String,
19907    unwrapped_text: String,
19908    wrap_column: usize,
19909    tab_size: NonZeroU32,
19910    preserve_existing_whitespace: bool,
19911) -> String {
19912    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
19913    let mut wrapped_text = String::new();
19914    let mut current_line = line_prefix.clone();
19915
19916    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
19917    let mut current_line_len = line_prefix_len;
19918    let mut in_whitespace = false;
19919    for token in tokenizer {
19920        let have_preceding_whitespace = in_whitespace;
19921        match token {
19922            WordBreakToken::Word {
19923                token,
19924                grapheme_len,
19925            } => {
19926                in_whitespace = false;
19927                if current_line_len + grapheme_len > wrap_column
19928                    && current_line_len != line_prefix_len
19929                {
19930                    wrapped_text.push_str(current_line.trim_end());
19931                    wrapped_text.push('\n');
19932                    current_line.truncate(line_prefix.len());
19933                    current_line_len = line_prefix_len;
19934                }
19935                current_line.push_str(token);
19936                current_line_len += grapheme_len;
19937            }
19938            WordBreakToken::InlineWhitespace {
19939                mut token,
19940                mut grapheme_len,
19941            } => {
19942                in_whitespace = true;
19943                if have_preceding_whitespace && !preserve_existing_whitespace {
19944                    continue;
19945                }
19946                if !preserve_existing_whitespace {
19947                    token = " ";
19948                    grapheme_len = 1;
19949                }
19950                if current_line_len + grapheme_len > wrap_column {
19951                    wrapped_text.push_str(current_line.trim_end());
19952                    wrapped_text.push('\n');
19953                    current_line.truncate(line_prefix.len());
19954                    current_line_len = line_prefix_len;
19955                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
19956                    current_line.push_str(token);
19957                    current_line_len += grapheme_len;
19958                }
19959            }
19960            WordBreakToken::Newline => {
19961                in_whitespace = true;
19962                if preserve_existing_whitespace {
19963                    wrapped_text.push_str(current_line.trim_end());
19964                    wrapped_text.push('\n');
19965                    current_line.truncate(line_prefix.len());
19966                    current_line_len = line_prefix_len;
19967                } else if have_preceding_whitespace {
19968                    continue;
19969                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
19970                {
19971                    wrapped_text.push_str(current_line.trim_end());
19972                    wrapped_text.push('\n');
19973                    current_line.truncate(line_prefix.len());
19974                    current_line_len = line_prefix_len;
19975                } else if current_line_len != line_prefix_len {
19976                    current_line.push(' ');
19977                    current_line_len += 1;
19978                }
19979            }
19980        }
19981    }
19982
19983    if !current_line.is_empty() {
19984        wrapped_text.push_str(&current_line);
19985    }
19986    wrapped_text
19987}
19988
19989#[test]
19990fn test_wrap_with_prefix() {
19991    assert_eq!(
19992        wrap_with_prefix(
19993            "# ".to_string(),
19994            "abcdefg".to_string(),
19995            4,
19996            NonZeroU32::new(4).unwrap(),
19997            false,
19998        ),
19999        "# abcdefg"
20000    );
20001    assert_eq!(
20002        wrap_with_prefix(
20003            "".to_string(),
20004            "\thello world".to_string(),
20005            8,
20006            NonZeroU32::new(4).unwrap(),
20007            false,
20008        ),
20009        "hello\nworld"
20010    );
20011    assert_eq!(
20012        wrap_with_prefix(
20013            "// ".to_string(),
20014            "xx \nyy zz aa bb cc".to_string(),
20015            12,
20016            NonZeroU32::new(4).unwrap(),
20017            false,
20018        ),
20019        "// xx yy zz\n// aa bb cc"
20020    );
20021    assert_eq!(
20022        wrap_with_prefix(
20023            String::new(),
20024            "这是什么 \n 钢笔".to_string(),
20025            3,
20026            NonZeroU32::new(4).unwrap(),
20027            false,
20028        ),
20029        "这是什\n么 钢\n"
20030    );
20031}
20032
20033pub trait CollaborationHub {
20034    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20035    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20036    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20037}
20038
20039impl CollaborationHub for Entity<Project> {
20040    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20041        self.read(cx).collaborators()
20042    }
20043
20044    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20045        self.read(cx).user_store().read(cx).participant_indices()
20046    }
20047
20048    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20049        let this = self.read(cx);
20050        let user_ids = this.collaborators().values().map(|c| c.user_id);
20051        this.user_store().read(cx).participant_names(user_ids, cx)
20052    }
20053}
20054
20055pub trait SemanticsProvider {
20056    fn hover(
20057        &self,
20058        buffer: &Entity<Buffer>,
20059        position: text::Anchor,
20060        cx: &mut App,
20061    ) -> Option<Task<Vec<project::Hover>>>;
20062
20063    fn inline_values(
20064        &self,
20065        buffer_handle: Entity<Buffer>,
20066        range: Range<text::Anchor>,
20067        cx: &mut App,
20068    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20069
20070    fn inlay_hints(
20071        &self,
20072        buffer_handle: Entity<Buffer>,
20073        range: Range<text::Anchor>,
20074        cx: &mut App,
20075    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20076
20077    fn resolve_inlay_hint(
20078        &self,
20079        hint: InlayHint,
20080        buffer_handle: Entity<Buffer>,
20081        server_id: LanguageServerId,
20082        cx: &mut App,
20083    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20084
20085    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20086
20087    fn document_highlights(
20088        &self,
20089        buffer: &Entity<Buffer>,
20090        position: text::Anchor,
20091        cx: &mut App,
20092    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20093
20094    fn definitions(
20095        &self,
20096        buffer: &Entity<Buffer>,
20097        position: text::Anchor,
20098        kind: GotoDefinitionKind,
20099        cx: &mut App,
20100    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20101
20102    fn range_for_rename(
20103        &self,
20104        buffer: &Entity<Buffer>,
20105        position: text::Anchor,
20106        cx: &mut App,
20107    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20108
20109    fn perform_rename(
20110        &self,
20111        buffer: &Entity<Buffer>,
20112        position: text::Anchor,
20113        new_name: String,
20114        cx: &mut App,
20115    ) -> Option<Task<Result<ProjectTransaction>>>;
20116}
20117
20118pub trait CompletionProvider {
20119    fn completions(
20120        &self,
20121        excerpt_id: ExcerptId,
20122        buffer: &Entity<Buffer>,
20123        buffer_position: text::Anchor,
20124        trigger: CompletionContext,
20125        window: &mut Window,
20126        cx: &mut Context<Editor>,
20127    ) -> Task<Result<Option<Vec<Completion>>>>;
20128
20129    fn resolve_completions(
20130        &self,
20131        buffer: Entity<Buffer>,
20132        completion_indices: Vec<usize>,
20133        completions: Rc<RefCell<Box<[Completion]>>>,
20134        cx: &mut Context<Editor>,
20135    ) -> Task<Result<bool>>;
20136
20137    fn apply_additional_edits_for_completion(
20138        &self,
20139        _buffer: Entity<Buffer>,
20140        _completions: Rc<RefCell<Box<[Completion]>>>,
20141        _completion_index: usize,
20142        _push_to_history: bool,
20143        _cx: &mut Context<Editor>,
20144    ) -> Task<Result<Option<language::Transaction>>> {
20145        Task::ready(Ok(None))
20146    }
20147
20148    fn is_completion_trigger(
20149        &self,
20150        buffer: &Entity<Buffer>,
20151        position: language::Anchor,
20152        text: &str,
20153        trigger_in_words: bool,
20154        cx: &mut Context<Editor>,
20155    ) -> bool;
20156
20157    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20158
20159    fn sort_completions(&self) -> bool {
20160        true
20161    }
20162
20163    fn filter_completions(&self) -> bool {
20164        true
20165    }
20166}
20167
20168pub trait CodeActionProvider {
20169    fn id(&self) -> Arc<str>;
20170
20171    fn code_actions(
20172        &self,
20173        buffer: &Entity<Buffer>,
20174        range: Range<text::Anchor>,
20175        window: &mut Window,
20176        cx: &mut App,
20177    ) -> Task<Result<Vec<CodeAction>>>;
20178
20179    fn apply_code_action(
20180        &self,
20181        buffer_handle: Entity<Buffer>,
20182        action: CodeAction,
20183        excerpt_id: ExcerptId,
20184        push_to_history: bool,
20185        window: &mut Window,
20186        cx: &mut App,
20187    ) -> Task<Result<ProjectTransaction>>;
20188}
20189
20190impl CodeActionProvider for Entity<Project> {
20191    fn id(&self) -> Arc<str> {
20192        "project".into()
20193    }
20194
20195    fn code_actions(
20196        &self,
20197        buffer: &Entity<Buffer>,
20198        range: Range<text::Anchor>,
20199        _window: &mut Window,
20200        cx: &mut App,
20201    ) -> Task<Result<Vec<CodeAction>>> {
20202        self.update(cx, |project, cx| {
20203            let code_lens = project.code_lens(buffer, range.clone(), cx);
20204            let code_actions = project.code_actions(buffer, range, None, cx);
20205            cx.background_spawn(async move {
20206                let (code_lens, code_actions) = join(code_lens, code_actions).await;
20207                Ok(code_lens
20208                    .context("code lens fetch")?
20209                    .into_iter()
20210                    .chain(code_actions.context("code action fetch")?)
20211                    .collect())
20212            })
20213        })
20214    }
20215
20216    fn apply_code_action(
20217        &self,
20218        buffer_handle: Entity<Buffer>,
20219        action: CodeAction,
20220        _excerpt_id: ExcerptId,
20221        push_to_history: bool,
20222        _window: &mut Window,
20223        cx: &mut App,
20224    ) -> Task<Result<ProjectTransaction>> {
20225        self.update(cx, |project, cx| {
20226            project.apply_code_action(buffer_handle, action, push_to_history, cx)
20227        })
20228    }
20229}
20230
20231fn snippet_completions(
20232    project: &Project,
20233    buffer: &Entity<Buffer>,
20234    buffer_position: text::Anchor,
20235    cx: &mut App,
20236) -> Task<Result<Vec<Completion>>> {
20237    let languages = buffer.read(cx).languages_at(buffer_position);
20238    let snippet_store = project.snippets().read(cx);
20239
20240    let scopes: Vec<_> = languages
20241        .iter()
20242        .filter_map(|language| {
20243            let language_name = language.lsp_id();
20244            let snippets = snippet_store.snippets_for(Some(language_name), cx);
20245
20246            if snippets.is_empty() {
20247                None
20248            } else {
20249                Some((language.default_scope(), snippets))
20250            }
20251        })
20252        .collect();
20253
20254    if scopes.is_empty() {
20255        return Task::ready(Ok(vec![]));
20256    }
20257
20258    let snapshot = buffer.read(cx).text_snapshot();
20259    let chars: String = snapshot
20260        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
20261        .collect();
20262    let executor = cx.background_executor().clone();
20263
20264    cx.background_spawn(async move {
20265        let mut all_results: Vec<Completion> = Vec::new();
20266        for (scope, snippets) in scopes.into_iter() {
20267            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
20268            let mut last_word = chars
20269                .chars()
20270                .take_while(|c| classifier.is_word(*c))
20271                .collect::<String>();
20272            last_word = last_word.chars().rev().collect();
20273
20274            if last_word.is_empty() {
20275                return Ok(vec![]);
20276            }
20277
20278            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
20279            let to_lsp = |point: &text::Anchor| {
20280                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
20281                point_to_lsp(end)
20282            };
20283            let lsp_end = to_lsp(&buffer_position);
20284
20285            let candidates = snippets
20286                .iter()
20287                .enumerate()
20288                .flat_map(|(ix, snippet)| {
20289                    snippet
20290                        .prefix
20291                        .iter()
20292                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
20293                })
20294                .collect::<Vec<StringMatchCandidate>>();
20295
20296            let mut matches = fuzzy::match_strings(
20297                &candidates,
20298                &last_word,
20299                last_word.chars().any(|c| c.is_uppercase()),
20300                100,
20301                &Default::default(),
20302                executor.clone(),
20303            )
20304            .await;
20305
20306            // Remove all candidates where the query's start does not match the start of any word in the candidate
20307            if let Some(query_start) = last_word.chars().next() {
20308                matches.retain(|string_match| {
20309                    split_words(&string_match.string).any(|word| {
20310                        // Check that the first codepoint of the word as lowercase matches the first
20311                        // codepoint of the query as lowercase
20312                        word.chars()
20313                            .flat_map(|codepoint| codepoint.to_lowercase())
20314                            .zip(query_start.to_lowercase())
20315                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20316                    })
20317                });
20318            }
20319
20320            let matched_strings = matches
20321                .into_iter()
20322                .map(|m| m.string)
20323                .collect::<HashSet<_>>();
20324
20325            let mut result: Vec<Completion> = snippets
20326                .iter()
20327                .filter_map(|snippet| {
20328                    let matching_prefix = snippet
20329                        .prefix
20330                        .iter()
20331                        .find(|prefix| matched_strings.contains(*prefix))?;
20332                    let start = as_offset - last_word.len();
20333                    let start = snapshot.anchor_before(start);
20334                    let range = start..buffer_position;
20335                    let lsp_start = to_lsp(&start);
20336                    let lsp_range = lsp::Range {
20337                        start: lsp_start,
20338                        end: lsp_end,
20339                    };
20340                    Some(Completion {
20341                        replace_range: range,
20342                        new_text: snippet.body.clone(),
20343                        source: CompletionSource::Lsp {
20344                            insert_range: None,
20345                            server_id: LanguageServerId(usize::MAX),
20346                            resolved: true,
20347                            lsp_completion: Box::new(lsp::CompletionItem {
20348                                label: snippet.prefix.first().unwrap().clone(),
20349                                kind: Some(CompletionItemKind::SNIPPET),
20350                                label_details: snippet.description.as_ref().map(|description| {
20351                                    lsp::CompletionItemLabelDetails {
20352                                        detail: Some(description.clone()),
20353                                        description: None,
20354                                    }
20355                                }),
20356                                insert_text_format: Some(InsertTextFormat::SNIPPET),
20357                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20358                                    lsp::InsertReplaceEdit {
20359                                        new_text: snippet.body.clone(),
20360                                        insert: lsp_range,
20361                                        replace: lsp_range,
20362                                    },
20363                                )),
20364                                filter_text: Some(snippet.body.clone()),
20365                                sort_text: Some(char::MAX.to_string()),
20366                                ..lsp::CompletionItem::default()
20367                            }),
20368                            lsp_defaults: None,
20369                        },
20370                        label: CodeLabel {
20371                            text: matching_prefix.clone(),
20372                            runs: Vec::new(),
20373                            filter_range: 0..matching_prefix.len(),
20374                        },
20375                        icon_path: None,
20376                        documentation: Some(
20377                            CompletionDocumentation::SingleLineAndMultiLinePlainText {
20378                                single_line: snippet.name.clone().into(),
20379                                plain_text: snippet
20380                                    .description
20381                                    .clone()
20382                                    .map(|description| description.into()),
20383                            },
20384                        ),
20385                        insert_text_mode: None,
20386                        confirm: None,
20387                    })
20388                })
20389                .collect();
20390
20391            all_results.append(&mut result);
20392        }
20393
20394        Ok(all_results)
20395    })
20396}
20397
20398impl CompletionProvider for Entity<Project> {
20399    fn completions(
20400        &self,
20401        _excerpt_id: ExcerptId,
20402        buffer: &Entity<Buffer>,
20403        buffer_position: text::Anchor,
20404        options: CompletionContext,
20405        _window: &mut Window,
20406        cx: &mut Context<Editor>,
20407    ) -> Task<Result<Option<Vec<Completion>>>> {
20408        self.update(cx, |project, cx| {
20409            let snippets = snippet_completions(project, buffer, buffer_position, cx);
20410            let project_completions = project.completions(buffer, buffer_position, options, cx);
20411            cx.background_spawn(async move {
20412                let snippets_completions = snippets.await?;
20413                match project_completions.await? {
20414                    Some(mut completions) => {
20415                        completions.extend(snippets_completions);
20416                        Ok(Some(completions))
20417                    }
20418                    None => {
20419                        if snippets_completions.is_empty() {
20420                            Ok(None)
20421                        } else {
20422                            Ok(Some(snippets_completions))
20423                        }
20424                    }
20425                }
20426            })
20427        })
20428    }
20429
20430    fn resolve_completions(
20431        &self,
20432        buffer: Entity<Buffer>,
20433        completion_indices: Vec<usize>,
20434        completions: Rc<RefCell<Box<[Completion]>>>,
20435        cx: &mut Context<Editor>,
20436    ) -> Task<Result<bool>> {
20437        self.update(cx, |project, cx| {
20438            project.lsp_store().update(cx, |lsp_store, cx| {
20439                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
20440            })
20441        })
20442    }
20443
20444    fn apply_additional_edits_for_completion(
20445        &self,
20446        buffer: Entity<Buffer>,
20447        completions: Rc<RefCell<Box<[Completion]>>>,
20448        completion_index: usize,
20449        push_to_history: bool,
20450        cx: &mut Context<Editor>,
20451    ) -> Task<Result<Option<language::Transaction>>> {
20452        self.update(cx, |project, cx| {
20453            project.lsp_store().update(cx, |lsp_store, cx| {
20454                lsp_store.apply_additional_edits_for_completion(
20455                    buffer,
20456                    completions,
20457                    completion_index,
20458                    push_to_history,
20459                    cx,
20460                )
20461            })
20462        })
20463    }
20464
20465    fn is_completion_trigger(
20466        &self,
20467        buffer: &Entity<Buffer>,
20468        position: language::Anchor,
20469        text: &str,
20470        trigger_in_words: bool,
20471        cx: &mut Context<Editor>,
20472    ) -> bool {
20473        let mut chars = text.chars();
20474        let char = if let Some(char) = chars.next() {
20475            char
20476        } else {
20477            return false;
20478        };
20479        if chars.next().is_some() {
20480            return false;
20481        }
20482
20483        let buffer = buffer.read(cx);
20484        let snapshot = buffer.snapshot();
20485        if !snapshot.settings_at(position, cx).show_completions_on_input {
20486            return false;
20487        }
20488        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20489        if trigger_in_words && classifier.is_word(char) {
20490            return true;
20491        }
20492
20493        buffer.completion_triggers().contains(text)
20494    }
20495}
20496
20497impl SemanticsProvider for Entity<Project> {
20498    fn hover(
20499        &self,
20500        buffer: &Entity<Buffer>,
20501        position: text::Anchor,
20502        cx: &mut App,
20503    ) -> Option<Task<Vec<project::Hover>>> {
20504        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20505    }
20506
20507    fn document_highlights(
20508        &self,
20509        buffer: &Entity<Buffer>,
20510        position: text::Anchor,
20511        cx: &mut App,
20512    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20513        Some(self.update(cx, |project, cx| {
20514            project.document_highlights(buffer, position, cx)
20515        }))
20516    }
20517
20518    fn definitions(
20519        &self,
20520        buffer: &Entity<Buffer>,
20521        position: text::Anchor,
20522        kind: GotoDefinitionKind,
20523        cx: &mut App,
20524    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20525        Some(self.update(cx, |project, cx| match kind {
20526            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20527            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20528            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20529            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20530        }))
20531    }
20532
20533    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20534        // TODO: make this work for remote projects
20535        self.update(cx, |project, cx| {
20536            if project
20537                .active_debug_session(cx)
20538                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20539            {
20540                return true;
20541            }
20542
20543            buffer.update(cx, |buffer, cx| {
20544                project.any_language_server_supports_inlay_hints(buffer, cx)
20545            })
20546        })
20547    }
20548
20549    fn inline_values(
20550        &self,
20551        buffer_handle: Entity<Buffer>,
20552
20553        range: Range<text::Anchor>,
20554        cx: &mut App,
20555    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20556        self.update(cx, |project, cx| {
20557            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20558
20559            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20560        })
20561    }
20562
20563    fn inlay_hints(
20564        &self,
20565        buffer_handle: Entity<Buffer>,
20566        range: Range<text::Anchor>,
20567        cx: &mut App,
20568    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20569        Some(self.update(cx, |project, cx| {
20570            project.inlay_hints(buffer_handle, range, cx)
20571        }))
20572    }
20573
20574    fn resolve_inlay_hint(
20575        &self,
20576        hint: InlayHint,
20577        buffer_handle: Entity<Buffer>,
20578        server_id: LanguageServerId,
20579        cx: &mut App,
20580    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20581        Some(self.update(cx, |project, cx| {
20582            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20583        }))
20584    }
20585
20586    fn range_for_rename(
20587        &self,
20588        buffer: &Entity<Buffer>,
20589        position: text::Anchor,
20590        cx: &mut App,
20591    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20592        Some(self.update(cx, |project, cx| {
20593            let buffer = buffer.clone();
20594            let task = project.prepare_rename(buffer.clone(), position, cx);
20595            cx.spawn(async move |_, cx| {
20596                Ok(match task.await? {
20597                    PrepareRenameResponse::Success(range) => Some(range),
20598                    PrepareRenameResponse::InvalidPosition => None,
20599                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20600                        // Fallback on using TreeSitter info to determine identifier range
20601                        buffer.read_with(cx, |buffer, _| {
20602                            let snapshot = buffer.snapshot();
20603                            let (range, kind) = snapshot.surrounding_word(position);
20604                            if kind != Some(CharKind::Word) {
20605                                return None;
20606                            }
20607                            Some(
20608                                snapshot.anchor_before(range.start)
20609                                    ..snapshot.anchor_after(range.end),
20610                            )
20611                        })?
20612                    }
20613                })
20614            })
20615        }))
20616    }
20617
20618    fn perform_rename(
20619        &self,
20620        buffer: &Entity<Buffer>,
20621        position: text::Anchor,
20622        new_name: String,
20623        cx: &mut App,
20624    ) -> Option<Task<Result<ProjectTransaction>>> {
20625        Some(self.update(cx, |project, cx| {
20626            project.perform_rename(buffer.clone(), position, new_name, cx)
20627        }))
20628    }
20629}
20630
20631fn inlay_hint_settings(
20632    location: Anchor,
20633    snapshot: &MultiBufferSnapshot,
20634    cx: &mut Context<Editor>,
20635) -> InlayHintSettings {
20636    let file = snapshot.file_at(location);
20637    let language = snapshot.language_at(location).map(|l| l.name());
20638    language_settings(language, file, cx).inlay_hints
20639}
20640
20641fn consume_contiguous_rows(
20642    contiguous_row_selections: &mut Vec<Selection<Point>>,
20643    selection: &Selection<Point>,
20644    display_map: &DisplaySnapshot,
20645    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20646) -> (MultiBufferRow, MultiBufferRow) {
20647    contiguous_row_selections.push(selection.clone());
20648    let start_row = MultiBufferRow(selection.start.row);
20649    let mut end_row = ending_row(selection, display_map);
20650
20651    while let Some(next_selection) = selections.peek() {
20652        if next_selection.start.row <= end_row.0 {
20653            end_row = ending_row(next_selection, display_map);
20654            contiguous_row_selections.push(selections.next().unwrap().clone());
20655        } else {
20656            break;
20657        }
20658    }
20659    (start_row, end_row)
20660}
20661
20662fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20663    if next_selection.end.column > 0 || next_selection.is_empty() {
20664        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20665    } else {
20666        MultiBufferRow(next_selection.end.row)
20667    }
20668}
20669
20670impl EditorSnapshot {
20671    pub fn remote_selections_in_range<'a>(
20672        &'a self,
20673        range: &'a Range<Anchor>,
20674        collaboration_hub: &dyn CollaborationHub,
20675        cx: &'a App,
20676    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20677        let participant_names = collaboration_hub.user_names(cx);
20678        let participant_indices = collaboration_hub.user_participant_indices(cx);
20679        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20680        let collaborators_by_replica_id = collaborators_by_peer_id
20681            .values()
20682            .map(|collaborator| (collaborator.replica_id, collaborator))
20683            .collect::<HashMap<_, _>>();
20684        self.buffer_snapshot
20685            .selections_in_range(range, false)
20686            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20687                if replica_id == AGENT_REPLICA_ID {
20688                    Some(RemoteSelection {
20689                        replica_id,
20690                        selection,
20691                        cursor_shape,
20692                        line_mode,
20693                        collaborator_id: CollaboratorId::Agent,
20694                        user_name: Some("Agent".into()),
20695                        color: cx.theme().players().agent(),
20696                    })
20697                } else {
20698                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20699                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20700                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20701                    Some(RemoteSelection {
20702                        replica_id,
20703                        selection,
20704                        cursor_shape,
20705                        line_mode,
20706                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20707                        user_name,
20708                        color: if let Some(index) = participant_index {
20709                            cx.theme().players().color_for_participant(index.0)
20710                        } else {
20711                            cx.theme().players().absent()
20712                        },
20713                    })
20714                }
20715            })
20716    }
20717
20718    pub fn hunks_for_ranges(
20719        &self,
20720        ranges: impl IntoIterator<Item = Range<Point>>,
20721    ) -> Vec<MultiBufferDiffHunk> {
20722        let mut hunks = Vec::new();
20723        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20724            HashMap::default();
20725        for query_range in ranges {
20726            let query_rows =
20727                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20728            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20729                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20730            ) {
20731                // Include deleted hunks that are adjacent to the query range, because
20732                // otherwise they would be missed.
20733                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20734                if hunk.status().is_deleted() {
20735                    intersects_range |= hunk.row_range.start == query_rows.end;
20736                    intersects_range |= hunk.row_range.end == query_rows.start;
20737                }
20738                if intersects_range {
20739                    if !processed_buffer_rows
20740                        .entry(hunk.buffer_id)
20741                        .or_default()
20742                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20743                    {
20744                        continue;
20745                    }
20746                    hunks.push(hunk);
20747                }
20748            }
20749        }
20750
20751        hunks
20752    }
20753
20754    fn display_diff_hunks_for_rows<'a>(
20755        &'a self,
20756        display_rows: Range<DisplayRow>,
20757        folded_buffers: &'a HashSet<BufferId>,
20758    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20759        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20760        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20761
20762        self.buffer_snapshot
20763            .diff_hunks_in_range(buffer_start..buffer_end)
20764            .filter_map(|hunk| {
20765                if folded_buffers.contains(&hunk.buffer_id) {
20766                    return None;
20767                }
20768
20769                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20770                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20771
20772                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20773                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20774
20775                let display_hunk = if hunk_display_start.column() != 0 {
20776                    DisplayDiffHunk::Folded {
20777                        display_row: hunk_display_start.row(),
20778                    }
20779                } else {
20780                    let mut end_row = hunk_display_end.row();
20781                    if hunk_display_end.column() > 0 {
20782                        end_row.0 += 1;
20783                    }
20784                    let is_created_file = hunk.is_created_file();
20785                    DisplayDiffHunk::Unfolded {
20786                        status: hunk.status(),
20787                        diff_base_byte_range: hunk.diff_base_byte_range,
20788                        display_row_range: hunk_display_start.row()..end_row,
20789                        multi_buffer_range: Anchor::range_in_buffer(
20790                            hunk.excerpt_id,
20791                            hunk.buffer_id,
20792                            hunk.buffer_range,
20793                        ),
20794                        is_created_file,
20795                    }
20796                };
20797
20798                Some(display_hunk)
20799            })
20800    }
20801
20802    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20803        self.display_snapshot.buffer_snapshot.language_at(position)
20804    }
20805
20806    pub fn is_focused(&self) -> bool {
20807        self.is_focused
20808    }
20809
20810    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20811        self.placeholder_text.as_ref()
20812    }
20813
20814    pub fn scroll_position(&self) -> gpui::Point<f32> {
20815        self.scroll_anchor.scroll_position(&self.display_snapshot)
20816    }
20817
20818    fn gutter_dimensions(
20819        &self,
20820        font_id: FontId,
20821        font_size: Pixels,
20822        max_line_number_width: Pixels,
20823        cx: &App,
20824    ) -> Option<GutterDimensions> {
20825        if !self.show_gutter {
20826            return None;
20827        }
20828
20829        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20830        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20831
20832        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20833            matches!(
20834                ProjectSettings::get_global(cx).git.git_gutter,
20835                Some(GitGutterSetting::TrackedFiles)
20836            )
20837        });
20838        let gutter_settings = EditorSettings::get_global(cx).gutter;
20839        let show_line_numbers = self
20840            .show_line_numbers
20841            .unwrap_or(gutter_settings.line_numbers);
20842        let line_gutter_width = if show_line_numbers {
20843            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
20844            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
20845            max_line_number_width.max(min_width_for_number_on_gutter)
20846        } else {
20847            0.0.into()
20848        };
20849
20850        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
20851        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
20852
20853        let git_blame_entries_width =
20854            self.git_blame_gutter_max_author_length
20855                .map(|max_author_length| {
20856                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20857                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
20858
20859                    /// The number of characters to dedicate to gaps and margins.
20860                    const SPACING_WIDTH: usize = 4;
20861
20862                    let max_char_count = max_author_length.min(renderer.max_author_length())
20863                        + ::git::SHORT_SHA_LENGTH
20864                        + MAX_RELATIVE_TIMESTAMP.len()
20865                        + SPACING_WIDTH;
20866
20867                    em_advance * max_char_count
20868                });
20869
20870        let is_singleton = self.buffer_snapshot.is_singleton();
20871
20872        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
20873        left_padding += if !is_singleton {
20874            em_width * 4.0
20875        } else if show_runnables || show_breakpoints {
20876            em_width * 3.0
20877        } else if show_git_gutter && show_line_numbers {
20878            em_width * 2.0
20879        } else if show_git_gutter || show_line_numbers {
20880            em_width
20881        } else {
20882            px(0.)
20883        };
20884
20885        let shows_folds = is_singleton && gutter_settings.folds;
20886
20887        let right_padding = if shows_folds && show_line_numbers {
20888            em_width * 4.0
20889        } else if shows_folds || (!is_singleton && show_line_numbers) {
20890            em_width * 3.0
20891        } else if show_line_numbers {
20892            em_width
20893        } else {
20894            px(0.)
20895        };
20896
20897        Some(GutterDimensions {
20898            left_padding,
20899            right_padding,
20900            width: line_gutter_width + left_padding + right_padding,
20901            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
20902            git_blame_entries_width,
20903        })
20904    }
20905
20906    pub fn render_crease_toggle(
20907        &self,
20908        buffer_row: MultiBufferRow,
20909        row_contains_cursor: bool,
20910        editor: Entity<Editor>,
20911        window: &mut Window,
20912        cx: &mut App,
20913    ) -> Option<AnyElement> {
20914        let folded = self.is_line_folded(buffer_row);
20915        let mut is_foldable = false;
20916
20917        if let Some(crease) = self
20918            .crease_snapshot
20919            .query_row(buffer_row, &self.buffer_snapshot)
20920        {
20921            is_foldable = true;
20922            match crease {
20923                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
20924                    if let Some(render_toggle) = render_toggle {
20925                        let toggle_callback =
20926                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
20927                                if folded {
20928                                    editor.update(cx, |editor, cx| {
20929                                        editor.fold_at(buffer_row, window, cx)
20930                                    });
20931                                } else {
20932                                    editor.update(cx, |editor, cx| {
20933                                        editor.unfold_at(buffer_row, window, cx)
20934                                    });
20935                                }
20936                            });
20937                        return Some((render_toggle)(
20938                            buffer_row,
20939                            folded,
20940                            toggle_callback,
20941                            window,
20942                            cx,
20943                        ));
20944                    }
20945                }
20946            }
20947        }
20948
20949        is_foldable |= self.starts_indent(buffer_row);
20950
20951        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
20952            Some(
20953                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
20954                    .toggle_state(folded)
20955                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
20956                        if folded {
20957                            this.unfold_at(buffer_row, window, cx);
20958                        } else {
20959                            this.fold_at(buffer_row, window, cx);
20960                        }
20961                    }))
20962                    .into_any_element(),
20963            )
20964        } else {
20965            None
20966        }
20967    }
20968
20969    pub fn render_crease_trailer(
20970        &self,
20971        buffer_row: MultiBufferRow,
20972        window: &mut Window,
20973        cx: &mut App,
20974    ) -> Option<AnyElement> {
20975        let folded = self.is_line_folded(buffer_row);
20976        if let Crease::Inline { render_trailer, .. } = self
20977            .crease_snapshot
20978            .query_row(buffer_row, &self.buffer_snapshot)?
20979        {
20980            let render_trailer = render_trailer.as_ref()?;
20981            Some(render_trailer(buffer_row, folded, window, cx))
20982        } else {
20983            None
20984        }
20985    }
20986}
20987
20988impl Deref for EditorSnapshot {
20989    type Target = DisplaySnapshot;
20990
20991    fn deref(&self) -> &Self::Target {
20992        &self.display_snapshot
20993    }
20994}
20995
20996#[derive(Clone, Debug, PartialEq, Eq)]
20997pub enum EditorEvent {
20998    InputIgnored {
20999        text: Arc<str>,
21000    },
21001    InputHandled {
21002        utf16_range_to_replace: Option<Range<isize>>,
21003        text: Arc<str>,
21004    },
21005    ExcerptsAdded {
21006        buffer: Entity<Buffer>,
21007        predecessor: ExcerptId,
21008        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21009    },
21010    ExcerptsRemoved {
21011        ids: Vec<ExcerptId>,
21012        removed_buffer_ids: Vec<BufferId>,
21013    },
21014    BufferFoldToggled {
21015        ids: Vec<ExcerptId>,
21016        folded: bool,
21017    },
21018    ExcerptsEdited {
21019        ids: Vec<ExcerptId>,
21020    },
21021    ExcerptsExpanded {
21022        ids: Vec<ExcerptId>,
21023    },
21024    BufferEdited,
21025    Edited {
21026        transaction_id: clock::Lamport,
21027    },
21028    Reparsed(BufferId),
21029    Focused,
21030    FocusedIn,
21031    Blurred,
21032    DirtyChanged,
21033    Saved,
21034    TitleChanged,
21035    DiffBaseChanged,
21036    SelectionsChanged {
21037        local: bool,
21038    },
21039    ScrollPositionChanged {
21040        local: bool,
21041        autoscroll: bool,
21042    },
21043    Closed,
21044    TransactionUndone {
21045        transaction_id: clock::Lamport,
21046    },
21047    TransactionBegun {
21048        transaction_id: clock::Lamport,
21049    },
21050    Reloaded,
21051    CursorShapeChanged,
21052    PushedToNavHistory {
21053        anchor: Anchor,
21054        is_deactivate: bool,
21055    },
21056}
21057
21058impl EventEmitter<EditorEvent> for Editor {}
21059
21060impl Focusable for Editor {
21061    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21062        self.focus_handle.clone()
21063    }
21064}
21065
21066impl Render for Editor {
21067    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21068        let settings = ThemeSettings::get_global(cx);
21069
21070        let mut text_style = match self.mode {
21071            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21072                color: cx.theme().colors().editor_foreground,
21073                font_family: settings.ui_font.family.clone(),
21074                font_features: settings.ui_font.features.clone(),
21075                font_fallbacks: settings.ui_font.fallbacks.clone(),
21076                font_size: rems(0.875).into(),
21077                font_weight: settings.ui_font.weight,
21078                line_height: relative(settings.buffer_line_height.value()),
21079                ..Default::default()
21080            },
21081            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21082                color: cx.theme().colors().editor_foreground,
21083                font_family: settings.buffer_font.family.clone(),
21084                font_features: settings.buffer_font.features.clone(),
21085                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21086                font_size: settings.buffer_font_size(cx).into(),
21087                font_weight: settings.buffer_font.weight,
21088                line_height: relative(settings.buffer_line_height.value()),
21089                ..Default::default()
21090            },
21091        };
21092        if let Some(text_style_refinement) = &self.text_style_refinement {
21093            text_style.refine(text_style_refinement)
21094        }
21095
21096        let background = match self.mode {
21097            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21098            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
21099            EditorMode::Full { .. } => cx.theme().colors().editor_background,
21100            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
21101        };
21102
21103        EditorElement::new(
21104            &cx.entity(),
21105            EditorStyle {
21106                background,
21107                local_player: cx.theme().players().local(),
21108                text: text_style,
21109                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
21110                syntax: cx.theme().syntax().clone(),
21111                status: cx.theme().status().clone(),
21112                inlay_hints_style: make_inlay_hints_style(cx),
21113                inline_completion_styles: make_suggestion_styles(cx),
21114                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
21115                show_underlines: !self.mode.is_minimap(),
21116            },
21117        )
21118    }
21119}
21120
21121impl EntityInputHandler for Editor {
21122    fn text_for_range(
21123        &mut self,
21124        range_utf16: Range<usize>,
21125        adjusted_range: &mut Option<Range<usize>>,
21126        _: &mut Window,
21127        cx: &mut Context<Self>,
21128    ) -> Option<String> {
21129        let snapshot = self.buffer.read(cx).read(cx);
21130        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
21131        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
21132        if (start.0..end.0) != range_utf16 {
21133            adjusted_range.replace(start.0..end.0);
21134        }
21135        Some(snapshot.text_for_range(start..end).collect())
21136    }
21137
21138    fn selected_text_range(
21139        &mut self,
21140        ignore_disabled_input: bool,
21141        _: &mut Window,
21142        cx: &mut Context<Self>,
21143    ) -> Option<UTF16Selection> {
21144        // Prevent the IME menu from appearing when holding down an alphabetic key
21145        // while input is disabled.
21146        if !ignore_disabled_input && !self.input_enabled {
21147            return None;
21148        }
21149
21150        let selection = self.selections.newest::<OffsetUtf16>(cx);
21151        let range = selection.range();
21152
21153        Some(UTF16Selection {
21154            range: range.start.0..range.end.0,
21155            reversed: selection.reversed,
21156        })
21157    }
21158
21159    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
21160        let snapshot = self.buffer.read(cx).read(cx);
21161        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
21162        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
21163    }
21164
21165    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21166        self.clear_highlights::<InputComposition>(cx);
21167        self.ime_transaction.take();
21168    }
21169
21170    fn replace_text_in_range(
21171        &mut self,
21172        range_utf16: Option<Range<usize>>,
21173        text: &str,
21174        window: &mut Window,
21175        cx: &mut Context<Self>,
21176    ) {
21177        if !self.input_enabled {
21178            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21179            return;
21180        }
21181
21182        self.transact(window, cx, |this, window, cx| {
21183            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
21184                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21185                Some(this.selection_replacement_ranges(range_utf16, cx))
21186            } else {
21187                this.marked_text_ranges(cx)
21188            };
21189
21190            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
21191                let newest_selection_id = this.selections.newest_anchor().id;
21192                this.selections
21193                    .all::<OffsetUtf16>(cx)
21194                    .iter()
21195                    .zip(ranges_to_replace.iter())
21196                    .find_map(|(selection, range)| {
21197                        if selection.id == newest_selection_id {
21198                            Some(
21199                                (range.start.0 as isize - selection.head().0 as isize)
21200                                    ..(range.end.0 as isize - selection.head().0 as isize),
21201                            )
21202                        } else {
21203                            None
21204                        }
21205                    })
21206            });
21207
21208            cx.emit(EditorEvent::InputHandled {
21209                utf16_range_to_replace: range_to_replace,
21210                text: text.into(),
21211            });
21212
21213            if let Some(new_selected_ranges) = new_selected_ranges {
21214                this.change_selections(None, window, cx, |selections| {
21215                    selections.select_ranges(new_selected_ranges)
21216                });
21217                this.backspace(&Default::default(), window, cx);
21218            }
21219
21220            this.handle_input(text, window, cx);
21221        });
21222
21223        if let Some(transaction) = self.ime_transaction {
21224            self.buffer.update(cx, |buffer, cx| {
21225                buffer.group_until_transaction(transaction, cx);
21226            });
21227        }
21228
21229        self.unmark_text(window, cx);
21230    }
21231
21232    fn replace_and_mark_text_in_range(
21233        &mut self,
21234        range_utf16: Option<Range<usize>>,
21235        text: &str,
21236        new_selected_range_utf16: Option<Range<usize>>,
21237        window: &mut Window,
21238        cx: &mut Context<Self>,
21239    ) {
21240        if !self.input_enabled {
21241            return;
21242        }
21243
21244        let transaction = self.transact(window, cx, |this, window, cx| {
21245            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
21246                let snapshot = this.buffer.read(cx).read(cx);
21247                if let Some(relative_range_utf16) = range_utf16.as_ref() {
21248                    for marked_range in &mut marked_ranges {
21249                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
21250                        marked_range.start.0 += relative_range_utf16.start;
21251                        marked_range.start =
21252                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
21253                        marked_range.end =
21254                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
21255                    }
21256                }
21257                Some(marked_ranges)
21258            } else if let Some(range_utf16) = range_utf16 {
21259                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21260                Some(this.selection_replacement_ranges(range_utf16, cx))
21261            } else {
21262                None
21263            };
21264
21265            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
21266                let newest_selection_id = this.selections.newest_anchor().id;
21267                this.selections
21268                    .all::<OffsetUtf16>(cx)
21269                    .iter()
21270                    .zip(ranges_to_replace.iter())
21271                    .find_map(|(selection, range)| {
21272                        if selection.id == newest_selection_id {
21273                            Some(
21274                                (range.start.0 as isize - selection.head().0 as isize)
21275                                    ..(range.end.0 as isize - selection.head().0 as isize),
21276                            )
21277                        } else {
21278                            None
21279                        }
21280                    })
21281            });
21282
21283            cx.emit(EditorEvent::InputHandled {
21284                utf16_range_to_replace: range_to_replace,
21285                text: text.into(),
21286            });
21287
21288            if let Some(ranges) = ranges_to_replace {
21289                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
21290            }
21291
21292            let marked_ranges = {
21293                let snapshot = this.buffer.read(cx).read(cx);
21294                this.selections
21295                    .disjoint_anchors()
21296                    .iter()
21297                    .map(|selection| {
21298                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
21299                    })
21300                    .collect::<Vec<_>>()
21301            };
21302
21303            if text.is_empty() {
21304                this.unmark_text(window, cx);
21305            } else {
21306                this.highlight_text::<InputComposition>(
21307                    marked_ranges.clone(),
21308                    HighlightStyle {
21309                        underline: Some(UnderlineStyle {
21310                            thickness: px(1.),
21311                            color: None,
21312                            wavy: false,
21313                        }),
21314                        ..Default::default()
21315                    },
21316                    cx,
21317                );
21318            }
21319
21320            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
21321            let use_autoclose = this.use_autoclose;
21322            let use_auto_surround = this.use_auto_surround;
21323            this.set_use_autoclose(false);
21324            this.set_use_auto_surround(false);
21325            this.handle_input(text, window, cx);
21326            this.set_use_autoclose(use_autoclose);
21327            this.set_use_auto_surround(use_auto_surround);
21328
21329            if let Some(new_selected_range) = new_selected_range_utf16 {
21330                let snapshot = this.buffer.read(cx).read(cx);
21331                let new_selected_ranges = marked_ranges
21332                    .into_iter()
21333                    .map(|marked_range| {
21334                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
21335                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
21336                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
21337                        snapshot.clip_offset_utf16(new_start, Bias::Left)
21338                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
21339                    })
21340                    .collect::<Vec<_>>();
21341
21342                drop(snapshot);
21343                this.change_selections(None, window, cx, |selections| {
21344                    selections.select_ranges(new_selected_ranges)
21345                });
21346            }
21347        });
21348
21349        self.ime_transaction = self.ime_transaction.or(transaction);
21350        if let Some(transaction) = self.ime_transaction {
21351            self.buffer.update(cx, |buffer, cx| {
21352                buffer.group_until_transaction(transaction, cx);
21353            });
21354        }
21355
21356        if self.text_highlights::<InputComposition>(cx).is_none() {
21357            self.ime_transaction.take();
21358        }
21359    }
21360
21361    fn bounds_for_range(
21362        &mut self,
21363        range_utf16: Range<usize>,
21364        element_bounds: gpui::Bounds<Pixels>,
21365        window: &mut Window,
21366        cx: &mut Context<Self>,
21367    ) -> Option<gpui::Bounds<Pixels>> {
21368        let text_layout_details = self.text_layout_details(window);
21369        let gpui::Size {
21370            width: em_width,
21371            height: line_height,
21372        } = self.character_size(window);
21373
21374        let snapshot = self.snapshot(window, cx);
21375        let scroll_position = snapshot.scroll_position();
21376        let scroll_left = scroll_position.x * em_width;
21377
21378        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
21379        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
21380            + self.gutter_dimensions.width
21381            + self.gutter_dimensions.margin;
21382        let y = line_height * (start.row().as_f32() - scroll_position.y);
21383
21384        Some(Bounds {
21385            origin: element_bounds.origin + point(x, y),
21386            size: size(em_width, line_height),
21387        })
21388    }
21389
21390    fn character_index_for_point(
21391        &mut self,
21392        point: gpui::Point<Pixels>,
21393        _window: &mut Window,
21394        _cx: &mut Context<Self>,
21395    ) -> Option<usize> {
21396        let position_map = self.last_position_map.as_ref()?;
21397        if !position_map.text_hitbox.contains(&point) {
21398            return None;
21399        }
21400        let display_point = position_map.point_for_position(point).previous_valid;
21401        let anchor = position_map
21402            .snapshot
21403            .display_point_to_anchor(display_point, Bias::Left);
21404        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
21405        Some(utf16_offset.0)
21406    }
21407}
21408
21409trait SelectionExt {
21410    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
21411    fn spanned_rows(
21412        &self,
21413        include_end_if_at_line_start: bool,
21414        map: &DisplaySnapshot,
21415    ) -> Range<MultiBufferRow>;
21416}
21417
21418impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
21419    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
21420        let start = self
21421            .start
21422            .to_point(&map.buffer_snapshot)
21423            .to_display_point(map);
21424        let end = self
21425            .end
21426            .to_point(&map.buffer_snapshot)
21427            .to_display_point(map);
21428        if self.reversed {
21429            end..start
21430        } else {
21431            start..end
21432        }
21433    }
21434
21435    fn spanned_rows(
21436        &self,
21437        include_end_if_at_line_start: bool,
21438        map: &DisplaySnapshot,
21439    ) -> Range<MultiBufferRow> {
21440        let start = self.start.to_point(&map.buffer_snapshot);
21441        let mut end = self.end.to_point(&map.buffer_snapshot);
21442        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
21443            end.row -= 1;
21444        }
21445
21446        let buffer_start = map.prev_line_boundary(start).0;
21447        let buffer_end = map.next_line_boundary(end).0;
21448        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
21449    }
21450}
21451
21452impl<T: InvalidationRegion> InvalidationStack<T> {
21453    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
21454    where
21455        S: Clone + ToOffset,
21456    {
21457        while let Some(region) = self.last() {
21458            let all_selections_inside_invalidation_ranges =
21459                if selections.len() == region.ranges().len() {
21460                    selections
21461                        .iter()
21462                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
21463                        .all(|(selection, invalidation_range)| {
21464                            let head = selection.head().to_offset(buffer);
21465                            invalidation_range.start <= head && invalidation_range.end >= head
21466                        })
21467                } else {
21468                    false
21469                };
21470
21471            if all_selections_inside_invalidation_ranges {
21472                break;
21473            } else {
21474                self.pop();
21475            }
21476        }
21477    }
21478}
21479
21480impl<T> Default for InvalidationStack<T> {
21481    fn default() -> Self {
21482        Self(Default::default())
21483    }
21484}
21485
21486impl<T> Deref for InvalidationStack<T> {
21487    type Target = Vec<T>;
21488
21489    fn deref(&self) -> &Self::Target {
21490        &self.0
21491    }
21492}
21493
21494impl<T> DerefMut for InvalidationStack<T> {
21495    fn deref_mut(&mut self) -> &mut Self::Target {
21496        &mut self.0
21497    }
21498}
21499
21500impl InvalidationRegion for SnippetState {
21501    fn ranges(&self) -> &[Range<Anchor>] {
21502        &self.ranges[self.active_index]
21503    }
21504}
21505
21506fn inline_completion_edit_text(
21507    current_snapshot: &BufferSnapshot,
21508    edits: &[(Range<Anchor>, String)],
21509    edit_preview: &EditPreview,
21510    include_deletions: bool,
21511    cx: &App,
21512) -> HighlightedText {
21513    let edits = edits
21514        .iter()
21515        .map(|(anchor, text)| {
21516            (
21517                anchor.start.text_anchor..anchor.end.text_anchor,
21518                text.clone(),
21519            )
21520        })
21521        .collect::<Vec<_>>();
21522
21523    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21524}
21525
21526pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21527    match severity {
21528        lsp::DiagnosticSeverity::ERROR => colors.error,
21529        lsp::DiagnosticSeverity::WARNING => colors.warning,
21530        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21531        lsp::DiagnosticSeverity::HINT => colors.info,
21532        _ => colors.ignored,
21533    }
21534}
21535
21536pub fn styled_runs_for_code_label<'a>(
21537    label: &'a CodeLabel,
21538    syntax_theme: &'a theme::SyntaxTheme,
21539) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21540    let fade_out = HighlightStyle {
21541        fade_out: Some(0.35),
21542        ..Default::default()
21543    };
21544
21545    let mut prev_end = label.filter_range.end;
21546    label
21547        .runs
21548        .iter()
21549        .enumerate()
21550        .flat_map(move |(ix, (range, highlight_id))| {
21551            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21552                style
21553            } else {
21554                return Default::default();
21555            };
21556            let mut muted_style = style;
21557            muted_style.highlight(fade_out);
21558
21559            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21560            if range.start >= label.filter_range.end {
21561                if range.start > prev_end {
21562                    runs.push((prev_end..range.start, fade_out));
21563                }
21564                runs.push((range.clone(), muted_style));
21565            } else if range.end <= label.filter_range.end {
21566                runs.push((range.clone(), style));
21567            } else {
21568                runs.push((range.start..label.filter_range.end, style));
21569                runs.push((label.filter_range.end..range.end, muted_style));
21570            }
21571            prev_end = cmp::max(prev_end, range.end);
21572
21573            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21574                runs.push((prev_end..label.text.len(), fade_out));
21575            }
21576
21577            runs
21578        })
21579}
21580
21581pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21582    let mut prev_index = 0;
21583    let mut prev_codepoint: Option<char> = None;
21584    text.char_indices()
21585        .chain([(text.len(), '\0')])
21586        .filter_map(move |(index, codepoint)| {
21587            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21588            let is_boundary = index == text.len()
21589                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21590                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21591            if is_boundary {
21592                let chunk = &text[prev_index..index];
21593                prev_index = index;
21594                Some(chunk)
21595            } else {
21596                None
21597            }
21598        })
21599}
21600
21601pub trait RangeToAnchorExt: Sized {
21602    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21603
21604    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21605        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21606        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21607    }
21608}
21609
21610impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21611    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21612        let start_offset = self.start.to_offset(snapshot);
21613        let end_offset = self.end.to_offset(snapshot);
21614        if start_offset == end_offset {
21615            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21616        } else {
21617            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21618        }
21619    }
21620}
21621
21622pub trait RowExt {
21623    fn as_f32(&self) -> f32;
21624
21625    fn next_row(&self) -> Self;
21626
21627    fn previous_row(&self) -> Self;
21628
21629    fn minus(&self, other: Self) -> u32;
21630}
21631
21632impl RowExt for DisplayRow {
21633    fn as_f32(&self) -> f32 {
21634        self.0 as f32
21635    }
21636
21637    fn next_row(&self) -> Self {
21638        Self(self.0 + 1)
21639    }
21640
21641    fn previous_row(&self) -> Self {
21642        Self(self.0.saturating_sub(1))
21643    }
21644
21645    fn minus(&self, other: Self) -> u32 {
21646        self.0 - other.0
21647    }
21648}
21649
21650impl RowExt for MultiBufferRow {
21651    fn as_f32(&self) -> f32 {
21652        self.0 as f32
21653    }
21654
21655    fn next_row(&self) -> Self {
21656        Self(self.0 + 1)
21657    }
21658
21659    fn previous_row(&self) -> Self {
21660        Self(self.0.saturating_sub(1))
21661    }
21662
21663    fn minus(&self, other: Self) -> u32 {
21664        self.0 - other.0
21665    }
21666}
21667
21668trait RowRangeExt {
21669    type Row;
21670
21671    fn len(&self) -> usize;
21672
21673    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21674}
21675
21676impl RowRangeExt for Range<MultiBufferRow> {
21677    type Row = MultiBufferRow;
21678
21679    fn len(&self) -> usize {
21680        (self.end.0 - self.start.0) as usize
21681    }
21682
21683    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21684        (self.start.0..self.end.0).map(MultiBufferRow)
21685    }
21686}
21687
21688impl RowRangeExt for Range<DisplayRow> {
21689    type Row = DisplayRow;
21690
21691    fn len(&self) -> usize {
21692        (self.end.0 - self.start.0) as usize
21693    }
21694
21695    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21696        (self.start.0..self.end.0).map(DisplayRow)
21697    }
21698}
21699
21700/// If select range has more than one line, we
21701/// just point the cursor to range.start.
21702fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21703    if range.start.row == range.end.row {
21704        range
21705    } else {
21706        range.start..range.start
21707    }
21708}
21709pub struct KillRing(ClipboardItem);
21710impl Global for KillRing {}
21711
21712const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21713
21714enum BreakpointPromptEditAction {
21715    Log,
21716    Condition,
21717    HitCondition,
21718}
21719
21720struct BreakpointPromptEditor {
21721    pub(crate) prompt: Entity<Editor>,
21722    editor: WeakEntity<Editor>,
21723    breakpoint_anchor: Anchor,
21724    breakpoint: Breakpoint,
21725    edit_action: BreakpointPromptEditAction,
21726    block_ids: HashSet<CustomBlockId>,
21727    editor_margins: Arc<Mutex<EditorMargins>>,
21728    _subscriptions: Vec<Subscription>,
21729}
21730
21731impl BreakpointPromptEditor {
21732    const MAX_LINES: u8 = 4;
21733
21734    fn new(
21735        editor: WeakEntity<Editor>,
21736        breakpoint_anchor: Anchor,
21737        breakpoint: Breakpoint,
21738        edit_action: BreakpointPromptEditAction,
21739        window: &mut Window,
21740        cx: &mut Context<Self>,
21741    ) -> Self {
21742        let base_text = match edit_action {
21743            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21744            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21745            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21746        }
21747        .map(|msg| msg.to_string())
21748        .unwrap_or_default();
21749
21750        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21751        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21752
21753        let prompt = cx.new(|cx| {
21754            let mut prompt = Editor::new(
21755                EditorMode::AutoHeight {
21756                    max_lines: Self::MAX_LINES as usize,
21757                },
21758                buffer,
21759                None,
21760                window,
21761                cx,
21762            );
21763            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21764            prompt.set_show_cursor_when_unfocused(false, cx);
21765            prompt.set_placeholder_text(
21766                match edit_action {
21767                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21768                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21769                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21770                },
21771                cx,
21772            );
21773
21774            prompt
21775        });
21776
21777        Self {
21778            prompt,
21779            editor,
21780            breakpoint_anchor,
21781            breakpoint,
21782            edit_action,
21783            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21784            block_ids: Default::default(),
21785            _subscriptions: vec![],
21786        }
21787    }
21788
21789    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21790        self.block_ids.extend(block_ids)
21791    }
21792
21793    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21794        if let Some(editor) = self.editor.upgrade() {
21795            let message = self
21796                .prompt
21797                .read(cx)
21798                .buffer
21799                .read(cx)
21800                .as_singleton()
21801                .expect("A multi buffer in breakpoint prompt isn't possible")
21802                .read(cx)
21803                .as_rope()
21804                .to_string();
21805
21806            editor.update(cx, |editor, cx| {
21807                editor.edit_breakpoint_at_anchor(
21808                    self.breakpoint_anchor,
21809                    self.breakpoint.clone(),
21810                    match self.edit_action {
21811                        BreakpointPromptEditAction::Log => {
21812                            BreakpointEditAction::EditLogMessage(message.into())
21813                        }
21814                        BreakpointPromptEditAction::Condition => {
21815                            BreakpointEditAction::EditCondition(message.into())
21816                        }
21817                        BreakpointPromptEditAction::HitCondition => {
21818                            BreakpointEditAction::EditHitCondition(message.into())
21819                        }
21820                    },
21821                    cx,
21822                );
21823
21824                editor.remove_blocks(self.block_ids.clone(), None, cx);
21825                cx.focus_self(window);
21826            });
21827        }
21828    }
21829
21830    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21831        self.editor
21832            .update(cx, |editor, cx| {
21833                editor.remove_blocks(self.block_ids.clone(), None, cx);
21834                window.focus(&editor.focus_handle);
21835            })
21836            .log_err();
21837    }
21838
21839    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
21840        let settings = ThemeSettings::get_global(cx);
21841        let text_style = TextStyle {
21842            color: if self.prompt.read(cx).read_only(cx) {
21843                cx.theme().colors().text_disabled
21844            } else {
21845                cx.theme().colors().text
21846            },
21847            font_family: settings.buffer_font.family.clone(),
21848            font_fallbacks: settings.buffer_font.fallbacks.clone(),
21849            font_size: settings.buffer_font_size(cx).into(),
21850            font_weight: settings.buffer_font.weight,
21851            line_height: relative(settings.buffer_line_height.value()),
21852            ..Default::default()
21853        };
21854        EditorElement::new(
21855            &self.prompt,
21856            EditorStyle {
21857                background: cx.theme().colors().editor_background,
21858                local_player: cx.theme().players().local(),
21859                text: text_style,
21860                ..Default::default()
21861            },
21862        )
21863    }
21864}
21865
21866impl Render for BreakpointPromptEditor {
21867    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21868        let editor_margins = *self.editor_margins.lock();
21869        let gutter_dimensions = editor_margins.gutter;
21870        h_flex()
21871            .key_context("Editor")
21872            .bg(cx.theme().colors().editor_background)
21873            .border_y_1()
21874            .border_color(cx.theme().status().info_border)
21875            .size_full()
21876            .py(window.line_height() / 2.5)
21877            .on_action(cx.listener(Self::confirm))
21878            .on_action(cx.listener(Self::cancel))
21879            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
21880            .child(div().flex_1().child(self.render_prompt_editor(cx)))
21881    }
21882}
21883
21884impl Focusable for BreakpointPromptEditor {
21885    fn focus_handle(&self, cx: &App) -> FocusHandle {
21886        self.prompt.focus_handle(cx)
21887    }
21888}
21889
21890fn all_edits_insertions_or_deletions(
21891    edits: &Vec<(Range<Anchor>, String)>,
21892    snapshot: &MultiBufferSnapshot,
21893) -> bool {
21894    let mut all_insertions = true;
21895    let mut all_deletions = true;
21896
21897    for (range, new_text) in edits.iter() {
21898        let range_is_empty = range.to_offset(&snapshot).is_empty();
21899        let text_is_empty = new_text.is_empty();
21900
21901        if range_is_empty != text_is_empty {
21902            if range_is_empty {
21903                all_deletions = false;
21904            } else {
21905                all_insertions = false;
21906            }
21907        } else {
21908            return false;
21909        }
21910
21911        if !all_insertions && !all_deletions {
21912            return false;
21913        }
21914    }
21915    all_insertions || all_deletions
21916}
21917
21918struct MissingEditPredictionKeybindingTooltip;
21919
21920impl Render for MissingEditPredictionKeybindingTooltip {
21921    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21922        ui::tooltip_container(window, cx, |container, _, cx| {
21923            container
21924                .flex_shrink_0()
21925                .max_w_80()
21926                .min_h(rems_from_px(124.))
21927                .justify_between()
21928                .child(
21929                    v_flex()
21930                        .flex_1()
21931                        .text_ui_sm(cx)
21932                        .child(Label::new("Conflict with Accept Keybinding"))
21933                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
21934                )
21935                .child(
21936                    h_flex()
21937                        .pb_1()
21938                        .gap_1()
21939                        .items_end()
21940                        .w_full()
21941                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
21942                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
21943                        }))
21944                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
21945                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
21946                        })),
21947                )
21948        })
21949    }
21950}
21951
21952#[derive(Debug, Clone, Copy, PartialEq)]
21953pub struct LineHighlight {
21954    pub background: Background,
21955    pub border: Option<gpui::Hsla>,
21956    pub include_gutter: bool,
21957    pub type_id: Option<TypeId>,
21958}
21959
21960fn render_diff_hunk_controls(
21961    row: u32,
21962    status: &DiffHunkStatus,
21963    hunk_range: Range<Anchor>,
21964    is_created_file: bool,
21965    line_height: Pixels,
21966    editor: &Entity<Editor>,
21967    _window: &mut Window,
21968    cx: &mut App,
21969) -> AnyElement {
21970    h_flex()
21971        .h(line_height)
21972        .mr_1()
21973        .gap_1()
21974        .px_0p5()
21975        .pb_1()
21976        .border_x_1()
21977        .border_b_1()
21978        .border_color(cx.theme().colors().border_variant)
21979        .rounded_b_lg()
21980        .bg(cx.theme().colors().editor_background)
21981        .gap_1()
21982        .block_mouse_except_scroll()
21983        .shadow_md()
21984        .child(if status.has_secondary_hunk() {
21985            Button::new(("stage", row as u64), "Stage")
21986                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21987                .tooltip({
21988                    let focus_handle = editor.focus_handle(cx);
21989                    move |window, cx| {
21990                        Tooltip::for_action_in(
21991                            "Stage Hunk",
21992                            &::git::ToggleStaged,
21993                            &focus_handle,
21994                            window,
21995                            cx,
21996                        )
21997                    }
21998                })
21999                .on_click({
22000                    let editor = editor.clone();
22001                    move |_event, _window, cx| {
22002                        editor.update(cx, |editor, cx| {
22003                            editor.stage_or_unstage_diff_hunks(
22004                                true,
22005                                vec![hunk_range.start..hunk_range.start],
22006                                cx,
22007                            );
22008                        });
22009                    }
22010                })
22011        } else {
22012            Button::new(("unstage", row as u64), "Unstage")
22013                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22014                .tooltip({
22015                    let focus_handle = editor.focus_handle(cx);
22016                    move |window, cx| {
22017                        Tooltip::for_action_in(
22018                            "Unstage Hunk",
22019                            &::git::ToggleStaged,
22020                            &focus_handle,
22021                            window,
22022                            cx,
22023                        )
22024                    }
22025                })
22026                .on_click({
22027                    let editor = editor.clone();
22028                    move |_event, _window, cx| {
22029                        editor.update(cx, |editor, cx| {
22030                            editor.stage_or_unstage_diff_hunks(
22031                                false,
22032                                vec![hunk_range.start..hunk_range.start],
22033                                cx,
22034                            );
22035                        });
22036                    }
22037                })
22038        })
22039        .child(
22040            Button::new(("restore", row as u64), "Restore")
22041                .tooltip({
22042                    let focus_handle = editor.focus_handle(cx);
22043                    move |window, cx| {
22044                        Tooltip::for_action_in(
22045                            "Restore Hunk",
22046                            &::git::Restore,
22047                            &focus_handle,
22048                            window,
22049                            cx,
22050                        )
22051                    }
22052                })
22053                .on_click({
22054                    let editor = editor.clone();
22055                    move |_event, window, cx| {
22056                        editor.update(cx, |editor, cx| {
22057                            let snapshot = editor.snapshot(window, cx);
22058                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22059                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22060                        });
22061                    }
22062                })
22063                .disabled(is_created_file),
22064        )
22065        .when(
22066            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22067            |el| {
22068                el.child(
22069                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22070                        .shape(IconButtonShape::Square)
22071                        .icon_size(IconSize::Small)
22072                        // .disabled(!has_multiple_hunks)
22073                        .tooltip({
22074                            let focus_handle = editor.focus_handle(cx);
22075                            move |window, cx| {
22076                                Tooltip::for_action_in(
22077                                    "Next Hunk",
22078                                    &GoToHunk,
22079                                    &focus_handle,
22080                                    window,
22081                                    cx,
22082                                )
22083                            }
22084                        })
22085                        .on_click({
22086                            let editor = editor.clone();
22087                            move |_event, window, cx| {
22088                                editor.update(cx, |editor, cx| {
22089                                    let snapshot = editor.snapshot(window, cx);
22090                                    let position =
22091                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22092                                    editor.go_to_hunk_before_or_after_position(
22093                                        &snapshot,
22094                                        position,
22095                                        Direction::Next,
22096                                        window,
22097                                        cx,
22098                                    );
22099                                    editor.expand_selected_diff_hunks(cx);
22100                                });
22101                            }
22102                        }),
22103                )
22104                .child(
22105                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
22106                        .shape(IconButtonShape::Square)
22107                        .icon_size(IconSize::Small)
22108                        // .disabled(!has_multiple_hunks)
22109                        .tooltip({
22110                            let focus_handle = editor.focus_handle(cx);
22111                            move |window, cx| {
22112                                Tooltip::for_action_in(
22113                                    "Previous Hunk",
22114                                    &GoToPreviousHunk,
22115                                    &focus_handle,
22116                                    window,
22117                                    cx,
22118                                )
22119                            }
22120                        })
22121                        .on_click({
22122                            let editor = editor.clone();
22123                            move |_event, window, cx| {
22124                                editor.update(cx, |editor, cx| {
22125                                    let snapshot = editor.snapshot(window, cx);
22126                                    let point =
22127                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
22128                                    editor.go_to_hunk_before_or_after_position(
22129                                        &snapshot,
22130                                        point,
22131                                        Direction::Prev,
22132                                        window,
22133                                        cx,
22134                                    );
22135                                    editor.expand_selected_diff_hunks(cx);
22136                                });
22137                            }
22138                        }),
22139                )
22140            },
22141        )
22142        .into_any_element()
22143}