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            let editor = editor.upgrade().unwrap();
15707
15708            if let Some(debounce) = debounce {
15709                cx.background_executor().timer(debounce).await;
15710            }
15711            let Some(snapshot) = editor
15712                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15713                .ok()
15714            else {
15715                return;
15716            };
15717
15718            let new_inline_diagnostics = cx
15719                .background_spawn(async move {
15720                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15721                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15722                        let message = diagnostic_entry
15723                            .diagnostic
15724                            .message
15725                            .split_once('\n')
15726                            .map(|(line, _)| line)
15727                            .map(SharedString::new)
15728                            .unwrap_or_else(|| {
15729                                SharedString::from(diagnostic_entry.diagnostic.message)
15730                            });
15731                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15732                        let (Ok(i) | Err(i)) = inline_diagnostics
15733                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15734                        inline_diagnostics.insert(
15735                            i,
15736                            (
15737                                start_anchor,
15738                                InlineDiagnostic {
15739                                    message,
15740                                    group_id: diagnostic_entry.diagnostic.group_id,
15741                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15742                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15743                                    severity: diagnostic_entry.diagnostic.severity,
15744                                },
15745                            ),
15746                        );
15747                    }
15748                    inline_diagnostics
15749                })
15750                .await;
15751
15752            editor
15753                .update(cx, |editor, cx| {
15754                    editor.inline_diagnostics = new_inline_diagnostics;
15755                    cx.notify();
15756                })
15757                .ok();
15758        });
15759    }
15760
15761    pub fn set_selections_from_remote(
15762        &mut self,
15763        selections: Vec<Selection<Anchor>>,
15764        pending_selection: Option<Selection<Anchor>>,
15765        window: &mut Window,
15766        cx: &mut Context<Self>,
15767    ) {
15768        let old_cursor_position = self.selections.newest_anchor().head();
15769        self.selections.change_with(cx, |s| {
15770            s.select_anchors(selections);
15771            if let Some(pending_selection) = pending_selection {
15772                s.set_pending(pending_selection, SelectMode::Character);
15773            } else {
15774                s.clear_pending();
15775            }
15776        });
15777        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15778    }
15779
15780    pub fn transact(
15781        &mut self,
15782        window: &mut Window,
15783        cx: &mut Context<Self>,
15784        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15785    ) -> Option<TransactionId> {
15786        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15787            this.start_transaction_at(Instant::now(), window, cx);
15788            update(this, window, cx);
15789            this.end_transaction_at(Instant::now(), cx)
15790        })
15791    }
15792
15793    pub fn start_transaction_at(
15794        &mut self,
15795        now: Instant,
15796        window: &mut Window,
15797        cx: &mut Context<Self>,
15798    ) {
15799        self.end_selection(window, cx);
15800        if let Some(tx_id) = self
15801            .buffer
15802            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15803        {
15804            self.selection_history
15805                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15806            cx.emit(EditorEvent::TransactionBegun {
15807                transaction_id: tx_id,
15808            })
15809        }
15810    }
15811
15812    pub fn end_transaction_at(
15813        &mut self,
15814        now: Instant,
15815        cx: &mut Context<Self>,
15816    ) -> Option<TransactionId> {
15817        if let Some(transaction_id) = self
15818            .buffer
15819            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15820        {
15821            if let Some((_, end_selections)) =
15822                self.selection_history.transaction_mut(transaction_id)
15823            {
15824                *end_selections = Some(self.selections.disjoint_anchors());
15825            } else {
15826                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15827            }
15828
15829            cx.emit(EditorEvent::Edited { transaction_id });
15830            Some(transaction_id)
15831        } else {
15832            None
15833        }
15834    }
15835
15836    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15837        if self.selection_mark_mode {
15838            self.change_selections(None, window, cx, |s| {
15839                s.move_with(|_, sel| {
15840                    sel.collapse_to(sel.head(), SelectionGoal::None);
15841                });
15842            })
15843        }
15844        self.selection_mark_mode = true;
15845        cx.notify();
15846    }
15847
15848    pub fn swap_selection_ends(
15849        &mut self,
15850        _: &actions::SwapSelectionEnds,
15851        window: &mut Window,
15852        cx: &mut Context<Self>,
15853    ) {
15854        self.change_selections(None, window, cx, |s| {
15855            s.move_with(|_, sel| {
15856                if sel.start != sel.end {
15857                    sel.reversed = !sel.reversed
15858                }
15859            });
15860        });
15861        self.request_autoscroll(Autoscroll::newest(), cx);
15862        cx.notify();
15863    }
15864
15865    pub fn toggle_fold(
15866        &mut self,
15867        _: &actions::ToggleFold,
15868        window: &mut Window,
15869        cx: &mut Context<Self>,
15870    ) {
15871        if self.is_singleton(cx) {
15872            let selection = self.selections.newest::<Point>(cx);
15873
15874            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15875            let range = if selection.is_empty() {
15876                let point = selection.head().to_display_point(&display_map);
15877                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15878                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15879                    .to_point(&display_map);
15880                start..end
15881            } else {
15882                selection.range()
15883            };
15884            if display_map.folds_in_range(range).next().is_some() {
15885                self.unfold_lines(&Default::default(), window, cx)
15886            } else {
15887                self.fold(&Default::default(), window, cx)
15888            }
15889        } else {
15890            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15891            let buffer_ids: HashSet<_> = self
15892                .selections
15893                .disjoint_anchor_ranges()
15894                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15895                .collect();
15896
15897            let should_unfold = buffer_ids
15898                .iter()
15899                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15900
15901            for buffer_id in buffer_ids {
15902                if should_unfold {
15903                    self.unfold_buffer(buffer_id, cx);
15904                } else {
15905                    self.fold_buffer(buffer_id, cx);
15906                }
15907            }
15908        }
15909    }
15910
15911    pub fn toggle_fold_recursive(
15912        &mut self,
15913        _: &actions::ToggleFoldRecursive,
15914        window: &mut Window,
15915        cx: &mut Context<Self>,
15916    ) {
15917        let selection = self.selections.newest::<Point>(cx);
15918
15919        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15920        let range = if selection.is_empty() {
15921            let point = selection.head().to_display_point(&display_map);
15922            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15923            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15924                .to_point(&display_map);
15925            start..end
15926        } else {
15927            selection.range()
15928        };
15929        if display_map.folds_in_range(range).next().is_some() {
15930            self.unfold_recursive(&Default::default(), window, cx)
15931        } else {
15932            self.fold_recursive(&Default::default(), window, cx)
15933        }
15934    }
15935
15936    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15937        if self.is_singleton(cx) {
15938            let mut to_fold = Vec::new();
15939            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15940            let selections = self.selections.all_adjusted(cx);
15941
15942            for selection in selections {
15943                let range = selection.range().sorted();
15944                let buffer_start_row = range.start.row;
15945
15946                if range.start.row != range.end.row {
15947                    let mut found = false;
15948                    let mut row = range.start.row;
15949                    while row <= range.end.row {
15950                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15951                        {
15952                            found = true;
15953                            row = crease.range().end.row + 1;
15954                            to_fold.push(crease);
15955                        } else {
15956                            row += 1
15957                        }
15958                    }
15959                    if found {
15960                        continue;
15961                    }
15962                }
15963
15964                for row in (0..=range.start.row).rev() {
15965                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15966                        if crease.range().end.row >= buffer_start_row {
15967                            to_fold.push(crease);
15968                            if row <= range.start.row {
15969                                break;
15970                            }
15971                        }
15972                    }
15973                }
15974            }
15975
15976            self.fold_creases(to_fold, true, window, cx);
15977        } else {
15978            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15979            let buffer_ids = self
15980                .selections
15981                .disjoint_anchor_ranges()
15982                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15983                .collect::<HashSet<_>>();
15984            for buffer_id in buffer_ids {
15985                self.fold_buffer(buffer_id, cx);
15986            }
15987        }
15988    }
15989
15990    fn fold_at_level(
15991        &mut self,
15992        fold_at: &FoldAtLevel,
15993        window: &mut Window,
15994        cx: &mut Context<Self>,
15995    ) {
15996        if !self.buffer.read(cx).is_singleton() {
15997            return;
15998        }
15999
16000        let fold_at_level = fold_at.0;
16001        let snapshot = self.buffer.read(cx).snapshot(cx);
16002        let mut to_fold = Vec::new();
16003        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16004
16005        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16006            while start_row < end_row {
16007                match self
16008                    .snapshot(window, cx)
16009                    .crease_for_buffer_row(MultiBufferRow(start_row))
16010                {
16011                    Some(crease) => {
16012                        let nested_start_row = crease.range().start.row + 1;
16013                        let nested_end_row = crease.range().end.row;
16014
16015                        if current_level < fold_at_level {
16016                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16017                        } else if current_level == fold_at_level {
16018                            to_fold.push(crease);
16019                        }
16020
16021                        start_row = nested_end_row + 1;
16022                    }
16023                    None => start_row += 1,
16024                }
16025            }
16026        }
16027
16028        self.fold_creases(to_fold, true, window, cx);
16029    }
16030
16031    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16032        if self.buffer.read(cx).is_singleton() {
16033            let mut fold_ranges = Vec::new();
16034            let snapshot = self.buffer.read(cx).snapshot(cx);
16035
16036            for row in 0..snapshot.max_row().0 {
16037                if let Some(foldable_range) = self
16038                    .snapshot(window, cx)
16039                    .crease_for_buffer_row(MultiBufferRow(row))
16040                {
16041                    fold_ranges.push(foldable_range);
16042                }
16043            }
16044
16045            self.fold_creases(fold_ranges, true, window, cx);
16046        } else {
16047            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16048                editor
16049                    .update_in(cx, |editor, _, cx| {
16050                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16051                            editor.fold_buffer(buffer_id, cx);
16052                        }
16053                    })
16054                    .ok();
16055            });
16056        }
16057    }
16058
16059    pub fn fold_function_bodies(
16060        &mut self,
16061        _: &actions::FoldFunctionBodies,
16062        window: &mut Window,
16063        cx: &mut Context<Self>,
16064    ) {
16065        let snapshot = self.buffer.read(cx).snapshot(cx);
16066
16067        let ranges = snapshot
16068            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16069            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16070            .collect::<Vec<_>>();
16071
16072        let creases = ranges
16073            .into_iter()
16074            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16075            .collect();
16076
16077        self.fold_creases(creases, true, window, cx);
16078    }
16079
16080    pub fn fold_recursive(
16081        &mut self,
16082        _: &actions::FoldRecursive,
16083        window: &mut Window,
16084        cx: &mut Context<Self>,
16085    ) {
16086        let mut to_fold = Vec::new();
16087        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16088        let selections = self.selections.all_adjusted(cx);
16089
16090        for selection in selections {
16091            let range = selection.range().sorted();
16092            let buffer_start_row = range.start.row;
16093
16094            if range.start.row != range.end.row {
16095                let mut found = false;
16096                for row in range.start.row..=range.end.row {
16097                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16098                        found = true;
16099                        to_fold.push(crease);
16100                    }
16101                }
16102                if found {
16103                    continue;
16104                }
16105            }
16106
16107            for row in (0..=range.start.row).rev() {
16108                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16109                    if crease.range().end.row >= buffer_start_row {
16110                        to_fold.push(crease);
16111                    } else {
16112                        break;
16113                    }
16114                }
16115            }
16116        }
16117
16118        self.fold_creases(to_fold, true, window, cx);
16119    }
16120
16121    pub fn fold_at(
16122        &mut self,
16123        buffer_row: MultiBufferRow,
16124        window: &mut Window,
16125        cx: &mut Context<Self>,
16126    ) {
16127        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16128
16129        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16130            let autoscroll = self
16131                .selections
16132                .all::<Point>(cx)
16133                .iter()
16134                .any(|selection| crease.range().overlaps(&selection.range()));
16135
16136            self.fold_creases(vec![crease], autoscroll, window, cx);
16137        }
16138    }
16139
16140    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16141        if self.is_singleton(cx) {
16142            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16143            let buffer = &display_map.buffer_snapshot;
16144            let selections = self.selections.all::<Point>(cx);
16145            let ranges = selections
16146                .iter()
16147                .map(|s| {
16148                    let range = s.display_range(&display_map).sorted();
16149                    let mut start = range.start.to_point(&display_map);
16150                    let mut end = range.end.to_point(&display_map);
16151                    start.column = 0;
16152                    end.column = buffer.line_len(MultiBufferRow(end.row));
16153                    start..end
16154                })
16155                .collect::<Vec<_>>();
16156
16157            self.unfold_ranges(&ranges, true, true, cx);
16158        } else {
16159            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16160            let buffer_ids = self
16161                .selections
16162                .disjoint_anchor_ranges()
16163                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16164                .collect::<HashSet<_>>();
16165            for buffer_id in buffer_ids {
16166                self.unfold_buffer(buffer_id, cx);
16167            }
16168        }
16169    }
16170
16171    pub fn unfold_recursive(
16172        &mut self,
16173        _: &UnfoldRecursive,
16174        _window: &mut Window,
16175        cx: &mut Context<Self>,
16176    ) {
16177        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16178        let selections = self.selections.all::<Point>(cx);
16179        let ranges = selections
16180            .iter()
16181            .map(|s| {
16182                let mut range = s.display_range(&display_map).sorted();
16183                *range.start.column_mut() = 0;
16184                *range.end.column_mut() = display_map.line_len(range.end.row());
16185                let start = range.start.to_point(&display_map);
16186                let end = range.end.to_point(&display_map);
16187                start..end
16188            })
16189            .collect::<Vec<_>>();
16190
16191        self.unfold_ranges(&ranges, true, true, cx);
16192    }
16193
16194    pub fn unfold_at(
16195        &mut self,
16196        buffer_row: MultiBufferRow,
16197        _window: &mut Window,
16198        cx: &mut Context<Self>,
16199    ) {
16200        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16201
16202        let intersection_range = Point::new(buffer_row.0, 0)
16203            ..Point::new(
16204                buffer_row.0,
16205                display_map.buffer_snapshot.line_len(buffer_row),
16206            );
16207
16208        let autoscroll = self
16209            .selections
16210            .all::<Point>(cx)
16211            .iter()
16212            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16213
16214        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16215    }
16216
16217    pub fn unfold_all(
16218        &mut self,
16219        _: &actions::UnfoldAll,
16220        _window: &mut Window,
16221        cx: &mut Context<Self>,
16222    ) {
16223        if self.buffer.read(cx).is_singleton() {
16224            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16225            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16226        } else {
16227            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16228                editor
16229                    .update(cx, |editor, cx| {
16230                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16231                            editor.unfold_buffer(buffer_id, cx);
16232                        }
16233                    })
16234                    .ok();
16235            });
16236        }
16237    }
16238
16239    pub fn fold_selected_ranges(
16240        &mut self,
16241        _: &FoldSelectedRanges,
16242        window: &mut Window,
16243        cx: &mut Context<Self>,
16244    ) {
16245        let selections = self.selections.all_adjusted(cx);
16246        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16247        let ranges = selections
16248            .into_iter()
16249            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16250            .collect::<Vec<_>>();
16251        self.fold_creases(ranges, true, window, cx);
16252    }
16253
16254    pub fn fold_ranges<T: ToOffset + Clone>(
16255        &mut self,
16256        ranges: Vec<Range<T>>,
16257        auto_scroll: bool,
16258        window: &mut Window,
16259        cx: &mut Context<Self>,
16260    ) {
16261        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16262        let ranges = ranges
16263            .into_iter()
16264            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16265            .collect::<Vec<_>>();
16266        self.fold_creases(ranges, auto_scroll, window, cx);
16267    }
16268
16269    pub fn fold_creases<T: ToOffset + Clone>(
16270        &mut self,
16271        creases: Vec<Crease<T>>,
16272        auto_scroll: bool,
16273        _window: &mut Window,
16274        cx: &mut Context<Self>,
16275    ) {
16276        if creases.is_empty() {
16277            return;
16278        }
16279
16280        let mut buffers_affected = HashSet::default();
16281        let multi_buffer = self.buffer().read(cx);
16282        for crease in &creases {
16283            if let Some((_, buffer, _)) =
16284                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16285            {
16286                buffers_affected.insert(buffer.read(cx).remote_id());
16287            };
16288        }
16289
16290        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16291
16292        if auto_scroll {
16293            self.request_autoscroll(Autoscroll::fit(), cx);
16294        }
16295
16296        cx.notify();
16297
16298        self.scrollbar_marker_state.dirty = true;
16299        self.folds_did_change(cx);
16300    }
16301
16302    /// Removes any folds whose ranges intersect any of the given ranges.
16303    pub fn unfold_ranges<T: ToOffset + Clone>(
16304        &mut self,
16305        ranges: &[Range<T>],
16306        inclusive: bool,
16307        auto_scroll: bool,
16308        cx: &mut Context<Self>,
16309    ) {
16310        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16311            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16312        });
16313        self.folds_did_change(cx);
16314    }
16315
16316    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16317        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16318            return;
16319        }
16320        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16321        self.display_map.update(cx, |display_map, cx| {
16322            display_map.fold_buffers([buffer_id], cx)
16323        });
16324        cx.emit(EditorEvent::BufferFoldToggled {
16325            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16326            folded: true,
16327        });
16328        cx.notify();
16329    }
16330
16331    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16332        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16333            return;
16334        }
16335        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16336        self.display_map.update(cx, |display_map, cx| {
16337            display_map.unfold_buffers([buffer_id], cx);
16338        });
16339        cx.emit(EditorEvent::BufferFoldToggled {
16340            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16341            folded: false,
16342        });
16343        cx.notify();
16344    }
16345
16346    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16347        self.display_map.read(cx).is_buffer_folded(buffer)
16348    }
16349
16350    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16351        self.display_map.read(cx).folded_buffers()
16352    }
16353
16354    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16355        self.display_map.update(cx, |display_map, cx| {
16356            display_map.disable_header_for_buffer(buffer_id, cx);
16357        });
16358        cx.notify();
16359    }
16360
16361    /// Removes any folds with the given ranges.
16362    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16363        &mut self,
16364        ranges: &[Range<T>],
16365        type_id: TypeId,
16366        auto_scroll: bool,
16367        cx: &mut Context<Self>,
16368    ) {
16369        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16370            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16371        });
16372        self.folds_did_change(cx);
16373    }
16374
16375    fn remove_folds_with<T: ToOffset + Clone>(
16376        &mut self,
16377        ranges: &[Range<T>],
16378        auto_scroll: bool,
16379        cx: &mut Context<Self>,
16380        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16381    ) {
16382        if ranges.is_empty() {
16383            return;
16384        }
16385
16386        let mut buffers_affected = HashSet::default();
16387        let multi_buffer = self.buffer().read(cx);
16388        for range in ranges {
16389            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16390                buffers_affected.insert(buffer.read(cx).remote_id());
16391            };
16392        }
16393
16394        self.display_map.update(cx, update);
16395
16396        if auto_scroll {
16397            self.request_autoscroll(Autoscroll::fit(), cx);
16398        }
16399
16400        cx.notify();
16401        self.scrollbar_marker_state.dirty = true;
16402        self.active_indent_guides_state.dirty = true;
16403    }
16404
16405    pub fn update_fold_widths(
16406        &mut self,
16407        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16408        cx: &mut Context<Self>,
16409    ) -> bool {
16410        self.display_map
16411            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16412    }
16413
16414    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16415        self.display_map.read(cx).fold_placeholder.clone()
16416    }
16417
16418    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16419        self.buffer.update(cx, |buffer, cx| {
16420            buffer.set_all_diff_hunks_expanded(cx);
16421        });
16422    }
16423
16424    pub fn expand_all_diff_hunks(
16425        &mut self,
16426        _: &ExpandAllDiffHunks,
16427        _window: &mut Window,
16428        cx: &mut Context<Self>,
16429    ) {
16430        self.buffer.update(cx, |buffer, cx| {
16431            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16432        });
16433    }
16434
16435    pub fn toggle_selected_diff_hunks(
16436        &mut self,
16437        _: &ToggleSelectedDiffHunks,
16438        _window: &mut Window,
16439        cx: &mut Context<Self>,
16440    ) {
16441        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16442        self.toggle_diff_hunks_in_ranges(ranges, cx);
16443    }
16444
16445    pub fn diff_hunks_in_ranges<'a>(
16446        &'a self,
16447        ranges: &'a [Range<Anchor>],
16448        buffer: &'a MultiBufferSnapshot,
16449    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16450        ranges.iter().flat_map(move |range| {
16451            let end_excerpt_id = range.end.excerpt_id;
16452            let range = range.to_point(buffer);
16453            let mut peek_end = range.end;
16454            if range.end.row < buffer.max_row().0 {
16455                peek_end = Point::new(range.end.row + 1, 0);
16456            }
16457            buffer
16458                .diff_hunks_in_range(range.start..peek_end)
16459                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16460        })
16461    }
16462
16463    pub fn has_stageable_diff_hunks_in_ranges(
16464        &self,
16465        ranges: &[Range<Anchor>],
16466        snapshot: &MultiBufferSnapshot,
16467    ) -> bool {
16468        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16469        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16470    }
16471
16472    pub fn toggle_staged_selected_diff_hunks(
16473        &mut self,
16474        _: &::git::ToggleStaged,
16475        _: &mut Window,
16476        cx: &mut Context<Self>,
16477    ) {
16478        let snapshot = self.buffer.read(cx).snapshot(cx);
16479        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16480        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16481        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16482    }
16483
16484    pub fn set_render_diff_hunk_controls(
16485        &mut self,
16486        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16487        cx: &mut Context<Self>,
16488    ) {
16489        self.render_diff_hunk_controls = render_diff_hunk_controls;
16490        cx.notify();
16491    }
16492
16493    pub fn stage_and_next(
16494        &mut self,
16495        _: &::git::StageAndNext,
16496        window: &mut Window,
16497        cx: &mut Context<Self>,
16498    ) {
16499        self.do_stage_or_unstage_and_next(true, window, cx);
16500    }
16501
16502    pub fn unstage_and_next(
16503        &mut self,
16504        _: &::git::UnstageAndNext,
16505        window: &mut Window,
16506        cx: &mut Context<Self>,
16507    ) {
16508        self.do_stage_or_unstage_and_next(false, window, cx);
16509    }
16510
16511    pub fn stage_or_unstage_diff_hunks(
16512        &mut self,
16513        stage: bool,
16514        ranges: Vec<Range<Anchor>>,
16515        cx: &mut Context<Self>,
16516    ) {
16517        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16518        cx.spawn(async move |this, cx| {
16519            task.await?;
16520            this.update(cx, |this, cx| {
16521                let snapshot = this.buffer.read(cx).snapshot(cx);
16522                let chunk_by = this
16523                    .diff_hunks_in_ranges(&ranges, &snapshot)
16524                    .chunk_by(|hunk| hunk.buffer_id);
16525                for (buffer_id, hunks) in &chunk_by {
16526                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16527                }
16528            })
16529        })
16530        .detach_and_log_err(cx);
16531    }
16532
16533    fn save_buffers_for_ranges_if_needed(
16534        &mut self,
16535        ranges: &[Range<Anchor>],
16536        cx: &mut Context<Editor>,
16537    ) -> Task<Result<()>> {
16538        let multibuffer = self.buffer.read(cx);
16539        let snapshot = multibuffer.read(cx);
16540        let buffer_ids: HashSet<_> = ranges
16541            .iter()
16542            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16543            .collect();
16544        drop(snapshot);
16545
16546        let mut buffers = HashSet::default();
16547        for buffer_id in buffer_ids {
16548            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16549                let buffer = buffer_entity.read(cx);
16550                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16551                {
16552                    buffers.insert(buffer_entity);
16553                }
16554            }
16555        }
16556
16557        if let Some(project) = &self.project {
16558            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16559        } else {
16560            Task::ready(Ok(()))
16561        }
16562    }
16563
16564    fn do_stage_or_unstage_and_next(
16565        &mut self,
16566        stage: bool,
16567        window: &mut Window,
16568        cx: &mut Context<Self>,
16569    ) {
16570        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16571
16572        if ranges.iter().any(|range| range.start != range.end) {
16573            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16574            return;
16575        }
16576
16577        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16578        let snapshot = self.snapshot(window, cx);
16579        let position = self.selections.newest::<Point>(cx).head();
16580        let mut row = snapshot
16581            .buffer_snapshot
16582            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16583            .find(|hunk| hunk.row_range.start.0 > position.row)
16584            .map(|hunk| hunk.row_range.start);
16585
16586        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16587        // Outside of the project diff editor, wrap around to the beginning.
16588        if !all_diff_hunks_expanded {
16589            row = row.or_else(|| {
16590                snapshot
16591                    .buffer_snapshot
16592                    .diff_hunks_in_range(Point::zero()..position)
16593                    .find(|hunk| hunk.row_range.end.0 < position.row)
16594                    .map(|hunk| hunk.row_range.start)
16595            });
16596        }
16597
16598        if let Some(row) = row {
16599            let destination = Point::new(row.0, 0);
16600            let autoscroll = Autoscroll::center();
16601
16602            self.unfold_ranges(&[destination..destination], false, false, cx);
16603            self.change_selections(Some(autoscroll), window, cx, |s| {
16604                s.select_ranges([destination..destination]);
16605            });
16606        }
16607    }
16608
16609    fn do_stage_or_unstage(
16610        &self,
16611        stage: bool,
16612        buffer_id: BufferId,
16613        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16614        cx: &mut App,
16615    ) -> Option<()> {
16616        let project = self.project.as_ref()?;
16617        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16618        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16619        let buffer_snapshot = buffer.read(cx).snapshot();
16620        let file_exists = buffer_snapshot
16621            .file()
16622            .is_some_and(|file| file.disk_state().exists());
16623        diff.update(cx, |diff, cx| {
16624            diff.stage_or_unstage_hunks(
16625                stage,
16626                &hunks
16627                    .map(|hunk| buffer_diff::DiffHunk {
16628                        buffer_range: hunk.buffer_range,
16629                        diff_base_byte_range: hunk.diff_base_byte_range,
16630                        secondary_status: hunk.secondary_status,
16631                        range: Point::zero()..Point::zero(), // unused
16632                    })
16633                    .collect::<Vec<_>>(),
16634                &buffer_snapshot,
16635                file_exists,
16636                cx,
16637            )
16638        });
16639        None
16640    }
16641
16642    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16643        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16644        self.buffer
16645            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16646    }
16647
16648    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16649        self.buffer.update(cx, |buffer, cx| {
16650            let ranges = vec![Anchor::min()..Anchor::max()];
16651            if !buffer.all_diff_hunks_expanded()
16652                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16653            {
16654                buffer.collapse_diff_hunks(ranges, cx);
16655                true
16656            } else {
16657                false
16658            }
16659        })
16660    }
16661
16662    fn toggle_diff_hunks_in_ranges(
16663        &mut self,
16664        ranges: Vec<Range<Anchor>>,
16665        cx: &mut Context<Editor>,
16666    ) {
16667        self.buffer.update(cx, |buffer, cx| {
16668            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16669            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16670        })
16671    }
16672
16673    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16674        self.buffer.update(cx, |buffer, cx| {
16675            let snapshot = buffer.snapshot(cx);
16676            let excerpt_id = range.end.excerpt_id;
16677            let point_range = range.to_point(&snapshot);
16678            let expand = !buffer.single_hunk_is_expanded(range, cx);
16679            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16680        })
16681    }
16682
16683    pub(crate) fn apply_all_diff_hunks(
16684        &mut self,
16685        _: &ApplyAllDiffHunks,
16686        window: &mut Window,
16687        cx: &mut Context<Self>,
16688    ) {
16689        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16690
16691        let buffers = self.buffer.read(cx).all_buffers();
16692        for branch_buffer in buffers {
16693            branch_buffer.update(cx, |branch_buffer, cx| {
16694                branch_buffer.merge_into_base(Vec::new(), cx);
16695            });
16696        }
16697
16698        if let Some(project) = self.project.clone() {
16699            self.save(true, project, window, cx).detach_and_log_err(cx);
16700        }
16701    }
16702
16703    pub(crate) fn apply_selected_diff_hunks(
16704        &mut self,
16705        _: &ApplyDiffHunk,
16706        window: &mut Window,
16707        cx: &mut Context<Self>,
16708    ) {
16709        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16710        let snapshot = self.snapshot(window, cx);
16711        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16712        let mut ranges_by_buffer = HashMap::default();
16713        self.transact(window, cx, |editor, _window, cx| {
16714            for hunk in hunks {
16715                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16716                    ranges_by_buffer
16717                        .entry(buffer.clone())
16718                        .or_insert_with(Vec::new)
16719                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16720                }
16721            }
16722
16723            for (buffer, ranges) in ranges_by_buffer {
16724                buffer.update(cx, |buffer, cx| {
16725                    buffer.merge_into_base(ranges, cx);
16726                });
16727            }
16728        });
16729
16730        if let Some(project) = self.project.clone() {
16731            self.save(true, project, window, cx).detach_and_log_err(cx);
16732        }
16733    }
16734
16735    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16736        if hovered != self.gutter_hovered {
16737            self.gutter_hovered = hovered;
16738            cx.notify();
16739        }
16740    }
16741
16742    pub fn insert_blocks(
16743        &mut self,
16744        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16745        autoscroll: Option<Autoscroll>,
16746        cx: &mut Context<Self>,
16747    ) -> Vec<CustomBlockId> {
16748        let blocks = self
16749            .display_map
16750            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16751        if let Some(autoscroll) = autoscroll {
16752            self.request_autoscroll(autoscroll, cx);
16753        }
16754        cx.notify();
16755        blocks
16756    }
16757
16758    pub fn resize_blocks(
16759        &mut self,
16760        heights: HashMap<CustomBlockId, u32>,
16761        autoscroll: Option<Autoscroll>,
16762        cx: &mut Context<Self>,
16763    ) {
16764        self.display_map
16765            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16766        if let Some(autoscroll) = autoscroll {
16767            self.request_autoscroll(autoscroll, cx);
16768        }
16769        cx.notify();
16770    }
16771
16772    pub fn replace_blocks(
16773        &mut self,
16774        renderers: HashMap<CustomBlockId, RenderBlock>,
16775        autoscroll: Option<Autoscroll>,
16776        cx: &mut Context<Self>,
16777    ) {
16778        self.display_map
16779            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16780        if let Some(autoscroll) = autoscroll {
16781            self.request_autoscroll(autoscroll, cx);
16782        }
16783        cx.notify();
16784    }
16785
16786    pub fn remove_blocks(
16787        &mut self,
16788        block_ids: HashSet<CustomBlockId>,
16789        autoscroll: Option<Autoscroll>,
16790        cx: &mut Context<Self>,
16791    ) {
16792        self.display_map.update(cx, |display_map, cx| {
16793            display_map.remove_blocks(block_ids, cx)
16794        });
16795        if let Some(autoscroll) = autoscroll {
16796            self.request_autoscroll(autoscroll, cx);
16797        }
16798        cx.notify();
16799    }
16800
16801    pub fn row_for_block(
16802        &self,
16803        block_id: CustomBlockId,
16804        cx: &mut Context<Self>,
16805    ) -> Option<DisplayRow> {
16806        self.display_map
16807            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16808    }
16809
16810    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16811        self.focused_block = Some(focused_block);
16812    }
16813
16814    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16815        self.focused_block.take()
16816    }
16817
16818    pub fn insert_creases(
16819        &mut self,
16820        creases: impl IntoIterator<Item = Crease<Anchor>>,
16821        cx: &mut Context<Self>,
16822    ) -> Vec<CreaseId> {
16823        self.display_map
16824            .update(cx, |map, cx| map.insert_creases(creases, cx))
16825    }
16826
16827    pub fn remove_creases(
16828        &mut self,
16829        ids: impl IntoIterator<Item = CreaseId>,
16830        cx: &mut Context<Self>,
16831    ) -> Vec<(CreaseId, Range<Anchor>)> {
16832        self.display_map
16833            .update(cx, |map, cx| map.remove_creases(ids, cx))
16834    }
16835
16836    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16837        self.display_map
16838            .update(cx, |map, cx| map.snapshot(cx))
16839            .longest_row()
16840    }
16841
16842    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16843        self.display_map
16844            .update(cx, |map, cx| map.snapshot(cx))
16845            .max_point()
16846    }
16847
16848    pub fn text(&self, cx: &App) -> String {
16849        self.buffer.read(cx).read(cx).text()
16850    }
16851
16852    pub fn is_empty(&self, cx: &App) -> bool {
16853        self.buffer.read(cx).read(cx).is_empty()
16854    }
16855
16856    pub fn text_option(&self, cx: &App) -> Option<String> {
16857        let text = self.text(cx);
16858        let text = text.trim();
16859
16860        if text.is_empty() {
16861            return None;
16862        }
16863
16864        Some(text.to_string())
16865    }
16866
16867    pub fn set_text(
16868        &mut self,
16869        text: impl Into<Arc<str>>,
16870        window: &mut Window,
16871        cx: &mut Context<Self>,
16872    ) {
16873        self.transact(window, cx, |this, _, cx| {
16874            this.buffer
16875                .read(cx)
16876                .as_singleton()
16877                .expect("you can only call set_text on editors for singleton buffers")
16878                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16879        });
16880    }
16881
16882    pub fn display_text(&self, cx: &mut App) -> String {
16883        self.display_map
16884            .update(cx, |map, cx| map.snapshot(cx))
16885            .text()
16886    }
16887
16888    fn create_minimap(
16889        &self,
16890        minimap_settings: MinimapSettings,
16891        window: &mut Window,
16892        cx: &mut Context<Self>,
16893    ) -> Option<Entity<Self>> {
16894        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16895            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16896    }
16897
16898    fn initialize_new_minimap(
16899        &self,
16900        minimap_settings: MinimapSettings,
16901        window: &mut Window,
16902        cx: &mut Context<Self>,
16903    ) -> Entity<Self> {
16904        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16905
16906        let mut minimap = Editor::new_internal(
16907            EditorMode::Minimap {
16908                parent: cx.weak_entity(),
16909            },
16910            self.buffer.clone(),
16911            self.project.clone(),
16912            Some(self.display_map.clone()),
16913            window,
16914            cx,
16915        );
16916        minimap.scroll_manager.clone_state(&self.scroll_manager);
16917        minimap.set_text_style_refinement(TextStyleRefinement {
16918            font_size: Some(MINIMAP_FONT_SIZE),
16919            font_weight: Some(MINIMAP_FONT_WEIGHT),
16920            ..Default::default()
16921        });
16922        minimap.update_minimap_configuration(minimap_settings, cx);
16923        cx.new(|_| minimap)
16924    }
16925
16926    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
16927        let current_line_highlight = minimap_settings
16928            .current_line_highlight
16929            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
16930        self.set_current_line_highlight(Some(current_line_highlight));
16931    }
16932
16933    pub fn minimap(&self) -> Option<&Entity<Self>> {
16934        self.minimap
16935            .as_ref()
16936            .filter(|_| self.minimap_visibility.visible())
16937    }
16938
16939    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16940        let mut wrap_guides = smallvec![];
16941
16942        if self.show_wrap_guides == Some(false) {
16943            return wrap_guides;
16944        }
16945
16946        let settings = self.buffer.read(cx).language_settings(cx);
16947        if settings.show_wrap_guides {
16948            match self.soft_wrap_mode(cx) {
16949                SoftWrap::Column(soft_wrap) => {
16950                    wrap_guides.push((soft_wrap as usize, true));
16951                }
16952                SoftWrap::Bounded(soft_wrap) => {
16953                    wrap_guides.push((soft_wrap as usize, true));
16954                }
16955                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
16956            }
16957            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
16958        }
16959
16960        wrap_guides
16961    }
16962
16963    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16964        let settings = self.buffer.read(cx).language_settings(cx);
16965        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16966        match mode {
16967            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16968                SoftWrap::None
16969            }
16970            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16971            language_settings::SoftWrap::PreferredLineLength => {
16972                SoftWrap::Column(settings.preferred_line_length)
16973            }
16974            language_settings::SoftWrap::Bounded => {
16975                SoftWrap::Bounded(settings.preferred_line_length)
16976            }
16977        }
16978    }
16979
16980    pub fn set_soft_wrap_mode(
16981        &mut self,
16982        mode: language_settings::SoftWrap,
16983
16984        cx: &mut Context<Self>,
16985    ) {
16986        self.soft_wrap_mode_override = Some(mode);
16987        cx.notify();
16988    }
16989
16990    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16991        self.hard_wrap = hard_wrap;
16992        cx.notify();
16993    }
16994
16995    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16996        self.text_style_refinement = Some(style);
16997    }
16998
16999    /// called by the Element so we know what style we were most recently rendered with.
17000    pub(crate) fn set_style(
17001        &mut self,
17002        style: EditorStyle,
17003        window: &mut Window,
17004        cx: &mut Context<Self>,
17005    ) {
17006        // We intentionally do not inform the display map about the minimap style
17007        // so that wrapping is not recalculated and stays consistent for the editor
17008        // and its linked minimap.
17009        if !self.mode.is_minimap() {
17010            let rem_size = window.rem_size();
17011            self.display_map.update(cx, |map, cx| {
17012                map.set_font(
17013                    style.text.font(),
17014                    style.text.font_size.to_pixels(rem_size),
17015                    cx,
17016                )
17017            });
17018        }
17019        self.style = Some(style);
17020    }
17021
17022    pub fn style(&self) -> Option<&EditorStyle> {
17023        self.style.as_ref()
17024    }
17025
17026    // Called by the element. This method is not designed to be called outside of the editor
17027    // element's layout code because it does not notify when rewrapping is computed synchronously.
17028    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17029        self.display_map
17030            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17031    }
17032
17033    pub fn set_soft_wrap(&mut self) {
17034        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17035    }
17036
17037    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17038        if self.soft_wrap_mode_override.is_some() {
17039            self.soft_wrap_mode_override.take();
17040        } else {
17041            let soft_wrap = match self.soft_wrap_mode(cx) {
17042                SoftWrap::GitDiff => return,
17043                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17044                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17045                    language_settings::SoftWrap::None
17046                }
17047            };
17048            self.soft_wrap_mode_override = Some(soft_wrap);
17049        }
17050        cx.notify();
17051    }
17052
17053    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17054        let Some(workspace) = self.workspace() else {
17055            return;
17056        };
17057        let fs = workspace.read(cx).app_state().fs.clone();
17058        let current_show = TabBarSettings::get_global(cx).show;
17059        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17060            setting.show = Some(!current_show);
17061        });
17062    }
17063
17064    pub fn toggle_indent_guides(
17065        &mut self,
17066        _: &ToggleIndentGuides,
17067        _: &mut Window,
17068        cx: &mut Context<Self>,
17069    ) {
17070        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17071            self.buffer
17072                .read(cx)
17073                .language_settings(cx)
17074                .indent_guides
17075                .enabled
17076        });
17077        self.show_indent_guides = Some(!currently_enabled);
17078        cx.notify();
17079    }
17080
17081    fn should_show_indent_guides(&self) -> Option<bool> {
17082        self.show_indent_guides
17083    }
17084
17085    pub fn toggle_line_numbers(
17086        &mut self,
17087        _: &ToggleLineNumbers,
17088        _: &mut Window,
17089        cx: &mut Context<Self>,
17090    ) {
17091        let mut editor_settings = EditorSettings::get_global(cx).clone();
17092        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17093        EditorSettings::override_global(editor_settings, cx);
17094    }
17095
17096    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17097        if let Some(show_line_numbers) = self.show_line_numbers {
17098            return show_line_numbers;
17099        }
17100        EditorSettings::get_global(cx).gutter.line_numbers
17101    }
17102
17103    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17104        self.use_relative_line_numbers
17105            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17106    }
17107
17108    pub fn toggle_relative_line_numbers(
17109        &mut self,
17110        _: &ToggleRelativeLineNumbers,
17111        _: &mut Window,
17112        cx: &mut Context<Self>,
17113    ) {
17114        let is_relative = self.should_use_relative_line_numbers(cx);
17115        self.set_relative_line_number(Some(!is_relative), cx)
17116    }
17117
17118    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17119        self.use_relative_line_numbers = is_relative;
17120        cx.notify();
17121    }
17122
17123    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17124        self.show_gutter = show_gutter;
17125        cx.notify();
17126    }
17127
17128    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17129        self.show_scrollbars = ScrollbarAxes {
17130            horizontal: show,
17131            vertical: show,
17132        };
17133        cx.notify();
17134    }
17135
17136    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17137        self.show_scrollbars.vertical = show;
17138        cx.notify();
17139    }
17140
17141    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17142        self.show_scrollbars.horizontal = show;
17143        cx.notify();
17144    }
17145
17146    pub fn set_minimap_visibility(
17147        &mut self,
17148        minimap_visibility: MinimapVisibility,
17149        window: &mut Window,
17150        cx: &mut Context<Self>,
17151    ) {
17152        if self.minimap_visibility != minimap_visibility {
17153            if minimap_visibility.visible() && self.minimap.is_none() {
17154                let minimap_settings = EditorSettings::get_global(cx).minimap;
17155                self.minimap =
17156                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17157            }
17158            self.minimap_visibility = minimap_visibility;
17159            cx.notify();
17160        }
17161    }
17162
17163    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17164        self.set_show_scrollbars(false, cx);
17165        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17166    }
17167
17168    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17169        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17170    }
17171
17172    /// Normally the text in full mode and auto height editors is padded on the
17173    /// left side by roughly half a character width for improved hit testing.
17174    ///
17175    /// Use this method to disable this for cases where this is not wanted (e.g.
17176    /// if you want to align the editor text with some other text above or below)
17177    /// or if you want to add this padding to single-line editors.
17178    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17179        self.offset_content = offset_content;
17180        cx.notify();
17181    }
17182
17183    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17184        self.show_line_numbers = Some(show_line_numbers);
17185        cx.notify();
17186    }
17187
17188    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17189        self.disable_expand_excerpt_buttons = true;
17190        cx.notify();
17191    }
17192
17193    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17194        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17195        cx.notify();
17196    }
17197
17198    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17199        self.show_code_actions = Some(show_code_actions);
17200        cx.notify();
17201    }
17202
17203    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17204        self.show_runnables = Some(show_runnables);
17205        cx.notify();
17206    }
17207
17208    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17209        self.show_breakpoints = Some(show_breakpoints);
17210        cx.notify();
17211    }
17212
17213    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17214        if self.display_map.read(cx).masked != masked {
17215            self.display_map.update(cx, |map, _| map.masked = masked);
17216        }
17217        cx.notify()
17218    }
17219
17220    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17221        self.show_wrap_guides = Some(show_wrap_guides);
17222        cx.notify();
17223    }
17224
17225    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17226        self.show_indent_guides = Some(show_indent_guides);
17227        cx.notify();
17228    }
17229
17230    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17231        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17232            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17233                if let Some(dir) = file.abs_path(cx).parent() {
17234                    return Some(dir.to_owned());
17235                }
17236            }
17237
17238            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17239                return Some(project_path.path.to_path_buf());
17240            }
17241        }
17242
17243        None
17244    }
17245
17246    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17247        self.active_excerpt(cx)?
17248            .1
17249            .read(cx)
17250            .file()
17251            .and_then(|f| f.as_local())
17252    }
17253
17254    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17255        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17256            let buffer = buffer.read(cx);
17257            if let Some(project_path) = buffer.project_path(cx) {
17258                let project = self.project.as_ref()?.read(cx);
17259                project.absolute_path(&project_path, cx)
17260            } else {
17261                buffer
17262                    .file()
17263                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17264            }
17265        })
17266    }
17267
17268    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17269        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17270            let project_path = buffer.read(cx).project_path(cx)?;
17271            let project = self.project.as_ref()?.read(cx);
17272            let entry = project.entry_for_path(&project_path, cx)?;
17273            let path = entry.path.to_path_buf();
17274            Some(path)
17275        })
17276    }
17277
17278    pub fn reveal_in_finder(
17279        &mut self,
17280        _: &RevealInFileManager,
17281        _window: &mut Window,
17282        cx: &mut Context<Self>,
17283    ) {
17284        if let Some(target) = self.target_file(cx) {
17285            cx.reveal_path(&target.abs_path(cx));
17286        }
17287    }
17288
17289    pub fn copy_path(
17290        &mut self,
17291        _: &zed_actions::workspace::CopyPath,
17292        _window: &mut Window,
17293        cx: &mut Context<Self>,
17294    ) {
17295        if let Some(path) = self.target_file_abs_path(cx) {
17296            if let Some(path) = path.to_str() {
17297                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17298            }
17299        }
17300    }
17301
17302    pub fn copy_relative_path(
17303        &mut self,
17304        _: &zed_actions::workspace::CopyRelativePath,
17305        _window: &mut Window,
17306        cx: &mut Context<Self>,
17307    ) {
17308        if let Some(path) = self.target_file_path(cx) {
17309            if let Some(path) = path.to_str() {
17310                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17311            }
17312        }
17313    }
17314
17315    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17316        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17317            buffer.read(cx).project_path(cx)
17318        } else {
17319            None
17320        }
17321    }
17322
17323    // Returns true if the editor handled a go-to-line request
17324    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17325        maybe!({
17326            let breakpoint_store = self.breakpoint_store.as_ref()?;
17327
17328            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17329            else {
17330                self.clear_row_highlights::<ActiveDebugLine>();
17331                return None;
17332            };
17333
17334            let position = active_stack_frame.position;
17335            let buffer_id = position.buffer_id?;
17336            let snapshot = self
17337                .project
17338                .as_ref()?
17339                .read(cx)
17340                .buffer_for_id(buffer_id, cx)?
17341                .read(cx)
17342                .snapshot();
17343
17344            let mut handled = false;
17345            for (id, ExcerptRange { context, .. }) in
17346                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17347            {
17348                if context.start.cmp(&position, &snapshot).is_ge()
17349                    || context.end.cmp(&position, &snapshot).is_lt()
17350                {
17351                    continue;
17352                }
17353                let snapshot = self.buffer.read(cx).snapshot(cx);
17354                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17355
17356                handled = true;
17357                self.clear_row_highlights::<ActiveDebugLine>();
17358
17359                self.go_to_line::<ActiveDebugLine>(
17360                    multibuffer_anchor,
17361                    Some(cx.theme().colors().editor_debugger_active_line_background),
17362                    window,
17363                    cx,
17364                );
17365
17366                cx.notify();
17367            }
17368
17369            handled.then_some(())
17370        })
17371        .is_some()
17372    }
17373
17374    pub fn copy_file_name_without_extension(
17375        &mut self,
17376        _: &CopyFileNameWithoutExtension,
17377        _: &mut Window,
17378        cx: &mut Context<Self>,
17379    ) {
17380        if let Some(file) = self.target_file(cx) {
17381            if let Some(file_stem) = file.path().file_stem() {
17382                if let Some(name) = file_stem.to_str() {
17383                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17384                }
17385            }
17386        }
17387    }
17388
17389    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17390        if let Some(file) = self.target_file(cx) {
17391            if let Some(file_name) = file.path().file_name() {
17392                if let Some(name) = file_name.to_str() {
17393                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17394                }
17395            }
17396        }
17397    }
17398
17399    pub fn toggle_git_blame(
17400        &mut self,
17401        _: &::git::Blame,
17402        window: &mut Window,
17403        cx: &mut Context<Self>,
17404    ) {
17405        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17406
17407        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17408            self.start_git_blame(true, window, cx);
17409        }
17410
17411        cx.notify();
17412    }
17413
17414    pub fn toggle_git_blame_inline(
17415        &mut self,
17416        _: &ToggleGitBlameInline,
17417        window: &mut Window,
17418        cx: &mut Context<Self>,
17419    ) {
17420        self.toggle_git_blame_inline_internal(true, window, cx);
17421        cx.notify();
17422    }
17423
17424    pub fn open_git_blame_commit(
17425        &mut self,
17426        _: &OpenGitBlameCommit,
17427        window: &mut Window,
17428        cx: &mut Context<Self>,
17429    ) {
17430        self.open_git_blame_commit_internal(window, cx);
17431    }
17432
17433    fn open_git_blame_commit_internal(
17434        &mut self,
17435        window: &mut Window,
17436        cx: &mut Context<Self>,
17437    ) -> Option<()> {
17438        let blame = self.blame.as_ref()?;
17439        let snapshot = self.snapshot(window, cx);
17440        let cursor = self.selections.newest::<Point>(cx).head();
17441        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17442        let blame_entry = blame
17443            .update(cx, |blame, cx| {
17444                blame
17445                    .blame_for_rows(
17446                        &[RowInfo {
17447                            buffer_id: Some(buffer.remote_id()),
17448                            buffer_row: Some(point.row),
17449                            ..Default::default()
17450                        }],
17451                        cx,
17452                    )
17453                    .next()
17454            })
17455            .flatten()?;
17456        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17457        let repo = blame.read(cx).repository(cx)?;
17458        let workspace = self.workspace()?.downgrade();
17459        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17460        None
17461    }
17462
17463    pub fn git_blame_inline_enabled(&self) -> bool {
17464        self.git_blame_inline_enabled
17465    }
17466
17467    pub fn toggle_selection_menu(
17468        &mut self,
17469        _: &ToggleSelectionMenu,
17470        _: &mut Window,
17471        cx: &mut Context<Self>,
17472    ) {
17473        self.show_selection_menu = self
17474            .show_selection_menu
17475            .map(|show_selections_menu| !show_selections_menu)
17476            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17477
17478        cx.notify();
17479    }
17480
17481    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17482        self.show_selection_menu
17483            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17484    }
17485
17486    fn start_git_blame(
17487        &mut self,
17488        user_triggered: bool,
17489        window: &mut Window,
17490        cx: &mut Context<Self>,
17491    ) {
17492        if let Some(project) = self.project.as_ref() {
17493            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17494                return;
17495            };
17496
17497            if buffer.read(cx).file().is_none() {
17498                return;
17499            }
17500
17501            let focused = self.focus_handle(cx).contains_focused(window, cx);
17502
17503            let project = project.clone();
17504            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17505            self.blame_subscription =
17506                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17507            self.blame = Some(blame);
17508        }
17509    }
17510
17511    fn toggle_git_blame_inline_internal(
17512        &mut self,
17513        user_triggered: bool,
17514        window: &mut Window,
17515        cx: &mut Context<Self>,
17516    ) {
17517        if self.git_blame_inline_enabled {
17518            self.git_blame_inline_enabled = false;
17519            self.show_git_blame_inline = false;
17520            self.show_git_blame_inline_delay_task.take();
17521        } else {
17522            self.git_blame_inline_enabled = true;
17523            self.start_git_blame_inline(user_triggered, window, cx);
17524        }
17525
17526        cx.notify();
17527    }
17528
17529    fn start_git_blame_inline(
17530        &mut self,
17531        user_triggered: bool,
17532        window: &mut Window,
17533        cx: &mut Context<Self>,
17534    ) {
17535        self.start_git_blame(user_triggered, window, cx);
17536
17537        if ProjectSettings::get_global(cx)
17538            .git
17539            .inline_blame_delay()
17540            .is_some()
17541        {
17542            self.start_inline_blame_timer(window, cx);
17543        } else {
17544            self.show_git_blame_inline = true
17545        }
17546    }
17547
17548    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17549        self.blame.as_ref()
17550    }
17551
17552    pub fn show_git_blame_gutter(&self) -> bool {
17553        self.show_git_blame_gutter
17554    }
17555
17556    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17557        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17558    }
17559
17560    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17561        self.show_git_blame_inline
17562            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17563            && !self.newest_selection_head_on_empty_line(cx)
17564            && self.has_blame_entries(cx)
17565    }
17566
17567    fn has_blame_entries(&self, cx: &App) -> bool {
17568        self.blame()
17569            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17570    }
17571
17572    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17573        let cursor_anchor = self.selections.newest_anchor().head();
17574
17575        let snapshot = self.buffer.read(cx).snapshot(cx);
17576        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17577
17578        snapshot.line_len(buffer_row) == 0
17579    }
17580
17581    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17582        let buffer_and_selection = maybe!({
17583            let selection = self.selections.newest::<Point>(cx);
17584            let selection_range = selection.range();
17585
17586            let multi_buffer = self.buffer().read(cx);
17587            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17588            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17589
17590            let (buffer, range, _) = if selection.reversed {
17591                buffer_ranges.first()
17592            } else {
17593                buffer_ranges.last()
17594            }?;
17595
17596            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17597                ..text::ToPoint::to_point(&range.end, &buffer).row;
17598            Some((
17599                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17600                selection,
17601            ))
17602        });
17603
17604        let Some((buffer, selection)) = buffer_and_selection else {
17605            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17606        };
17607
17608        let Some(project) = self.project.as_ref() else {
17609            return Task::ready(Err(anyhow!("editor does not have project")));
17610        };
17611
17612        project.update(cx, |project, cx| {
17613            project.get_permalink_to_line(&buffer, selection, cx)
17614        })
17615    }
17616
17617    pub fn copy_permalink_to_line(
17618        &mut self,
17619        _: &CopyPermalinkToLine,
17620        window: &mut Window,
17621        cx: &mut Context<Self>,
17622    ) {
17623        let permalink_task = self.get_permalink_to_line(cx);
17624        let workspace = self.workspace();
17625
17626        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17627            Ok(permalink) => {
17628                cx.update(|_, cx| {
17629                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17630                })
17631                .ok();
17632            }
17633            Err(err) => {
17634                let message = format!("Failed to copy permalink: {err}");
17635
17636                anyhow::Result::<()>::Err(err).log_err();
17637
17638                if let Some(workspace) = workspace {
17639                    workspace
17640                        .update_in(cx, |workspace, _, cx| {
17641                            struct CopyPermalinkToLine;
17642
17643                            workspace.show_toast(
17644                                Toast::new(
17645                                    NotificationId::unique::<CopyPermalinkToLine>(),
17646                                    message,
17647                                ),
17648                                cx,
17649                            )
17650                        })
17651                        .ok();
17652                }
17653            }
17654        })
17655        .detach();
17656    }
17657
17658    pub fn copy_file_location(
17659        &mut self,
17660        _: &CopyFileLocation,
17661        _: &mut Window,
17662        cx: &mut Context<Self>,
17663    ) {
17664        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17665        if let Some(file) = self.target_file(cx) {
17666            if let Some(path) = file.path().to_str() {
17667                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17668            }
17669        }
17670    }
17671
17672    pub fn open_permalink_to_line(
17673        &mut self,
17674        _: &OpenPermalinkToLine,
17675        window: &mut Window,
17676        cx: &mut Context<Self>,
17677    ) {
17678        let permalink_task = self.get_permalink_to_line(cx);
17679        let workspace = self.workspace();
17680
17681        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17682            Ok(permalink) => {
17683                cx.update(|_, cx| {
17684                    cx.open_url(permalink.as_ref());
17685                })
17686                .ok();
17687            }
17688            Err(err) => {
17689                let message = format!("Failed to open permalink: {err}");
17690
17691                anyhow::Result::<()>::Err(err).log_err();
17692
17693                if let Some(workspace) = workspace {
17694                    workspace
17695                        .update(cx, |workspace, cx| {
17696                            struct OpenPermalinkToLine;
17697
17698                            workspace.show_toast(
17699                                Toast::new(
17700                                    NotificationId::unique::<OpenPermalinkToLine>(),
17701                                    message,
17702                                ),
17703                                cx,
17704                            )
17705                        })
17706                        .ok();
17707                }
17708            }
17709        })
17710        .detach();
17711    }
17712
17713    pub fn insert_uuid_v4(
17714        &mut self,
17715        _: &InsertUuidV4,
17716        window: &mut Window,
17717        cx: &mut Context<Self>,
17718    ) {
17719        self.insert_uuid(UuidVersion::V4, window, cx);
17720    }
17721
17722    pub fn insert_uuid_v7(
17723        &mut self,
17724        _: &InsertUuidV7,
17725        window: &mut Window,
17726        cx: &mut Context<Self>,
17727    ) {
17728        self.insert_uuid(UuidVersion::V7, window, cx);
17729    }
17730
17731    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17732        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17733        self.transact(window, cx, |this, window, cx| {
17734            let edits = this
17735                .selections
17736                .all::<Point>(cx)
17737                .into_iter()
17738                .map(|selection| {
17739                    let uuid = match version {
17740                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17741                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17742                    };
17743
17744                    (selection.range(), uuid.to_string())
17745                });
17746            this.edit(edits, cx);
17747            this.refresh_inline_completion(true, false, window, cx);
17748        });
17749    }
17750
17751    pub fn open_selections_in_multibuffer(
17752        &mut self,
17753        _: &OpenSelectionsInMultibuffer,
17754        window: &mut Window,
17755        cx: &mut Context<Self>,
17756    ) {
17757        let multibuffer = self.buffer.read(cx);
17758
17759        let Some(buffer) = multibuffer.as_singleton() else {
17760            return;
17761        };
17762
17763        let Some(workspace) = self.workspace() else {
17764            return;
17765        };
17766
17767        let locations = self
17768            .selections
17769            .disjoint_anchors()
17770            .iter()
17771            .map(|selection| {
17772                let range = if selection.reversed {
17773                    selection.end.text_anchor..selection.start.text_anchor
17774                } else {
17775                    selection.start.text_anchor..selection.end.text_anchor
17776                };
17777                Location {
17778                    buffer: buffer.clone(),
17779                    range,
17780                }
17781            })
17782            .collect::<Vec<_>>();
17783
17784        let title = multibuffer.title(cx).to_string();
17785
17786        cx.spawn_in(window, async move |_, cx| {
17787            workspace.update_in(cx, |workspace, window, cx| {
17788                Self::open_locations_in_multibuffer(
17789                    workspace,
17790                    locations,
17791                    format!("Selections for '{title}'"),
17792                    false,
17793                    MultibufferSelectionMode::All,
17794                    window,
17795                    cx,
17796                );
17797            })
17798        })
17799        .detach();
17800    }
17801
17802    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17803    /// last highlight added will be used.
17804    ///
17805    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17806    pub fn highlight_rows<T: 'static>(
17807        &mut self,
17808        range: Range<Anchor>,
17809        color: Hsla,
17810        options: RowHighlightOptions,
17811        cx: &mut Context<Self>,
17812    ) {
17813        let snapshot = self.buffer().read(cx).snapshot(cx);
17814        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17815        let ix = row_highlights.binary_search_by(|highlight| {
17816            Ordering::Equal
17817                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17818                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17819        });
17820
17821        if let Err(mut ix) = ix {
17822            let index = post_inc(&mut self.highlight_order);
17823
17824            // If this range intersects with the preceding highlight, then merge it with
17825            // the preceding highlight. Otherwise insert a new highlight.
17826            let mut merged = false;
17827            if ix > 0 {
17828                let prev_highlight = &mut row_highlights[ix - 1];
17829                if prev_highlight
17830                    .range
17831                    .end
17832                    .cmp(&range.start, &snapshot)
17833                    .is_ge()
17834                {
17835                    ix -= 1;
17836                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17837                        prev_highlight.range.end = range.end;
17838                    }
17839                    merged = true;
17840                    prev_highlight.index = index;
17841                    prev_highlight.color = color;
17842                    prev_highlight.options = options;
17843                }
17844            }
17845
17846            if !merged {
17847                row_highlights.insert(
17848                    ix,
17849                    RowHighlight {
17850                        range: range.clone(),
17851                        index,
17852                        color,
17853                        options,
17854                        type_id: TypeId::of::<T>(),
17855                    },
17856                );
17857            }
17858
17859            // If any of the following highlights intersect with this one, merge them.
17860            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17861                let highlight = &row_highlights[ix];
17862                if next_highlight
17863                    .range
17864                    .start
17865                    .cmp(&highlight.range.end, &snapshot)
17866                    .is_le()
17867                {
17868                    if next_highlight
17869                        .range
17870                        .end
17871                        .cmp(&highlight.range.end, &snapshot)
17872                        .is_gt()
17873                    {
17874                        row_highlights[ix].range.end = next_highlight.range.end;
17875                    }
17876                    row_highlights.remove(ix + 1);
17877                } else {
17878                    break;
17879                }
17880            }
17881        }
17882    }
17883
17884    /// Remove any highlighted row ranges of the given type that intersect the
17885    /// given ranges.
17886    pub fn remove_highlighted_rows<T: 'static>(
17887        &mut self,
17888        ranges_to_remove: Vec<Range<Anchor>>,
17889        cx: &mut Context<Self>,
17890    ) {
17891        let snapshot = self.buffer().read(cx).snapshot(cx);
17892        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17893        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17894        row_highlights.retain(|highlight| {
17895            while let Some(range_to_remove) = ranges_to_remove.peek() {
17896                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17897                    Ordering::Less | Ordering::Equal => {
17898                        ranges_to_remove.next();
17899                    }
17900                    Ordering::Greater => {
17901                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17902                            Ordering::Less | Ordering::Equal => {
17903                                return false;
17904                            }
17905                            Ordering::Greater => break,
17906                        }
17907                    }
17908                }
17909            }
17910
17911            true
17912        })
17913    }
17914
17915    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17916    pub fn clear_row_highlights<T: 'static>(&mut self) {
17917        self.highlighted_rows.remove(&TypeId::of::<T>());
17918    }
17919
17920    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17921    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17922        self.highlighted_rows
17923            .get(&TypeId::of::<T>())
17924            .map_or(&[] as &[_], |vec| vec.as_slice())
17925            .iter()
17926            .map(|highlight| (highlight.range.clone(), highlight.color))
17927    }
17928
17929    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17930    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17931    /// Allows to ignore certain kinds of highlights.
17932    pub fn highlighted_display_rows(
17933        &self,
17934        window: &mut Window,
17935        cx: &mut App,
17936    ) -> BTreeMap<DisplayRow, LineHighlight> {
17937        let snapshot = self.snapshot(window, cx);
17938        let mut used_highlight_orders = HashMap::default();
17939        self.highlighted_rows
17940            .iter()
17941            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17942            .fold(
17943                BTreeMap::<DisplayRow, LineHighlight>::new(),
17944                |mut unique_rows, highlight| {
17945                    let start = highlight.range.start.to_display_point(&snapshot);
17946                    let end = highlight.range.end.to_display_point(&snapshot);
17947                    let start_row = start.row().0;
17948                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
17949                        && end.column() == 0
17950                    {
17951                        end.row().0.saturating_sub(1)
17952                    } else {
17953                        end.row().0
17954                    };
17955                    for row in start_row..=end_row {
17956                        let used_index =
17957                            used_highlight_orders.entry(row).or_insert(highlight.index);
17958                        if highlight.index >= *used_index {
17959                            *used_index = highlight.index;
17960                            unique_rows.insert(
17961                                DisplayRow(row),
17962                                LineHighlight {
17963                                    include_gutter: highlight.options.include_gutter,
17964                                    border: None,
17965                                    background: highlight.color.into(),
17966                                    type_id: Some(highlight.type_id),
17967                                },
17968                            );
17969                        }
17970                    }
17971                    unique_rows
17972                },
17973            )
17974    }
17975
17976    pub fn highlighted_display_row_for_autoscroll(
17977        &self,
17978        snapshot: &DisplaySnapshot,
17979    ) -> Option<DisplayRow> {
17980        self.highlighted_rows
17981            .values()
17982            .flat_map(|highlighted_rows| highlighted_rows.iter())
17983            .filter_map(|highlight| {
17984                if highlight.options.autoscroll {
17985                    Some(highlight.range.start.to_display_point(snapshot).row())
17986                } else {
17987                    None
17988                }
17989            })
17990            .min()
17991    }
17992
17993    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
17994        self.highlight_background::<SearchWithinRange>(
17995            ranges,
17996            |colors| colors.editor_document_highlight_read_background,
17997            cx,
17998        )
17999    }
18000
18001    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18002        self.breadcrumb_header = Some(new_header);
18003    }
18004
18005    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18006        self.clear_background_highlights::<SearchWithinRange>(cx);
18007    }
18008
18009    pub fn highlight_background<T: 'static>(
18010        &mut self,
18011        ranges: &[Range<Anchor>],
18012        color_fetcher: fn(&ThemeColors) -> Hsla,
18013        cx: &mut Context<Self>,
18014    ) {
18015        self.background_highlights
18016            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18017        self.scrollbar_marker_state.dirty = true;
18018        cx.notify();
18019    }
18020
18021    pub fn clear_background_highlights<T: 'static>(
18022        &mut self,
18023        cx: &mut Context<Self>,
18024    ) -> Option<BackgroundHighlight> {
18025        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18026        if !text_highlights.1.is_empty() {
18027            self.scrollbar_marker_state.dirty = true;
18028            cx.notify();
18029        }
18030        Some(text_highlights)
18031    }
18032
18033    pub fn highlight_gutter<T: 'static>(
18034        &mut self,
18035        ranges: &[Range<Anchor>],
18036        color_fetcher: fn(&App) -> Hsla,
18037        cx: &mut Context<Self>,
18038    ) {
18039        self.gutter_highlights
18040            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18041        cx.notify();
18042    }
18043
18044    pub fn clear_gutter_highlights<T: 'static>(
18045        &mut self,
18046        cx: &mut Context<Self>,
18047    ) -> Option<GutterHighlight> {
18048        cx.notify();
18049        self.gutter_highlights.remove(&TypeId::of::<T>())
18050    }
18051
18052    #[cfg(feature = "test-support")]
18053    pub fn all_text_background_highlights(
18054        &self,
18055        window: &mut Window,
18056        cx: &mut Context<Self>,
18057    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18058        let snapshot = self.snapshot(window, cx);
18059        let buffer = &snapshot.buffer_snapshot;
18060        let start = buffer.anchor_before(0);
18061        let end = buffer.anchor_after(buffer.len());
18062        let theme = cx.theme().colors();
18063        self.background_highlights_in_range(start..end, &snapshot, theme)
18064    }
18065
18066    #[cfg(feature = "test-support")]
18067    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18068        let snapshot = self.buffer().read(cx).snapshot(cx);
18069
18070        let highlights = self
18071            .background_highlights
18072            .get(&TypeId::of::<items::BufferSearchHighlights>());
18073
18074        if let Some((_color, ranges)) = highlights {
18075            ranges
18076                .iter()
18077                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18078                .collect_vec()
18079        } else {
18080            vec![]
18081        }
18082    }
18083
18084    fn document_highlights_for_position<'a>(
18085        &'a self,
18086        position: Anchor,
18087        buffer: &'a MultiBufferSnapshot,
18088    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18089        let read_highlights = self
18090            .background_highlights
18091            .get(&TypeId::of::<DocumentHighlightRead>())
18092            .map(|h| &h.1);
18093        let write_highlights = self
18094            .background_highlights
18095            .get(&TypeId::of::<DocumentHighlightWrite>())
18096            .map(|h| &h.1);
18097        let left_position = position.bias_left(buffer);
18098        let right_position = position.bias_right(buffer);
18099        read_highlights
18100            .into_iter()
18101            .chain(write_highlights)
18102            .flat_map(move |ranges| {
18103                let start_ix = match ranges.binary_search_by(|probe| {
18104                    let cmp = probe.end.cmp(&left_position, buffer);
18105                    if cmp.is_ge() {
18106                        Ordering::Greater
18107                    } else {
18108                        Ordering::Less
18109                    }
18110                }) {
18111                    Ok(i) | Err(i) => i,
18112                };
18113
18114                ranges[start_ix..]
18115                    .iter()
18116                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18117            })
18118    }
18119
18120    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18121        self.background_highlights
18122            .get(&TypeId::of::<T>())
18123            .map_or(false, |(_, highlights)| !highlights.is_empty())
18124    }
18125
18126    pub fn background_highlights_in_range(
18127        &self,
18128        search_range: Range<Anchor>,
18129        display_snapshot: &DisplaySnapshot,
18130        theme: &ThemeColors,
18131    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18132        let mut results = Vec::new();
18133        for (color_fetcher, ranges) in self.background_highlights.values() {
18134            let color = color_fetcher(theme);
18135            let start_ix = match ranges.binary_search_by(|probe| {
18136                let cmp = probe
18137                    .end
18138                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18139                if cmp.is_gt() {
18140                    Ordering::Greater
18141                } else {
18142                    Ordering::Less
18143                }
18144            }) {
18145                Ok(i) | Err(i) => i,
18146            };
18147            for range in &ranges[start_ix..] {
18148                if range
18149                    .start
18150                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18151                    .is_ge()
18152                {
18153                    break;
18154                }
18155
18156                let start = range.start.to_display_point(display_snapshot);
18157                let end = range.end.to_display_point(display_snapshot);
18158                results.push((start..end, color))
18159            }
18160        }
18161        results
18162    }
18163
18164    pub fn background_highlight_row_ranges<T: 'static>(
18165        &self,
18166        search_range: Range<Anchor>,
18167        display_snapshot: &DisplaySnapshot,
18168        count: usize,
18169    ) -> Vec<RangeInclusive<DisplayPoint>> {
18170        let mut results = Vec::new();
18171        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18172            return vec![];
18173        };
18174
18175        let start_ix = match ranges.binary_search_by(|probe| {
18176            let cmp = probe
18177                .end
18178                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18179            if cmp.is_gt() {
18180                Ordering::Greater
18181            } else {
18182                Ordering::Less
18183            }
18184        }) {
18185            Ok(i) | Err(i) => i,
18186        };
18187        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18188            if let (Some(start_display), Some(end_display)) = (start, end) {
18189                results.push(
18190                    start_display.to_display_point(display_snapshot)
18191                        ..=end_display.to_display_point(display_snapshot),
18192                );
18193            }
18194        };
18195        let mut start_row: Option<Point> = None;
18196        let mut end_row: Option<Point> = None;
18197        if ranges.len() > count {
18198            return Vec::new();
18199        }
18200        for range in &ranges[start_ix..] {
18201            if range
18202                .start
18203                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18204                .is_ge()
18205            {
18206                break;
18207            }
18208            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18209            if let Some(current_row) = &end_row {
18210                if end.row == current_row.row {
18211                    continue;
18212                }
18213            }
18214            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18215            if start_row.is_none() {
18216                assert_eq!(end_row, None);
18217                start_row = Some(start);
18218                end_row = Some(end);
18219                continue;
18220            }
18221            if let Some(current_end) = end_row.as_mut() {
18222                if start.row > current_end.row + 1 {
18223                    push_region(start_row, end_row);
18224                    start_row = Some(start);
18225                    end_row = Some(end);
18226                } else {
18227                    // Merge two hunks.
18228                    *current_end = end;
18229                }
18230            } else {
18231                unreachable!();
18232            }
18233        }
18234        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18235        push_region(start_row, end_row);
18236        results
18237    }
18238
18239    pub fn gutter_highlights_in_range(
18240        &self,
18241        search_range: Range<Anchor>,
18242        display_snapshot: &DisplaySnapshot,
18243        cx: &App,
18244    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18245        let mut results = Vec::new();
18246        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18247            let color = color_fetcher(cx);
18248            let start_ix = match ranges.binary_search_by(|probe| {
18249                let cmp = probe
18250                    .end
18251                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18252                if cmp.is_gt() {
18253                    Ordering::Greater
18254                } else {
18255                    Ordering::Less
18256                }
18257            }) {
18258                Ok(i) | Err(i) => i,
18259            };
18260            for range in &ranges[start_ix..] {
18261                if range
18262                    .start
18263                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18264                    .is_ge()
18265                {
18266                    break;
18267                }
18268
18269                let start = range.start.to_display_point(display_snapshot);
18270                let end = range.end.to_display_point(display_snapshot);
18271                results.push((start..end, color))
18272            }
18273        }
18274        results
18275    }
18276
18277    /// Get the text ranges corresponding to the redaction query
18278    pub fn redacted_ranges(
18279        &self,
18280        search_range: Range<Anchor>,
18281        display_snapshot: &DisplaySnapshot,
18282        cx: &App,
18283    ) -> Vec<Range<DisplayPoint>> {
18284        display_snapshot
18285            .buffer_snapshot
18286            .redacted_ranges(search_range, |file| {
18287                if let Some(file) = file {
18288                    file.is_private()
18289                        && EditorSettings::get(
18290                            Some(SettingsLocation {
18291                                worktree_id: file.worktree_id(cx),
18292                                path: file.path().as_ref(),
18293                            }),
18294                            cx,
18295                        )
18296                        .redact_private_values
18297                } else {
18298                    false
18299                }
18300            })
18301            .map(|range| {
18302                range.start.to_display_point(display_snapshot)
18303                    ..range.end.to_display_point(display_snapshot)
18304            })
18305            .collect()
18306    }
18307
18308    pub fn highlight_text<T: 'static>(
18309        &mut self,
18310        ranges: Vec<Range<Anchor>>,
18311        style: HighlightStyle,
18312        cx: &mut Context<Self>,
18313    ) {
18314        self.display_map.update(cx, |map, _| {
18315            map.highlight_text(TypeId::of::<T>(), ranges, style)
18316        });
18317        cx.notify();
18318    }
18319
18320    pub(crate) fn highlight_inlays<T: 'static>(
18321        &mut self,
18322        highlights: Vec<InlayHighlight>,
18323        style: HighlightStyle,
18324        cx: &mut Context<Self>,
18325    ) {
18326        self.display_map.update(cx, |map, _| {
18327            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18328        });
18329        cx.notify();
18330    }
18331
18332    pub fn text_highlights<'a, T: 'static>(
18333        &'a self,
18334        cx: &'a App,
18335    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18336        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18337    }
18338
18339    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18340        let cleared = self
18341            .display_map
18342            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18343        if cleared {
18344            cx.notify();
18345        }
18346    }
18347
18348    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18349        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18350            && self.focus_handle.is_focused(window)
18351    }
18352
18353    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18354        self.show_cursor_when_unfocused = is_enabled;
18355        cx.notify();
18356    }
18357
18358    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18359        cx.notify();
18360    }
18361
18362    fn on_debug_session_event(
18363        &mut self,
18364        _session: Entity<Session>,
18365        event: &SessionEvent,
18366        cx: &mut Context<Self>,
18367    ) {
18368        match event {
18369            SessionEvent::InvalidateInlineValue => {
18370                self.refresh_inline_values(cx);
18371            }
18372            _ => {}
18373        }
18374    }
18375
18376    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18377        let Some(project) = self.project.clone() else {
18378            return;
18379        };
18380
18381        if !self.inline_value_cache.enabled {
18382            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18383            self.splice_inlays(&inlays, Vec::new(), cx);
18384            return;
18385        }
18386
18387        let current_execution_position = self
18388            .highlighted_rows
18389            .get(&TypeId::of::<ActiveDebugLine>())
18390            .and_then(|lines| lines.last().map(|line| line.range.start));
18391
18392        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18393            let inline_values = editor
18394                .update(cx, |editor, cx| {
18395                    let Some(current_execution_position) = current_execution_position else {
18396                        return Some(Task::ready(Ok(Vec::new())));
18397                    };
18398
18399                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18400                        let snapshot = buffer.snapshot(cx);
18401
18402                        let excerpt = snapshot.excerpt_containing(
18403                            current_execution_position..current_execution_position,
18404                        )?;
18405
18406                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18407                    })?;
18408
18409                    let range =
18410                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18411
18412                    project.inline_values(buffer, range, cx)
18413                })
18414                .ok()
18415                .flatten()?
18416                .await
18417                .context("refreshing debugger inlays")
18418                .log_err()?;
18419
18420            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18421
18422            for (buffer_id, inline_value) in inline_values
18423                .into_iter()
18424                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18425            {
18426                buffer_inline_values
18427                    .entry(buffer_id)
18428                    .or_default()
18429                    .push(inline_value);
18430            }
18431
18432            editor
18433                .update(cx, |editor, cx| {
18434                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18435                    let mut new_inlays = Vec::default();
18436
18437                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18438                        let buffer_id = buffer_snapshot.remote_id();
18439                        buffer_inline_values
18440                            .get(&buffer_id)
18441                            .into_iter()
18442                            .flatten()
18443                            .for_each(|hint| {
18444                                let inlay = Inlay::debugger_hint(
18445                                    post_inc(&mut editor.next_inlay_id),
18446                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18447                                    hint.text(),
18448                                );
18449
18450                                new_inlays.push(inlay);
18451                            });
18452                    }
18453
18454                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18455                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18456
18457                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18458                })
18459                .ok()?;
18460            Some(())
18461        });
18462    }
18463
18464    fn on_buffer_event(
18465        &mut self,
18466        multibuffer: &Entity<MultiBuffer>,
18467        event: &multi_buffer::Event,
18468        window: &mut Window,
18469        cx: &mut Context<Self>,
18470    ) {
18471        match event {
18472            multi_buffer::Event::Edited {
18473                singleton_buffer_edited,
18474                edited_buffer: buffer_edited,
18475            } => {
18476                self.scrollbar_marker_state.dirty = true;
18477                self.active_indent_guides_state.dirty = true;
18478                self.refresh_active_diagnostics(cx);
18479                self.refresh_code_actions(window, cx);
18480                self.refresh_selected_text_highlights(true, window, cx);
18481                refresh_matching_bracket_highlights(self, window, cx);
18482                if self.has_active_inline_completion() {
18483                    self.update_visible_inline_completion(window, cx);
18484                }
18485                if let Some(buffer) = buffer_edited {
18486                    let buffer_id = buffer.read(cx).remote_id();
18487                    if !self.registered_buffers.contains_key(&buffer_id) {
18488                        if let Some(project) = self.project.as_ref() {
18489                            project.update(cx, |project, cx| {
18490                                self.registered_buffers.insert(
18491                                    buffer_id,
18492                                    project.register_buffer_with_language_servers(&buffer, cx),
18493                                );
18494                            })
18495                        }
18496                    }
18497                }
18498                cx.emit(EditorEvent::BufferEdited);
18499                cx.emit(SearchEvent::MatchesInvalidated);
18500                if *singleton_buffer_edited {
18501                    if let Some(project) = &self.project {
18502                        #[allow(clippy::mutable_key_type)]
18503                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18504                            multibuffer
18505                                .all_buffers()
18506                                .into_iter()
18507                                .filter_map(|buffer| {
18508                                    buffer.update(cx, |buffer, cx| {
18509                                        let language = buffer.language()?;
18510                                        let should_discard = project.update(cx, |project, cx| {
18511                                            project.is_local()
18512                                                && !project.has_language_servers_for(buffer, cx)
18513                                        });
18514                                        should_discard.not().then_some(language.clone())
18515                                    })
18516                                })
18517                                .collect::<HashSet<_>>()
18518                        });
18519                        if !languages_affected.is_empty() {
18520                            self.refresh_inlay_hints(
18521                                InlayHintRefreshReason::BufferEdited(languages_affected),
18522                                cx,
18523                            );
18524                        }
18525                    }
18526                }
18527
18528                let Some(project) = &self.project else { return };
18529                let (telemetry, is_via_ssh) = {
18530                    let project = project.read(cx);
18531                    let telemetry = project.client().telemetry().clone();
18532                    let is_via_ssh = project.is_via_ssh();
18533                    (telemetry, is_via_ssh)
18534                };
18535                refresh_linked_ranges(self, window, cx);
18536                telemetry.log_edit_event("editor", is_via_ssh);
18537            }
18538            multi_buffer::Event::ExcerptsAdded {
18539                buffer,
18540                predecessor,
18541                excerpts,
18542            } => {
18543                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18544                let buffer_id = buffer.read(cx).remote_id();
18545                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18546                    if let Some(project) = &self.project {
18547                        update_uncommitted_diff_for_buffer(
18548                            cx.entity(),
18549                            project,
18550                            [buffer.clone()],
18551                            self.buffer.clone(),
18552                            cx,
18553                        )
18554                        .detach();
18555                    }
18556                }
18557                cx.emit(EditorEvent::ExcerptsAdded {
18558                    buffer: buffer.clone(),
18559                    predecessor: *predecessor,
18560                    excerpts: excerpts.clone(),
18561                });
18562                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18563            }
18564            multi_buffer::Event::ExcerptsRemoved {
18565                ids,
18566                removed_buffer_ids,
18567            } => {
18568                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18569                let buffer = self.buffer.read(cx);
18570                self.registered_buffers
18571                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18572                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18573                cx.emit(EditorEvent::ExcerptsRemoved {
18574                    ids: ids.clone(),
18575                    removed_buffer_ids: removed_buffer_ids.clone(),
18576                })
18577            }
18578            multi_buffer::Event::ExcerptsEdited {
18579                excerpt_ids,
18580                buffer_ids,
18581            } => {
18582                self.display_map.update(cx, |map, cx| {
18583                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18584                });
18585                cx.emit(EditorEvent::ExcerptsEdited {
18586                    ids: excerpt_ids.clone(),
18587                })
18588            }
18589            multi_buffer::Event::ExcerptsExpanded { ids } => {
18590                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18591                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18592            }
18593            multi_buffer::Event::Reparsed(buffer_id) => {
18594                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18595                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18596
18597                cx.emit(EditorEvent::Reparsed(*buffer_id));
18598            }
18599            multi_buffer::Event::DiffHunksToggled => {
18600                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18601            }
18602            multi_buffer::Event::LanguageChanged(buffer_id) => {
18603                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18604                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18605                cx.emit(EditorEvent::Reparsed(*buffer_id));
18606                cx.notify();
18607            }
18608            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18609            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18610            multi_buffer::Event::FileHandleChanged
18611            | multi_buffer::Event::Reloaded
18612            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18613            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18614            multi_buffer::Event::DiagnosticsUpdated => {
18615                self.refresh_active_diagnostics(cx);
18616                self.refresh_inline_diagnostics(true, window, cx);
18617                self.scrollbar_marker_state.dirty = true;
18618                cx.notify();
18619            }
18620            _ => {}
18621        };
18622    }
18623
18624    pub fn start_temporary_diff_override(&mut self) {
18625        self.load_diff_task.take();
18626        self.temporary_diff_override = true;
18627    }
18628
18629    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18630        self.temporary_diff_override = false;
18631        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18632        self.buffer.update(cx, |buffer, cx| {
18633            buffer.set_all_diff_hunks_collapsed(cx);
18634        });
18635
18636        if let Some(project) = self.project.clone() {
18637            self.load_diff_task = Some(
18638                update_uncommitted_diff_for_buffer(
18639                    cx.entity(),
18640                    &project,
18641                    self.buffer.read(cx).all_buffers(),
18642                    self.buffer.clone(),
18643                    cx,
18644                )
18645                .shared(),
18646            );
18647        }
18648    }
18649
18650    fn on_display_map_changed(
18651        &mut self,
18652        _: Entity<DisplayMap>,
18653        _: &mut Window,
18654        cx: &mut Context<Self>,
18655    ) {
18656        cx.notify();
18657    }
18658
18659    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18660        let new_severity = if self.diagnostics_enabled() {
18661            EditorSettings::get_global(cx)
18662                .diagnostics_max_severity
18663                .unwrap_or(DiagnosticSeverity::Hint)
18664        } else {
18665            DiagnosticSeverity::Off
18666        };
18667        self.set_max_diagnostics_severity(new_severity, cx);
18668        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18669        self.update_edit_prediction_settings(cx);
18670        self.refresh_inline_completion(true, false, window, cx);
18671        self.refresh_inlay_hints(
18672            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18673                self.selections.newest_anchor().head(),
18674                &self.buffer.read(cx).snapshot(cx),
18675                cx,
18676            )),
18677            cx,
18678        );
18679
18680        let old_cursor_shape = self.cursor_shape;
18681
18682        {
18683            let editor_settings = EditorSettings::get_global(cx);
18684            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18685            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18686            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18687            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18688        }
18689
18690        if old_cursor_shape != self.cursor_shape {
18691            cx.emit(EditorEvent::CursorShapeChanged);
18692        }
18693
18694        let project_settings = ProjectSettings::get_global(cx);
18695        self.serialize_dirty_buffers =
18696            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18697
18698        if self.mode.is_full() {
18699            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18700            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18701            if self.show_inline_diagnostics != show_inline_diagnostics {
18702                self.show_inline_diagnostics = show_inline_diagnostics;
18703                self.refresh_inline_diagnostics(false, window, cx);
18704            }
18705
18706            if self.git_blame_inline_enabled != inline_blame_enabled {
18707                self.toggle_git_blame_inline_internal(false, window, cx);
18708            }
18709
18710            let minimap_settings = EditorSettings::get_global(cx).minimap;
18711            if self.minimap_visibility != MinimapVisibility::Disabled {
18712                if self.minimap_visibility.settings_visibility()
18713                    != minimap_settings.minimap_enabled()
18714                {
18715                    self.set_minimap_visibility(
18716                        MinimapVisibility::for_mode(self.mode(), cx),
18717                        window,
18718                        cx,
18719                    );
18720                } else if let Some(minimap_entity) = self.minimap.as_ref() {
18721                    minimap_entity.update(cx, |minimap_editor, cx| {
18722                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
18723                    })
18724                }
18725            }
18726        }
18727
18728        cx.notify();
18729    }
18730
18731    pub fn set_searchable(&mut self, searchable: bool) {
18732        self.searchable = searchable;
18733    }
18734
18735    pub fn searchable(&self) -> bool {
18736        self.searchable
18737    }
18738
18739    fn open_proposed_changes_editor(
18740        &mut self,
18741        _: &OpenProposedChangesEditor,
18742        window: &mut Window,
18743        cx: &mut Context<Self>,
18744    ) {
18745        let Some(workspace) = self.workspace() else {
18746            cx.propagate();
18747            return;
18748        };
18749
18750        let selections = self.selections.all::<usize>(cx);
18751        let multi_buffer = self.buffer.read(cx);
18752        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18753        let mut new_selections_by_buffer = HashMap::default();
18754        for selection in selections {
18755            for (buffer, range, _) in
18756                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18757            {
18758                let mut range = range.to_point(buffer);
18759                range.start.column = 0;
18760                range.end.column = buffer.line_len(range.end.row);
18761                new_selections_by_buffer
18762                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18763                    .or_insert(Vec::new())
18764                    .push(range)
18765            }
18766        }
18767
18768        let proposed_changes_buffers = new_selections_by_buffer
18769            .into_iter()
18770            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18771            .collect::<Vec<_>>();
18772        let proposed_changes_editor = cx.new(|cx| {
18773            ProposedChangesEditor::new(
18774                "Proposed changes",
18775                proposed_changes_buffers,
18776                self.project.clone(),
18777                window,
18778                cx,
18779            )
18780        });
18781
18782        window.defer(cx, move |window, cx| {
18783            workspace.update(cx, |workspace, cx| {
18784                workspace.active_pane().update(cx, |pane, cx| {
18785                    pane.add_item(
18786                        Box::new(proposed_changes_editor),
18787                        true,
18788                        true,
18789                        None,
18790                        window,
18791                        cx,
18792                    );
18793                });
18794            });
18795        });
18796    }
18797
18798    pub fn open_excerpts_in_split(
18799        &mut self,
18800        _: &OpenExcerptsSplit,
18801        window: &mut Window,
18802        cx: &mut Context<Self>,
18803    ) {
18804        self.open_excerpts_common(None, true, window, cx)
18805    }
18806
18807    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18808        self.open_excerpts_common(None, false, window, cx)
18809    }
18810
18811    fn open_excerpts_common(
18812        &mut self,
18813        jump_data: Option<JumpData>,
18814        split: bool,
18815        window: &mut Window,
18816        cx: &mut Context<Self>,
18817    ) {
18818        let Some(workspace) = self.workspace() else {
18819            cx.propagate();
18820            return;
18821        };
18822
18823        if self.buffer.read(cx).is_singleton() {
18824            cx.propagate();
18825            return;
18826        }
18827
18828        let mut new_selections_by_buffer = HashMap::default();
18829        match &jump_data {
18830            Some(JumpData::MultiBufferPoint {
18831                excerpt_id,
18832                position,
18833                anchor,
18834                line_offset_from_top,
18835            }) => {
18836                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18837                if let Some(buffer) = multi_buffer_snapshot
18838                    .buffer_id_for_excerpt(*excerpt_id)
18839                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18840                {
18841                    let buffer_snapshot = buffer.read(cx).snapshot();
18842                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18843                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18844                    } else {
18845                        buffer_snapshot.clip_point(*position, Bias::Left)
18846                    };
18847                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18848                    new_selections_by_buffer.insert(
18849                        buffer,
18850                        (
18851                            vec![jump_to_offset..jump_to_offset],
18852                            Some(*line_offset_from_top),
18853                        ),
18854                    );
18855                }
18856            }
18857            Some(JumpData::MultiBufferRow {
18858                row,
18859                line_offset_from_top,
18860            }) => {
18861                let point = MultiBufferPoint::new(row.0, 0);
18862                if let Some((buffer, buffer_point, _)) =
18863                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18864                {
18865                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18866                    new_selections_by_buffer
18867                        .entry(buffer)
18868                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18869                        .0
18870                        .push(buffer_offset..buffer_offset)
18871                }
18872            }
18873            None => {
18874                let selections = self.selections.all::<usize>(cx);
18875                let multi_buffer = self.buffer.read(cx);
18876                for selection in selections {
18877                    for (snapshot, range, _, anchor) in multi_buffer
18878                        .snapshot(cx)
18879                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18880                    {
18881                        if let Some(anchor) = anchor {
18882                            // selection is in a deleted hunk
18883                            let Some(buffer_id) = anchor.buffer_id else {
18884                                continue;
18885                            };
18886                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18887                                continue;
18888                            };
18889                            let offset = text::ToOffset::to_offset(
18890                                &anchor.text_anchor,
18891                                &buffer_handle.read(cx).snapshot(),
18892                            );
18893                            let range = offset..offset;
18894                            new_selections_by_buffer
18895                                .entry(buffer_handle)
18896                                .or_insert((Vec::new(), None))
18897                                .0
18898                                .push(range)
18899                        } else {
18900                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18901                            else {
18902                                continue;
18903                            };
18904                            new_selections_by_buffer
18905                                .entry(buffer_handle)
18906                                .or_insert((Vec::new(), None))
18907                                .0
18908                                .push(range)
18909                        }
18910                    }
18911                }
18912            }
18913        }
18914
18915        new_selections_by_buffer
18916            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18917
18918        if new_selections_by_buffer.is_empty() {
18919            return;
18920        }
18921
18922        // We defer the pane interaction because we ourselves are a workspace item
18923        // and activating a new item causes the pane to call a method on us reentrantly,
18924        // which panics if we're on the stack.
18925        window.defer(cx, move |window, cx| {
18926            workspace.update(cx, |workspace, cx| {
18927                let pane = if split {
18928                    workspace.adjacent_pane(window, cx)
18929                } else {
18930                    workspace.active_pane().clone()
18931                };
18932
18933                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
18934                    let editor = buffer
18935                        .read(cx)
18936                        .file()
18937                        .is_none()
18938                        .then(|| {
18939                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
18940                            // so `workspace.open_project_item` will never find them, always opening a new editor.
18941                            // Instead, we try to activate the existing editor in the pane first.
18942                            let (editor, pane_item_index) =
18943                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
18944                                    let editor = item.downcast::<Editor>()?;
18945                                    let singleton_buffer =
18946                                        editor.read(cx).buffer().read(cx).as_singleton()?;
18947                                    if singleton_buffer == buffer {
18948                                        Some((editor, i))
18949                                    } else {
18950                                        None
18951                                    }
18952                                })?;
18953                            pane.update(cx, |pane, cx| {
18954                                pane.activate_item(pane_item_index, true, true, window, cx)
18955                            });
18956                            Some(editor)
18957                        })
18958                        .flatten()
18959                        .unwrap_or_else(|| {
18960                            workspace.open_project_item::<Self>(
18961                                pane.clone(),
18962                                buffer,
18963                                true,
18964                                true,
18965                                window,
18966                                cx,
18967                            )
18968                        });
18969
18970                    editor.update(cx, |editor, cx| {
18971                        let autoscroll = match scroll_offset {
18972                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
18973                            None => Autoscroll::newest(),
18974                        };
18975                        let nav_history = editor.nav_history.take();
18976                        editor.change_selections(Some(autoscroll), window, cx, |s| {
18977                            s.select_ranges(ranges);
18978                        });
18979                        editor.nav_history = nav_history;
18980                    });
18981                }
18982            })
18983        });
18984    }
18985
18986    // For now, don't allow opening excerpts in buffers that aren't backed by
18987    // regular project files.
18988    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
18989        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
18990    }
18991
18992    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
18993        let snapshot = self.buffer.read(cx).read(cx);
18994        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
18995        Some(
18996            ranges
18997                .iter()
18998                .map(move |range| {
18999                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19000                })
19001                .collect(),
19002        )
19003    }
19004
19005    fn selection_replacement_ranges(
19006        &self,
19007        range: Range<OffsetUtf16>,
19008        cx: &mut App,
19009    ) -> Vec<Range<OffsetUtf16>> {
19010        let selections = self.selections.all::<OffsetUtf16>(cx);
19011        let newest_selection = selections
19012            .iter()
19013            .max_by_key(|selection| selection.id)
19014            .unwrap();
19015        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19016        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19017        let snapshot = self.buffer.read(cx).read(cx);
19018        selections
19019            .into_iter()
19020            .map(|mut selection| {
19021                selection.start.0 =
19022                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19023                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19024                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19025                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19026            })
19027            .collect()
19028    }
19029
19030    fn report_editor_event(
19031        &self,
19032        event_type: &'static str,
19033        file_extension: Option<String>,
19034        cx: &App,
19035    ) {
19036        if cfg!(any(test, feature = "test-support")) {
19037            return;
19038        }
19039
19040        let Some(project) = &self.project else { return };
19041
19042        // If None, we are in a file without an extension
19043        let file = self
19044            .buffer
19045            .read(cx)
19046            .as_singleton()
19047            .and_then(|b| b.read(cx).file());
19048        let file_extension = file_extension.or(file
19049            .as_ref()
19050            .and_then(|file| Path::new(file.file_name(cx)).extension())
19051            .and_then(|e| e.to_str())
19052            .map(|a| a.to_string()));
19053
19054        let vim_mode = vim_enabled(cx);
19055
19056        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19057        let copilot_enabled = edit_predictions_provider
19058            == language::language_settings::EditPredictionProvider::Copilot;
19059        let copilot_enabled_for_language = self
19060            .buffer
19061            .read(cx)
19062            .language_settings(cx)
19063            .show_edit_predictions;
19064
19065        let project = project.read(cx);
19066        telemetry::event!(
19067            event_type,
19068            file_extension,
19069            vim_mode,
19070            copilot_enabled,
19071            copilot_enabled_for_language,
19072            edit_predictions_provider,
19073            is_via_ssh = project.is_via_ssh(),
19074        );
19075    }
19076
19077    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19078    /// with each line being an array of {text, highlight} objects.
19079    fn copy_highlight_json(
19080        &mut self,
19081        _: &CopyHighlightJson,
19082        window: &mut Window,
19083        cx: &mut Context<Self>,
19084    ) {
19085        #[derive(Serialize)]
19086        struct Chunk<'a> {
19087            text: String,
19088            highlight: Option<&'a str>,
19089        }
19090
19091        let snapshot = self.buffer.read(cx).snapshot(cx);
19092        let range = self
19093            .selected_text_range(false, window, cx)
19094            .and_then(|selection| {
19095                if selection.range.is_empty() {
19096                    None
19097                } else {
19098                    Some(selection.range)
19099                }
19100            })
19101            .unwrap_or_else(|| 0..snapshot.len());
19102
19103        let chunks = snapshot.chunks(range, true);
19104        let mut lines = Vec::new();
19105        let mut line: VecDeque<Chunk> = VecDeque::new();
19106
19107        let Some(style) = self.style.as_ref() else {
19108            return;
19109        };
19110
19111        for chunk in chunks {
19112            let highlight = chunk
19113                .syntax_highlight_id
19114                .and_then(|id| id.name(&style.syntax));
19115            let mut chunk_lines = chunk.text.split('\n').peekable();
19116            while let Some(text) = chunk_lines.next() {
19117                let mut merged_with_last_token = false;
19118                if let Some(last_token) = line.back_mut() {
19119                    if last_token.highlight == highlight {
19120                        last_token.text.push_str(text);
19121                        merged_with_last_token = true;
19122                    }
19123                }
19124
19125                if !merged_with_last_token {
19126                    line.push_back(Chunk {
19127                        text: text.into(),
19128                        highlight,
19129                    });
19130                }
19131
19132                if chunk_lines.peek().is_some() {
19133                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19134                        line.pop_front();
19135                    }
19136                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19137                        line.pop_back();
19138                    }
19139
19140                    lines.push(mem::take(&mut line));
19141                }
19142            }
19143        }
19144
19145        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19146            return;
19147        };
19148        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19149    }
19150
19151    pub fn open_context_menu(
19152        &mut self,
19153        _: &OpenContextMenu,
19154        window: &mut Window,
19155        cx: &mut Context<Self>,
19156    ) {
19157        self.request_autoscroll(Autoscroll::newest(), cx);
19158        let position = self.selections.newest_display(cx).start;
19159        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19160    }
19161
19162    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19163        &self.inlay_hint_cache
19164    }
19165
19166    pub fn replay_insert_event(
19167        &mut self,
19168        text: &str,
19169        relative_utf16_range: Option<Range<isize>>,
19170        window: &mut Window,
19171        cx: &mut Context<Self>,
19172    ) {
19173        if !self.input_enabled {
19174            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19175            return;
19176        }
19177        if let Some(relative_utf16_range) = relative_utf16_range {
19178            let selections = self.selections.all::<OffsetUtf16>(cx);
19179            self.change_selections(None, window, cx, |s| {
19180                let new_ranges = selections.into_iter().map(|range| {
19181                    let start = OffsetUtf16(
19182                        range
19183                            .head()
19184                            .0
19185                            .saturating_add_signed(relative_utf16_range.start),
19186                    );
19187                    let end = OffsetUtf16(
19188                        range
19189                            .head()
19190                            .0
19191                            .saturating_add_signed(relative_utf16_range.end),
19192                    );
19193                    start..end
19194                });
19195                s.select_ranges(new_ranges);
19196            });
19197        }
19198
19199        self.handle_input(text, window, cx);
19200    }
19201
19202    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19203        let Some(provider) = self.semantics_provider.as_ref() else {
19204            return false;
19205        };
19206
19207        let mut supports = false;
19208        self.buffer().update(cx, |this, cx| {
19209            this.for_each_buffer(|buffer| {
19210                supports |= provider.supports_inlay_hints(buffer, cx);
19211            });
19212        });
19213
19214        supports
19215    }
19216
19217    pub fn is_focused(&self, window: &Window) -> bool {
19218        self.focus_handle.is_focused(window)
19219    }
19220
19221    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19222        cx.emit(EditorEvent::Focused);
19223
19224        if let Some(descendant) = self
19225            .last_focused_descendant
19226            .take()
19227            .and_then(|descendant| descendant.upgrade())
19228        {
19229            window.focus(&descendant);
19230        } else {
19231            if let Some(blame) = self.blame.as_ref() {
19232                blame.update(cx, GitBlame::focus)
19233            }
19234
19235            self.blink_manager.update(cx, BlinkManager::enable);
19236            self.show_cursor_names(window, cx);
19237            self.buffer.update(cx, |buffer, cx| {
19238                buffer.finalize_last_transaction(cx);
19239                if self.leader_id.is_none() {
19240                    buffer.set_active_selections(
19241                        &self.selections.disjoint_anchors(),
19242                        self.selections.line_mode,
19243                        self.cursor_shape,
19244                        cx,
19245                    );
19246                }
19247            });
19248        }
19249    }
19250
19251    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19252        cx.emit(EditorEvent::FocusedIn)
19253    }
19254
19255    fn handle_focus_out(
19256        &mut self,
19257        event: FocusOutEvent,
19258        _window: &mut Window,
19259        cx: &mut Context<Self>,
19260    ) {
19261        if event.blurred != self.focus_handle {
19262            self.last_focused_descendant = Some(event.blurred);
19263        }
19264        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19265    }
19266
19267    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19268        self.blink_manager.update(cx, BlinkManager::disable);
19269        self.buffer
19270            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19271
19272        if let Some(blame) = self.blame.as_ref() {
19273            blame.update(cx, GitBlame::blur)
19274        }
19275        if !self.hover_state.focused(window, cx) {
19276            hide_hover(self, cx);
19277        }
19278        if !self
19279            .context_menu
19280            .borrow()
19281            .as_ref()
19282            .is_some_and(|context_menu| context_menu.focused(window, cx))
19283        {
19284            self.hide_context_menu(window, cx);
19285        }
19286        self.discard_inline_completion(false, cx);
19287        cx.emit(EditorEvent::Blurred);
19288        cx.notify();
19289    }
19290
19291    pub fn register_action<A: Action>(
19292        &mut self,
19293        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19294    ) -> Subscription {
19295        let id = self.next_editor_action_id.post_inc();
19296        let listener = Arc::new(listener);
19297        self.editor_actions.borrow_mut().insert(
19298            id,
19299            Box::new(move |window, _| {
19300                let listener = listener.clone();
19301                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19302                    let action = action.downcast_ref().unwrap();
19303                    if phase == DispatchPhase::Bubble {
19304                        listener(action, window, cx)
19305                    }
19306                })
19307            }),
19308        );
19309
19310        let editor_actions = self.editor_actions.clone();
19311        Subscription::new(move || {
19312            editor_actions.borrow_mut().remove(&id);
19313        })
19314    }
19315
19316    pub fn file_header_size(&self) -> u32 {
19317        FILE_HEADER_HEIGHT
19318    }
19319
19320    pub fn restore(
19321        &mut self,
19322        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19323        window: &mut Window,
19324        cx: &mut Context<Self>,
19325    ) {
19326        let workspace = self.workspace();
19327        let project = self.project.as_ref();
19328        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19329            let mut tasks = Vec::new();
19330            for (buffer_id, changes) in revert_changes {
19331                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19332                    buffer.update(cx, |buffer, cx| {
19333                        buffer.edit(
19334                            changes
19335                                .into_iter()
19336                                .map(|(range, text)| (range, text.to_string())),
19337                            None,
19338                            cx,
19339                        );
19340                    });
19341
19342                    if let Some(project) =
19343                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19344                    {
19345                        project.update(cx, |project, cx| {
19346                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19347                        })
19348                    }
19349                }
19350            }
19351            tasks
19352        });
19353        cx.spawn_in(window, async move |_, cx| {
19354            for (buffer, task) in save_tasks {
19355                let result = task.await;
19356                if result.is_err() {
19357                    let Some(path) = buffer
19358                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19359                        .ok()
19360                    else {
19361                        continue;
19362                    };
19363                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19364                        let Some(task) = cx
19365                            .update_window_entity(&workspace, |workspace, window, cx| {
19366                                workspace
19367                                    .open_path_preview(path, None, false, false, false, window, cx)
19368                            })
19369                            .ok()
19370                        else {
19371                            continue;
19372                        };
19373                        task.await.log_err();
19374                    }
19375                }
19376            }
19377        })
19378        .detach();
19379        self.change_selections(None, window, cx, |selections| selections.refresh());
19380    }
19381
19382    pub fn to_pixel_point(
19383        &self,
19384        source: multi_buffer::Anchor,
19385        editor_snapshot: &EditorSnapshot,
19386        window: &mut Window,
19387    ) -> Option<gpui::Point<Pixels>> {
19388        let source_point = source.to_display_point(editor_snapshot);
19389        self.display_to_pixel_point(source_point, editor_snapshot, window)
19390    }
19391
19392    pub fn display_to_pixel_point(
19393        &self,
19394        source: DisplayPoint,
19395        editor_snapshot: &EditorSnapshot,
19396        window: &mut Window,
19397    ) -> Option<gpui::Point<Pixels>> {
19398        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19399        let text_layout_details = self.text_layout_details(window);
19400        let scroll_top = text_layout_details
19401            .scroll_anchor
19402            .scroll_position(editor_snapshot)
19403            .y;
19404
19405        if source.row().as_f32() < scroll_top.floor() {
19406            return None;
19407        }
19408        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19409        let source_y = line_height * (source.row().as_f32() - scroll_top);
19410        Some(gpui::Point::new(source_x, source_y))
19411    }
19412
19413    pub fn has_visible_completions_menu(&self) -> bool {
19414        !self.edit_prediction_preview_is_active()
19415            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19416                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19417            })
19418    }
19419
19420    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19421        if self.mode.is_minimap() {
19422            return;
19423        }
19424        self.addons
19425            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19426    }
19427
19428    pub fn unregister_addon<T: Addon>(&mut self) {
19429        self.addons.remove(&std::any::TypeId::of::<T>());
19430    }
19431
19432    pub fn addon<T: Addon>(&self) -> Option<&T> {
19433        let type_id = std::any::TypeId::of::<T>();
19434        self.addons
19435            .get(&type_id)
19436            .and_then(|item| item.to_any().downcast_ref::<T>())
19437    }
19438
19439    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19440        let type_id = std::any::TypeId::of::<T>();
19441        self.addons
19442            .get_mut(&type_id)
19443            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19444    }
19445
19446    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19447        let text_layout_details = self.text_layout_details(window);
19448        let style = &text_layout_details.editor_style;
19449        let font_id = window.text_system().resolve_font(&style.text.font());
19450        let font_size = style.text.font_size.to_pixels(window.rem_size());
19451        let line_height = style.text.line_height_in_pixels(window.rem_size());
19452        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19453
19454        gpui::Size::new(em_width, line_height)
19455    }
19456
19457    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19458        self.load_diff_task.clone()
19459    }
19460
19461    fn read_metadata_from_db(
19462        &mut self,
19463        item_id: u64,
19464        workspace_id: WorkspaceId,
19465        window: &mut Window,
19466        cx: &mut Context<Editor>,
19467    ) {
19468        if self.is_singleton(cx)
19469            && !self.mode.is_minimap()
19470            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19471        {
19472            let buffer_snapshot = OnceCell::new();
19473
19474            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19475                if !folds.is_empty() {
19476                    let snapshot =
19477                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19478                    self.fold_ranges(
19479                        folds
19480                            .into_iter()
19481                            .map(|(start, end)| {
19482                                snapshot.clip_offset(start, Bias::Left)
19483                                    ..snapshot.clip_offset(end, Bias::Right)
19484                            })
19485                            .collect(),
19486                        false,
19487                        window,
19488                        cx,
19489                    );
19490                }
19491            }
19492
19493            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19494                if !selections.is_empty() {
19495                    let snapshot =
19496                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19497                    self.change_selections(None, window, cx, |s| {
19498                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19499                            snapshot.clip_offset(start, Bias::Left)
19500                                ..snapshot.clip_offset(end, Bias::Right)
19501                        }));
19502                    });
19503                }
19504            };
19505        }
19506
19507        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19508    }
19509}
19510
19511fn vim_enabled(cx: &App) -> bool {
19512    cx.global::<SettingsStore>()
19513        .raw_user_settings()
19514        .get("vim_mode")
19515        == Some(&serde_json::Value::Bool(true))
19516}
19517
19518// Consider user intent and default settings
19519fn choose_completion_range(
19520    completion: &Completion,
19521    intent: CompletionIntent,
19522    buffer: &Entity<Buffer>,
19523    cx: &mut Context<Editor>,
19524) -> Range<usize> {
19525    fn should_replace(
19526        completion: &Completion,
19527        insert_range: &Range<text::Anchor>,
19528        intent: CompletionIntent,
19529        completion_mode_setting: LspInsertMode,
19530        buffer: &Buffer,
19531    ) -> bool {
19532        // specific actions take precedence over settings
19533        match intent {
19534            CompletionIntent::CompleteWithInsert => return false,
19535            CompletionIntent::CompleteWithReplace => return true,
19536            CompletionIntent::Complete | CompletionIntent::Compose => {}
19537        }
19538
19539        match completion_mode_setting {
19540            LspInsertMode::Insert => false,
19541            LspInsertMode::Replace => true,
19542            LspInsertMode::ReplaceSubsequence => {
19543                let mut text_to_replace = buffer.chars_for_range(
19544                    buffer.anchor_before(completion.replace_range.start)
19545                        ..buffer.anchor_after(completion.replace_range.end),
19546                );
19547                let mut completion_text = completion.new_text.chars();
19548
19549                // is `text_to_replace` a subsequence of `completion_text`
19550                text_to_replace
19551                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
19552            }
19553            LspInsertMode::ReplaceSuffix => {
19554                let range_after_cursor = insert_range.end..completion.replace_range.end;
19555
19556                let text_after_cursor = buffer
19557                    .text_for_range(
19558                        buffer.anchor_before(range_after_cursor.start)
19559                            ..buffer.anchor_after(range_after_cursor.end),
19560                    )
19561                    .collect::<String>();
19562                completion.new_text.ends_with(&text_after_cursor)
19563            }
19564        }
19565    }
19566
19567    let buffer = buffer.read(cx);
19568
19569    if let CompletionSource::Lsp {
19570        insert_range: Some(insert_range),
19571        ..
19572    } = &completion.source
19573    {
19574        let completion_mode_setting =
19575            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19576                .completions
19577                .lsp_insert_mode;
19578
19579        if !should_replace(
19580            completion,
19581            &insert_range,
19582            intent,
19583            completion_mode_setting,
19584            buffer,
19585        ) {
19586            return insert_range.to_offset(buffer);
19587        }
19588    }
19589
19590    completion.replace_range.to_offset(buffer)
19591}
19592
19593fn insert_extra_newline_brackets(
19594    buffer: &MultiBufferSnapshot,
19595    range: Range<usize>,
19596    language: &language::LanguageScope,
19597) -> bool {
19598    let leading_whitespace_len = buffer
19599        .reversed_chars_at(range.start)
19600        .take_while(|c| c.is_whitespace() && *c != '\n')
19601        .map(|c| c.len_utf8())
19602        .sum::<usize>();
19603    let trailing_whitespace_len = buffer
19604        .chars_at(range.end)
19605        .take_while(|c| c.is_whitespace() && *c != '\n')
19606        .map(|c| c.len_utf8())
19607        .sum::<usize>();
19608    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19609
19610    language.brackets().any(|(pair, enabled)| {
19611        let pair_start = pair.start.trim_end();
19612        let pair_end = pair.end.trim_start();
19613
19614        enabled
19615            && pair.newline
19616            && buffer.contains_str_at(range.end, pair_end)
19617            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19618    })
19619}
19620
19621fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19622    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19623        [(buffer, range, _)] => (*buffer, range.clone()),
19624        _ => return false,
19625    };
19626    let pair = {
19627        let mut result: Option<BracketMatch> = None;
19628
19629        for pair in buffer
19630            .all_bracket_ranges(range.clone())
19631            .filter(move |pair| {
19632                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19633            })
19634        {
19635            let len = pair.close_range.end - pair.open_range.start;
19636
19637            if let Some(existing) = &result {
19638                let existing_len = existing.close_range.end - existing.open_range.start;
19639                if len > existing_len {
19640                    continue;
19641                }
19642            }
19643
19644            result = Some(pair);
19645        }
19646
19647        result
19648    };
19649    let Some(pair) = pair else {
19650        return false;
19651    };
19652    pair.newline_only
19653        && buffer
19654            .chars_for_range(pair.open_range.end..range.start)
19655            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19656            .all(|c| c.is_whitespace() && c != '\n')
19657}
19658
19659fn update_uncommitted_diff_for_buffer(
19660    editor: Entity<Editor>,
19661    project: &Entity<Project>,
19662    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19663    buffer: Entity<MultiBuffer>,
19664    cx: &mut App,
19665) -> Task<()> {
19666    let mut tasks = Vec::new();
19667    project.update(cx, |project, cx| {
19668        for buffer in buffers {
19669            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19670                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19671            }
19672        }
19673    });
19674    cx.spawn(async move |cx| {
19675        let diffs = future::join_all(tasks).await;
19676        if editor
19677            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19678            .unwrap_or(false)
19679        {
19680            return;
19681        }
19682
19683        buffer
19684            .update(cx, |buffer, cx| {
19685                for diff in diffs.into_iter().flatten() {
19686                    buffer.add_diff(diff, cx);
19687                }
19688            })
19689            .ok();
19690    })
19691}
19692
19693fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
19694    let tab_size = tab_size.get() as usize;
19695    let mut width = offset;
19696
19697    for ch in text.chars() {
19698        width += if ch == '\t' {
19699            tab_size - (width % tab_size)
19700        } else {
19701            1
19702        };
19703    }
19704
19705    width - offset
19706}
19707
19708#[cfg(test)]
19709mod tests {
19710    use super::*;
19711
19712    #[test]
19713    fn test_string_size_with_expanded_tabs() {
19714        let nz = |val| NonZeroU32::new(val).unwrap();
19715        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
19716        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
19717        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
19718        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
19719        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
19720        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
19721        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
19722        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
19723    }
19724}
19725
19726/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
19727struct WordBreakingTokenizer<'a> {
19728    input: &'a str,
19729}
19730
19731impl<'a> WordBreakingTokenizer<'a> {
19732    fn new(input: &'a str) -> Self {
19733        Self { input }
19734    }
19735}
19736
19737fn is_char_ideographic(ch: char) -> bool {
19738    use unicode_script::Script::*;
19739    use unicode_script::UnicodeScript;
19740    matches!(ch.script(), Han | Tangut | Yi)
19741}
19742
19743fn is_grapheme_ideographic(text: &str) -> bool {
19744    text.chars().any(is_char_ideographic)
19745}
19746
19747fn is_grapheme_whitespace(text: &str) -> bool {
19748    text.chars().any(|x| x.is_whitespace())
19749}
19750
19751fn should_stay_with_preceding_ideograph(text: &str) -> bool {
19752    text.chars().next().map_or(false, |ch| {
19753        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
19754    })
19755}
19756
19757#[derive(PartialEq, Eq, Debug, Clone, Copy)]
19758enum WordBreakToken<'a> {
19759    Word { token: &'a str, grapheme_len: usize },
19760    InlineWhitespace { token: &'a str, grapheme_len: usize },
19761    Newline,
19762}
19763
19764impl<'a> Iterator for WordBreakingTokenizer<'a> {
19765    /// Yields a span, the count of graphemes in the token, and whether it was
19766    /// whitespace. Note that it also breaks at word boundaries.
19767    type Item = WordBreakToken<'a>;
19768
19769    fn next(&mut self) -> Option<Self::Item> {
19770        use unicode_segmentation::UnicodeSegmentation;
19771        if self.input.is_empty() {
19772            return None;
19773        }
19774
19775        let mut iter = self.input.graphemes(true).peekable();
19776        let mut offset = 0;
19777        let mut grapheme_len = 0;
19778        if let Some(first_grapheme) = iter.next() {
19779            let is_newline = first_grapheme == "\n";
19780            let is_whitespace = is_grapheme_whitespace(first_grapheme);
19781            offset += first_grapheme.len();
19782            grapheme_len += 1;
19783            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
19784                if let Some(grapheme) = iter.peek().copied() {
19785                    if should_stay_with_preceding_ideograph(grapheme) {
19786                        offset += grapheme.len();
19787                        grapheme_len += 1;
19788                    }
19789                }
19790            } else {
19791                let mut words = self.input[offset..].split_word_bound_indices().peekable();
19792                let mut next_word_bound = words.peek().copied();
19793                if next_word_bound.map_or(false, |(i, _)| i == 0) {
19794                    next_word_bound = words.next();
19795                }
19796                while let Some(grapheme) = iter.peek().copied() {
19797                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
19798                        break;
19799                    };
19800                    if is_grapheme_whitespace(grapheme) != is_whitespace
19801                        || (grapheme == "\n") != is_newline
19802                    {
19803                        break;
19804                    };
19805                    offset += grapheme.len();
19806                    grapheme_len += 1;
19807                    iter.next();
19808                }
19809            }
19810            let token = &self.input[..offset];
19811            self.input = &self.input[offset..];
19812            if token == "\n" {
19813                Some(WordBreakToken::Newline)
19814            } else if is_whitespace {
19815                Some(WordBreakToken::InlineWhitespace {
19816                    token,
19817                    grapheme_len,
19818                })
19819            } else {
19820                Some(WordBreakToken::Word {
19821                    token,
19822                    grapheme_len,
19823                })
19824            }
19825        } else {
19826            None
19827        }
19828    }
19829}
19830
19831#[test]
19832fn test_word_breaking_tokenizer() {
19833    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
19834        ("", &[]),
19835        ("  ", &[whitespace("  ", 2)]),
19836        ("Ʒ", &[word("Ʒ", 1)]),
19837        ("Ǽ", &[word("Ǽ", 1)]),
19838        ("", &[word("", 1)]),
19839        ("⋑⋑", &[word("⋑⋑", 2)]),
19840        (
19841            "原理,进而",
19842            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
19843        ),
19844        (
19845            "hello world",
19846            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
19847        ),
19848        (
19849            "hello, world",
19850            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
19851        ),
19852        (
19853            "  hello world",
19854            &[
19855                whitespace("  ", 2),
19856                word("hello", 5),
19857                whitespace(" ", 1),
19858                word("world", 5),
19859            ],
19860        ),
19861        (
19862            "这是什么 \n 钢笔",
19863            &[
19864                word("", 1),
19865                word("", 1),
19866                word("", 1),
19867                word("", 1),
19868                whitespace(" ", 1),
19869                newline(),
19870                whitespace(" ", 1),
19871                word("", 1),
19872                word("", 1),
19873            ],
19874        ),
19875        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
19876    ];
19877
19878    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19879        WordBreakToken::Word {
19880            token,
19881            grapheme_len,
19882        }
19883    }
19884
19885    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19886        WordBreakToken::InlineWhitespace {
19887            token,
19888            grapheme_len,
19889        }
19890    }
19891
19892    fn newline() -> WordBreakToken<'static> {
19893        WordBreakToken::Newline
19894    }
19895
19896    for (input, result) in tests {
19897        assert_eq!(
19898            WordBreakingTokenizer::new(input)
19899                .collect::<Vec<_>>()
19900                .as_slice(),
19901            *result,
19902        );
19903    }
19904}
19905
19906fn wrap_with_prefix(
19907    line_prefix: String,
19908    unwrapped_text: String,
19909    wrap_column: usize,
19910    tab_size: NonZeroU32,
19911    preserve_existing_whitespace: bool,
19912) -> String {
19913    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
19914    let mut wrapped_text = String::new();
19915    let mut current_line = line_prefix.clone();
19916
19917    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
19918    let mut current_line_len = line_prefix_len;
19919    let mut in_whitespace = false;
19920    for token in tokenizer {
19921        let have_preceding_whitespace = in_whitespace;
19922        match token {
19923            WordBreakToken::Word {
19924                token,
19925                grapheme_len,
19926            } => {
19927                in_whitespace = false;
19928                if current_line_len + grapheme_len > wrap_column
19929                    && current_line_len != line_prefix_len
19930                {
19931                    wrapped_text.push_str(current_line.trim_end());
19932                    wrapped_text.push('\n');
19933                    current_line.truncate(line_prefix.len());
19934                    current_line_len = line_prefix_len;
19935                }
19936                current_line.push_str(token);
19937                current_line_len += grapheme_len;
19938            }
19939            WordBreakToken::InlineWhitespace {
19940                mut token,
19941                mut grapheme_len,
19942            } => {
19943                in_whitespace = true;
19944                if have_preceding_whitespace && !preserve_existing_whitespace {
19945                    continue;
19946                }
19947                if !preserve_existing_whitespace {
19948                    token = " ";
19949                    grapheme_len = 1;
19950                }
19951                if current_line_len + grapheme_len > wrap_column {
19952                    wrapped_text.push_str(current_line.trim_end());
19953                    wrapped_text.push('\n');
19954                    current_line.truncate(line_prefix.len());
19955                    current_line_len = line_prefix_len;
19956                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
19957                    current_line.push_str(token);
19958                    current_line_len += grapheme_len;
19959                }
19960            }
19961            WordBreakToken::Newline => {
19962                in_whitespace = true;
19963                if preserve_existing_whitespace {
19964                    wrapped_text.push_str(current_line.trim_end());
19965                    wrapped_text.push('\n');
19966                    current_line.truncate(line_prefix.len());
19967                    current_line_len = line_prefix_len;
19968                } else if have_preceding_whitespace {
19969                    continue;
19970                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
19971                {
19972                    wrapped_text.push_str(current_line.trim_end());
19973                    wrapped_text.push('\n');
19974                    current_line.truncate(line_prefix.len());
19975                    current_line_len = line_prefix_len;
19976                } else if current_line_len != line_prefix_len {
19977                    current_line.push(' ');
19978                    current_line_len += 1;
19979                }
19980            }
19981        }
19982    }
19983
19984    if !current_line.is_empty() {
19985        wrapped_text.push_str(&current_line);
19986    }
19987    wrapped_text
19988}
19989
19990#[test]
19991fn test_wrap_with_prefix() {
19992    assert_eq!(
19993        wrap_with_prefix(
19994            "# ".to_string(),
19995            "abcdefg".to_string(),
19996            4,
19997            NonZeroU32::new(4).unwrap(),
19998            false,
19999        ),
20000        "# abcdefg"
20001    );
20002    assert_eq!(
20003        wrap_with_prefix(
20004            "".to_string(),
20005            "\thello world".to_string(),
20006            8,
20007            NonZeroU32::new(4).unwrap(),
20008            false,
20009        ),
20010        "hello\nworld"
20011    );
20012    assert_eq!(
20013        wrap_with_prefix(
20014            "// ".to_string(),
20015            "xx \nyy zz aa bb cc".to_string(),
20016            12,
20017            NonZeroU32::new(4).unwrap(),
20018            false,
20019        ),
20020        "// xx yy zz\n// aa bb cc"
20021    );
20022    assert_eq!(
20023        wrap_with_prefix(
20024            String::new(),
20025            "这是什么 \n 钢笔".to_string(),
20026            3,
20027            NonZeroU32::new(4).unwrap(),
20028            false,
20029        ),
20030        "这是什\n么 钢\n"
20031    );
20032}
20033
20034pub trait CollaborationHub {
20035    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20036    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20037    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20038}
20039
20040impl CollaborationHub for Entity<Project> {
20041    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20042        self.read(cx).collaborators()
20043    }
20044
20045    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20046        self.read(cx).user_store().read(cx).participant_indices()
20047    }
20048
20049    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20050        let this = self.read(cx);
20051        let user_ids = this.collaborators().values().map(|c| c.user_id);
20052        this.user_store().read(cx).participant_names(user_ids, cx)
20053    }
20054}
20055
20056pub trait SemanticsProvider {
20057    fn hover(
20058        &self,
20059        buffer: &Entity<Buffer>,
20060        position: text::Anchor,
20061        cx: &mut App,
20062    ) -> Option<Task<Vec<project::Hover>>>;
20063
20064    fn inline_values(
20065        &self,
20066        buffer_handle: Entity<Buffer>,
20067        range: Range<text::Anchor>,
20068        cx: &mut App,
20069    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20070
20071    fn inlay_hints(
20072        &self,
20073        buffer_handle: Entity<Buffer>,
20074        range: Range<text::Anchor>,
20075        cx: &mut App,
20076    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20077
20078    fn resolve_inlay_hint(
20079        &self,
20080        hint: InlayHint,
20081        buffer_handle: Entity<Buffer>,
20082        server_id: LanguageServerId,
20083        cx: &mut App,
20084    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20085
20086    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20087
20088    fn document_highlights(
20089        &self,
20090        buffer: &Entity<Buffer>,
20091        position: text::Anchor,
20092        cx: &mut App,
20093    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20094
20095    fn definitions(
20096        &self,
20097        buffer: &Entity<Buffer>,
20098        position: text::Anchor,
20099        kind: GotoDefinitionKind,
20100        cx: &mut App,
20101    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20102
20103    fn range_for_rename(
20104        &self,
20105        buffer: &Entity<Buffer>,
20106        position: text::Anchor,
20107        cx: &mut App,
20108    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20109
20110    fn perform_rename(
20111        &self,
20112        buffer: &Entity<Buffer>,
20113        position: text::Anchor,
20114        new_name: String,
20115        cx: &mut App,
20116    ) -> Option<Task<Result<ProjectTransaction>>>;
20117}
20118
20119pub trait CompletionProvider {
20120    fn completions(
20121        &self,
20122        excerpt_id: ExcerptId,
20123        buffer: &Entity<Buffer>,
20124        buffer_position: text::Anchor,
20125        trigger: CompletionContext,
20126        window: &mut Window,
20127        cx: &mut Context<Editor>,
20128    ) -> Task<Result<Option<Vec<Completion>>>>;
20129
20130    fn resolve_completions(
20131        &self,
20132        buffer: Entity<Buffer>,
20133        completion_indices: Vec<usize>,
20134        completions: Rc<RefCell<Box<[Completion]>>>,
20135        cx: &mut Context<Editor>,
20136    ) -> Task<Result<bool>>;
20137
20138    fn apply_additional_edits_for_completion(
20139        &self,
20140        _buffer: Entity<Buffer>,
20141        _completions: Rc<RefCell<Box<[Completion]>>>,
20142        _completion_index: usize,
20143        _push_to_history: bool,
20144        _cx: &mut Context<Editor>,
20145    ) -> Task<Result<Option<language::Transaction>>> {
20146        Task::ready(Ok(None))
20147    }
20148
20149    fn is_completion_trigger(
20150        &self,
20151        buffer: &Entity<Buffer>,
20152        position: language::Anchor,
20153        text: &str,
20154        trigger_in_words: bool,
20155        cx: &mut Context<Editor>,
20156    ) -> bool;
20157
20158    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20159
20160    fn sort_completions(&self) -> bool {
20161        true
20162    }
20163
20164    fn filter_completions(&self) -> bool {
20165        true
20166    }
20167}
20168
20169pub trait CodeActionProvider {
20170    fn id(&self) -> Arc<str>;
20171
20172    fn code_actions(
20173        &self,
20174        buffer: &Entity<Buffer>,
20175        range: Range<text::Anchor>,
20176        window: &mut Window,
20177        cx: &mut App,
20178    ) -> Task<Result<Vec<CodeAction>>>;
20179
20180    fn apply_code_action(
20181        &self,
20182        buffer_handle: Entity<Buffer>,
20183        action: CodeAction,
20184        excerpt_id: ExcerptId,
20185        push_to_history: bool,
20186        window: &mut Window,
20187        cx: &mut App,
20188    ) -> Task<Result<ProjectTransaction>>;
20189}
20190
20191impl CodeActionProvider for Entity<Project> {
20192    fn id(&self) -> Arc<str> {
20193        "project".into()
20194    }
20195
20196    fn code_actions(
20197        &self,
20198        buffer: &Entity<Buffer>,
20199        range: Range<text::Anchor>,
20200        _window: &mut Window,
20201        cx: &mut App,
20202    ) -> Task<Result<Vec<CodeAction>>> {
20203        self.update(cx, |project, cx| {
20204            let code_lens = project.code_lens(buffer, range.clone(), cx);
20205            let code_actions = project.code_actions(buffer, range, None, cx);
20206            cx.background_spawn(async move {
20207                let (code_lens, code_actions) = join(code_lens, code_actions).await;
20208                Ok(code_lens
20209                    .context("code lens fetch")?
20210                    .into_iter()
20211                    .chain(code_actions.context("code action fetch")?)
20212                    .collect())
20213            })
20214        })
20215    }
20216
20217    fn apply_code_action(
20218        &self,
20219        buffer_handle: Entity<Buffer>,
20220        action: CodeAction,
20221        _excerpt_id: ExcerptId,
20222        push_to_history: bool,
20223        _window: &mut Window,
20224        cx: &mut App,
20225    ) -> Task<Result<ProjectTransaction>> {
20226        self.update(cx, |project, cx| {
20227            project.apply_code_action(buffer_handle, action, push_to_history, cx)
20228        })
20229    }
20230}
20231
20232fn snippet_completions(
20233    project: &Project,
20234    buffer: &Entity<Buffer>,
20235    buffer_position: text::Anchor,
20236    cx: &mut App,
20237) -> Task<Result<Vec<Completion>>> {
20238    let languages = buffer.read(cx).languages_at(buffer_position);
20239    let snippet_store = project.snippets().read(cx);
20240
20241    let scopes: Vec<_> = languages
20242        .iter()
20243        .filter_map(|language| {
20244            let language_name = language.lsp_id();
20245            let snippets = snippet_store.snippets_for(Some(language_name), cx);
20246
20247            if snippets.is_empty() {
20248                None
20249            } else {
20250                Some((language.default_scope(), snippets))
20251            }
20252        })
20253        .collect();
20254
20255    if scopes.is_empty() {
20256        return Task::ready(Ok(vec![]));
20257    }
20258
20259    let snapshot = buffer.read(cx).text_snapshot();
20260    let chars: String = snapshot
20261        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
20262        .collect();
20263    let executor = cx.background_executor().clone();
20264
20265    cx.background_spawn(async move {
20266        let mut all_results: Vec<Completion> = Vec::new();
20267        for (scope, snippets) in scopes.into_iter() {
20268            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
20269            let mut last_word = chars
20270                .chars()
20271                .take_while(|c| classifier.is_word(*c))
20272                .collect::<String>();
20273            last_word = last_word.chars().rev().collect();
20274
20275            if last_word.is_empty() {
20276                return Ok(vec![]);
20277            }
20278
20279            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
20280            let to_lsp = |point: &text::Anchor| {
20281                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
20282                point_to_lsp(end)
20283            };
20284            let lsp_end = to_lsp(&buffer_position);
20285
20286            let candidates = snippets
20287                .iter()
20288                .enumerate()
20289                .flat_map(|(ix, snippet)| {
20290                    snippet
20291                        .prefix
20292                        .iter()
20293                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
20294                })
20295                .collect::<Vec<StringMatchCandidate>>();
20296
20297            let mut matches = fuzzy::match_strings(
20298                &candidates,
20299                &last_word,
20300                last_word.chars().any(|c| c.is_uppercase()),
20301                100,
20302                &Default::default(),
20303                executor.clone(),
20304            )
20305            .await;
20306
20307            // Remove all candidates where the query's start does not match the start of any word in the candidate
20308            if let Some(query_start) = last_word.chars().next() {
20309                matches.retain(|string_match| {
20310                    split_words(&string_match.string).any(|word| {
20311                        // Check that the first codepoint of the word as lowercase matches the first
20312                        // codepoint of the query as lowercase
20313                        word.chars()
20314                            .flat_map(|codepoint| codepoint.to_lowercase())
20315                            .zip(query_start.to_lowercase())
20316                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20317                    })
20318                });
20319            }
20320
20321            let matched_strings = matches
20322                .into_iter()
20323                .map(|m| m.string)
20324                .collect::<HashSet<_>>();
20325
20326            let mut result: Vec<Completion> = snippets
20327                .iter()
20328                .filter_map(|snippet| {
20329                    let matching_prefix = snippet
20330                        .prefix
20331                        .iter()
20332                        .find(|prefix| matched_strings.contains(*prefix))?;
20333                    let start = as_offset - last_word.len();
20334                    let start = snapshot.anchor_before(start);
20335                    let range = start..buffer_position;
20336                    let lsp_start = to_lsp(&start);
20337                    let lsp_range = lsp::Range {
20338                        start: lsp_start,
20339                        end: lsp_end,
20340                    };
20341                    Some(Completion {
20342                        replace_range: range,
20343                        new_text: snippet.body.clone(),
20344                        source: CompletionSource::Lsp {
20345                            insert_range: None,
20346                            server_id: LanguageServerId(usize::MAX),
20347                            resolved: true,
20348                            lsp_completion: Box::new(lsp::CompletionItem {
20349                                label: snippet.prefix.first().unwrap().clone(),
20350                                kind: Some(CompletionItemKind::SNIPPET),
20351                                label_details: snippet.description.as_ref().map(|description| {
20352                                    lsp::CompletionItemLabelDetails {
20353                                        detail: Some(description.clone()),
20354                                        description: None,
20355                                    }
20356                                }),
20357                                insert_text_format: Some(InsertTextFormat::SNIPPET),
20358                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20359                                    lsp::InsertReplaceEdit {
20360                                        new_text: snippet.body.clone(),
20361                                        insert: lsp_range,
20362                                        replace: lsp_range,
20363                                    },
20364                                )),
20365                                filter_text: Some(snippet.body.clone()),
20366                                sort_text: Some(char::MAX.to_string()),
20367                                ..lsp::CompletionItem::default()
20368                            }),
20369                            lsp_defaults: None,
20370                        },
20371                        label: CodeLabel {
20372                            text: matching_prefix.clone(),
20373                            runs: Vec::new(),
20374                            filter_range: 0..matching_prefix.len(),
20375                        },
20376                        icon_path: None,
20377                        documentation: Some(
20378                            CompletionDocumentation::SingleLineAndMultiLinePlainText {
20379                                single_line: snippet.name.clone().into(),
20380                                plain_text: snippet
20381                                    .description
20382                                    .clone()
20383                                    .map(|description| description.into()),
20384                            },
20385                        ),
20386                        insert_text_mode: None,
20387                        confirm: None,
20388                    })
20389                })
20390                .collect();
20391
20392            all_results.append(&mut result);
20393        }
20394
20395        Ok(all_results)
20396    })
20397}
20398
20399impl CompletionProvider for Entity<Project> {
20400    fn completions(
20401        &self,
20402        _excerpt_id: ExcerptId,
20403        buffer: &Entity<Buffer>,
20404        buffer_position: text::Anchor,
20405        options: CompletionContext,
20406        _window: &mut Window,
20407        cx: &mut Context<Editor>,
20408    ) -> Task<Result<Option<Vec<Completion>>>> {
20409        self.update(cx, |project, cx| {
20410            let snippets = snippet_completions(project, buffer, buffer_position, cx);
20411            let project_completions = project.completions(buffer, buffer_position, options, cx);
20412            cx.background_spawn(async move {
20413                let snippets_completions = snippets.await?;
20414                match project_completions.await? {
20415                    Some(mut completions) => {
20416                        completions.extend(snippets_completions);
20417                        Ok(Some(completions))
20418                    }
20419                    None => {
20420                        if snippets_completions.is_empty() {
20421                            Ok(None)
20422                        } else {
20423                            Ok(Some(snippets_completions))
20424                        }
20425                    }
20426                }
20427            })
20428        })
20429    }
20430
20431    fn resolve_completions(
20432        &self,
20433        buffer: Entity<Buffer>,
20434        completion_indices: Vec<usize>,
20435        completions: Rc<RefCell<Box<[Completion]>>>,
20436        cx: &mut Context<Editor>,
20437    ) -> Task<Result<bool>> {
20438        self.update(cx, |project, cx| {
20439            project.lsp_store().update(cx, |lsp_store, cx| {
20440                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
20441            })
20442        })
20443    }
20444
20445    fn apply_additional_edits_for_completion(
20446        &self,
20447        buffer: Entity<Buffer>,
20448        completions: Rc<RefCell<Box<[Completion]>>>,
20449        completion_index: usize,
20450        push_to_history: bool,
20451        cx: &mut Context<Editor>,
20452    ) -> Task<Result<Option<language::Transaction>>> {
20453        self.update(cx, |project, cx| {
20454            project.lsp_store().update(cx, |lsp_store, cx| {
20455                lsp_store.apply_additional_edits_for_completion(
20456                    buffer,
20457                    completions,
20458                    completion_index,
20459                    push_to_history,
20460                    cx,
20461                )
20462            })
20463        })
20464    }
20465
20466    fn is_completion_trigger(
20467        &self,
20468        buffer: &Entity<Buffer>,
20469        position: language::Anchor,
20470        text: &str,
20471        trigger_in_words: bool,
20472        cx: &mut Context<Editor>,
20473    ) -> bool {
20474        let mut chars = text.chars();
20475        let char = if let Some(char) = chars.next() {
20476            char
20477        } else {
20478            return false;
20479        };
20480        if chars.next().is_some() {
20481            return false;
20482        }
20483
20484        let buffer = buffer.read(cx);
20485        let snapshot = buffer.snapshot();
20486        if !snapshot.settings_at(position, cx).show_completions_on_input {
20487            return false;
20488        }
20489        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20490        if trigger_in_words && classifier.is_word(char) {
20491            return true;
20492        }
20493
20494        buffer.completion_triggers().contains(text)
20495    }
20496}
20497
20498impl SemanticsProvider for Entity<Project> {
20499    fn hover(
20500        &self,
20501        buffer: &Entity<Buffer>,
20502        position: text::Anchor,
20503        cx: &mut App,
20504    ) -> Option<Task<Vec<project::Hover>>> {
20505        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20506    }
20507
20508    fn document_highlights(
20509        &self,
20510        buffer: &Entity<Buffer>,
20511        position: text::Anchor,
20512        cx: &mut App,
20513    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20514        Some(self.update(cx, |project, cx| {
20515            project.document_highlights(buffer, position, cx)
20516        }))
20517    }
20518
20519    fn definitions(
20520        &self,
20521        buffer: &Entity<Buffer>,
20522        position: text::Anchor,
20523        kind: GotoDefinitionKind,
20524        cx: &mut App,
20525    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20526        Some(self.update(cx, |project, cx| match kind {
20527            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20528            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20529            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20530            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20531        }))
20532    }
20533
20534    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20535        // TODO: make this work for remote projects
20536        self.update(cx, |project, cx| {
20537            if project
20538                .active_debug_session(cx)
20539                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20540            {
20541                return true;
20542            }
20543
20544            buffer.update(cx, |buffer, cx| {
20545                project.any_language_server_supports_inlay_hints(buffer, cx)
20546            })
20547        })
20548    }
20549
20550    fn inline_values(
20551        &self,
20552        buffer_handle: Entity<Buffer>,
20553
20554        range: Range<text::Anchor>,
20555        cx: &mut App,
20556    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20557        self.update(cx, |project, cx| {
20558            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20559
20560            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20561        })
20562    }
20563
20564    fn inlay_hints(
20565        &self,
20566        buffer_handle: Entity<Buffer>,
20567        range: Range<text::Anchor>,
20568        cx: &mut App,
20569    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20570        Some(self.update(cx, |project, cx| {
20571            project.inlay_hints(buffer_handle, range, cx)
20572        }))
20573    }
20574
20575    fn resolve_inlay_hint(
20576        &self,
20577        hint: InlayHint,
20578        buffer_handle: Entity<Buffer>,
20579        server_id: LanguageServerId,
20580        cx: &mut App,
20581    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20582        Some(self.update(cx, |project, cx| {
20583            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20584        }))
20585    }
20586
20587    fn range_for_rename(
20588        &self,
20589        buffer: &Entity<Buffer>,
20590        position: text::Anchor,
20591        cx: &mut App,
20592    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20593        Some(self.update(cx, |project, cx| {
20594            let buffer = buffer.clone();
20595            let task = project.prepare_rename(buffer.clone(), position, cx);
20596            cx.spawn(async move |_, cx| {
20597                Ok(match task.await? {
20598                    PrepareRenameResponse::Success(range) => Some(range),
20599                    PrepareRenameResponse::InvalidPosition => None,
20600                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20601                        // Fallback on using TreeSitter info to determine identifier range
20602                        buffer.read_with(cx, |buffer, _| {
20603                            let snapshot = buffer.snapshot();
20604                            let (range, kind) = snapshot.surrounding_word(position);
20605                            if kind != Some(CharKind::Word) {
20606                                return None;
20607                            }
20608                            Some(
20609                                snapshot.anchor_before(range.start)
20610                                    ..snapshot.anchor_after(range.end),
20611                            )
20612                        })?
20613                    }
20614                })
20615            })
20616        }))
20617    }
20618
20619    fn perform_rename(
20620        &self,
20621        buffer: &Entity<Buffer>,
20622        position: text::Anchor,
20623        new_name: String,
20624        cx: &mut App,
20625    ) -> Option<Task<Result<ProjectTransaction>>> {
20626        Some(self.update(cx, |project, cx| {
20627            project.perform_rename(buffer.clone(), position, new_name, cx)
20628        }))
20629    }
20630}
20631
20632fn inlay_hint_settings(
20633    location: Anchor,
20634    snapshot: &MultiBufferSnapshot,
20635    cx: &mut Context<Editor>,
20636) -> InlayHintSettings {
20637    let file = snapshot.file_at(location);
20638    let language = snapshot.language_at(location).map(|l| l.name());
20639    language_settings(language, file, cx).inlay_hints
20640}
20641
20642fn consume_contiguous_rows(
20643    contiguous_row_selections: &mut Vec<Selection<Point>>,
20644    selection: &Selection<Point>,
20645    display_map: &DisplaySnapshot,
20646    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20647) -> (MultiBufferRow, MultiBufferRow) {
20648    contiguous_row_selections.push(selection.clone());
20649    let start_row = MultiBufferRow(selection.start.row);
20650    let mut end_row = ending_row(selection, display_map);
20651
20652    while let Some(next_selection) = selections.peek() {
20653        if next_selection.start.row <= end_row.0 {
20654            end_row = ending_row(next_selection, display_map);
20655            contiguous_row_selections.push(selections.next().unwrap().clone());
20656        } else {
20657            break;
20658        }
20659    }
20660    (start_row, end_row)
20661}
20662
20663fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20664    if next_selection.end.column > 0 || next_selection.is_empty() {
20665        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20666    } else {
20667        MultiBufferRow(next_selection.end.row)
20668    }
20669}
20670
20671impl EditorSnapshot {
20672    pub fn remote_selections_in_range<'a>(
20673        &'a self,
20674        range: &'a Range<Anchor>,
20675        collaboration_hub: &dyn CollaborationHub,
20676        cx: &'a App,
20677    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20678        let participant_names = collaboration_hub.user_names(cx);
20679        let participant_indices = collaboration_hub.user_participant_indices(cx);
20680        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20681        let collaborators_by_replica_id = collaborators_by_peer_id
20682            .values()
20683            .map(|collaborator| (collaborator.replica_id, collaborator))
20684            .collect::<HashMap<_, _>>();
20685        self.buffer_snapshot
20686            .selections_in_range(range, false)
20687            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20688                if replica_id == AGENT_REPLICA_ID {
20689                    Some(RemoteSelection {
20690                        replica_id,
20691                        selection,
20692                        cursor_shape,
20693                        line_mode,
20694                        collaborator_id: CollaboratorId::Agent,
20695                        user_name: Some("Agent".into()),
20696                        color: cx.theme().players().agent(),
20697                    })
20698                } else {
20699                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20700                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20701                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20702                    Some(RemoteSelection {
20703                        replica_id,
20704                        selection,
20705                        cursor_shape,
20706                        line_mode,
20707                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20708                        user_name,
20709                        color: if let Some(index) = participant_index {
20710                            cx.theme().players().color_for_participant(index.0)
20711                        } else {
20712                            cx.theme().players().absent()
20713                        },
20714                    })
20715                }
20716            })
20717    }
20718
20719    pub fn hunks_for_ranges(
20720        &self,
20721        ranges: impl IntoIterator<Item = Range<Point>>,
20722    ) -> Vec<MultiBufferDiffHunk> {
20723        let mut hunks = Vec::new();
20724        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20725            HashMap::default();
20726        for query_range in ranges {
20727            let query_rows =
20728                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20729            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20730                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20731            ) {
20732                // Include deleted hunks that are adjacent to the query range, because
20733                // otherwise they would be missed.
20734                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20735                if hunk.status().is_deleted() {
20736                    intersects_range |= hunk.row_range.start == query_rows.end;
20737                    intersects_range |= hunk.row_range.end == query_rows.start;
20738                }
20739                if intersects_range {
20740                    if !processed_buffer_rows
20741                        .entry(hunk.buffer_id)
20742                        .or_default()
20743                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20744                    {
20745                        continue;
20746                    }
20747                    hunks.push(hunk);
20748                }
20749            }
20750        }
20751
20752        hunks
20753    }
20754
20755    fn display_diff_hunks_for_rows<'a>(
20756        &'a self,
20757        display_rows: Range<DisplayRow>,
20758        folded_buffers: &'a HashSet<BufferId>,
20759    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20760        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20761        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20762
20763        self.buffer_snapshot
20764            .diff_hunks_in_range(buffer_start..buffer_end)
20765            .filter_map(|hunk| {
20766                if folded_buffers.contains(&hunk.buffer_id) {
20767                    return None;
20768                }
20769
20770                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20771                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20772
20773                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20774                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20775
20776                let display_hunk = if hunk_display_start.column() != 0 {
20777                    DisplayDiffHunk::Folded {
20778                        display_row: hunk_display_start.row(),
20779                    }
20780                } else {
20781                    let mut end_row = hunk_display_end.row();
20782                    if hunk_display_end.column() > 0 {
20783                        end_row.0 += 1;
20784                    }
20785                    let is_created_file = hunk.is_created_file();
20786                    DisplayDiffHunk::Unfolded {
20787                        status: hunk.status(),
20788                        diff_base_byte_range: hunk.diff_base_byte_range,
20789                        display_row_range: hunk_display_start.row()..end_row,
20790                        multi_buffer_range: Anchor::range_in_buffer(
20791                            hunk.excerpt_id,
20792                            hunk.buffer_id,
20793                            hunk.buffer_range,
20794                        ),
20795                        is_created_file,
20796                    }
20797                };
20798
20799                Some(display_hunk)
20800            })
20801    }
20802
20803    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20804        self.display_snapshot.buffer_snapshot.language_at(position)
20805    }
20806
20807    pub fn is_focused(&self) -> bool {
20808        self.is_focused
20809    }
20810
20811    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20812        self.placeholder_text.as_ref()
20813    }
20814
20815    pub fn scroll_position(&self) -> gpui::Point<f32> {
20816        self.scroll_anchor.scroll_position(&self.display_snapshot)
20817    }
20818
20819    fn gutter_dimensions(
20820        &self,
20821        font_id: FontId,
20822        font_size: Pixels,
20823        max_line_number_width: Pixels,
20824        cx: &App,
20825    ) -> Option<GutterDimensions> {
20826        if !self.show_gutter {
20827            return None;
20828        }
20829
20830        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20831        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20832
20833        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20834            matches!(
20835                ProjectSettings::get_global(cx).git.git_gutter,
20836                Some(GitGutterSetting::TrackedFiles)
20837            )
20838        });
20839        let gutter_settings = EditorSettings::get_global(cx).gutter;
20840        let show_line_numbers = self
20841            .show_line_numbers
20842            .unwrap_or(gutter_settings.line_numbers);
20843        let line_gutter_width = if show_line_numbers {
20844            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
20845            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
20846            max_line_number_width.max(min_width_for_number_on_gutter)
20847        } else {
20848            0.0.into()
20849        };
20850
20851        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
20852        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
20853
20854        let git_blame_entries_width =
20855            self.git_blame_gutter_max_author_length
20856                .map(|max_author_length| {
20857                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20858                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
20859
20860                    /// The number of characters to dedicate to gaps and margins.
20861                    const SPACING_WIDTH: usize = 4;
20862
20863                    let max_char_count = max_author_length.min(renderer.max_author_length())
20864                        + ::git::SHORT_SHA_LENGTH
20865                        + MAX_RELATIVE_TIMESTAMP.len()
20866                        + SPACING_WIDTH;
20867
20868                    em_advance * max_char_count
20869                });
20870
20871        let is_singleton = self.buffer_snapshot.is_singleton();
20872
20873        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
20874        left_padding += if !is_singleton {
20875            em_width * 4.0
20876        } else if show_runnables || show_breakpoints {
20877            em_width * 3.0
20878        } else if show_git_gutter && show_line_numbers {
20879            em_width * 2.0
20880        } else if show_git_gutter || show_line_numbers {
20881            em_width
20882        } else {
20883            px(0.)
20884        };
20885
20886        let shows_folds = is_singleton && gutter_settings.folds;
20887
20888        let right_padding = if shows_folds && show_line_numbers {
20889            em_width * 4.0
20890        } else if shows_folds || (!is_singleton && show_line_numbers) {
20891            em_width * 3.0
20892        } else if show_line_numbers {
20893            em_width
20894        } else {
20895            px(0.)
20896        };
20897
20898        Some(GutterDimensions {
20899            left_padding,
20900            right_padding,
20901            width: line_gutter_width + left_padding + right_padding,
20902            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
20903            git_blame_entries_width,
20904        })
20905    }
20906
20907    pub fn render_crease_toggle(
20908        &self,
20909        buffer_row: MultiBufferRow,
20910        row_contains_cursor: bool,
20911        editor: Entity<Editor>,
20912        window: &mut Window,
20913        cx: &mut App,
20914    ) -> Option<AnyElement> {
20915        let folded = self.is_line_folded(buffer_row);
20916        let mut is_foldable = false;
20917
20918        if let Some(crease) = self
20919            .crease_snapshot
20920            .query_row(buffer_row, &self.buffer_snapshot)
20921        {
20922            is_foldable = true;
20923            match crease {
20924                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
20925                    if let Some(render_toggle) = render_toggle {
20926                        let toggle_callback =
20927                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
20928                                if folded {
20929                                    editor.update(cx, |editor, cx| {
20930                                        editor.fold_at(buffer_row, window, cx)
20931                                    });
20932                                } else {
20933                                    editor.update(cx, |editor, cx| {
20934                                        editor.unfold_at(buffer_row, window, cx)
20935                                    });
20936                                }
20937                            });
20938                        return Some((render_toggle)(
20939                            buffer_row,
20940                            folded,
20941                            toggle_callback,
20942                            window,
20943                            cx,
20944                        ));
20945                    }
20946                }
20947            }
20948        }
20949
20950        is_foldable |= self.starts_indent(buffer_row);
20951
20952        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
20953            Some(
20954                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
20955                    .toggle_state(folded)
20956                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
20957                        if folded {
20958                            this.unfold_at(buffer_row, window, cx);
20959                        } else {
20960                            this.fold_at(buffer_row, window, cx);
20961                        }
20962                    }))
20963                    .into_any_element(),
20964            )
20965        } else {
20966            None
20967        }
20968    }
20969
20970    pub fn render_crease_trailer(
20971        &self,
20972        buffer_row: MultiBufferRow,
20973        window: &mut Window,
20974        cx: &mut App,
20975    ) -> Option<AnyElement> {
20976        let folded = self.is_line_folded(buffer_row);
20977        if let Crease::Inline { render_trailer, .. } = self
20978            .crease_snapshot
20979            .query_row(buffer_row, &self.buffer_snapshot)?
20980        {
20981            let render_trailer = render_trailer.as_ref()?;
20982            Some(render_trailer(buffer_row, folded, window, cx))
20983        } else {
20984            None
20985        }
20986    }
20987}
20988
20989impl Deref for EditorSnapshot {
20990    type Target = DisplaySnapshot;
20991
20992    fn deref(&self) -> &Self::Target {
20993        &self.display_snapshot
20994    }
20995}
20996
20997#[derive(Clone, Debug, PartialEq, Eq)]
20998pub enum EditorEvent {
20999    InputIgnored {
21000        text: Arc<str>,
21001    },
21002    InputHandled {
21003        utf16_range_to_replace: Option<Range<isize>>,
21004        text: Arc<str>,
21005    },
21006    ExcerptsAdded {
21007        buffer: Entity<Buffer>,
21008        predecessor: ExcerptId,
21009        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21010    },
21011    ExcerptsRemoved {
21012        ids: Vec<ExcerptId>,
21013        removed_buffer_ids: Vec<BufferId>,
21014    },
21015    BufferFoldToggled {
21016        ids: Vec<ExcerptId>,
21017        folded: bool,
21018    },
21019    ExcerptsEdited {
21020        ids: Vec<ExcerptId>,
21021    },
21022    ExcerptsExpanded {
21023        ids: Vec<ExcerptId>,
21024    },
21025    BufferEdited,
21026    Edited {
21027        transaction_id: clock::Lamport,
21028    },
21029    Reparsed(BufferId),
21030    Focused,
21031    FocusedIn,
21032    Blurred,
21033    DirtyChanged,
21034    Saved,
21035    TitleChanged,
21036    DiffBaseChanged,
21037    SelectionsChanged {
21038        local: bool,
21039    },
21040    ScrollPositionChanged {
21041        local: bool,
21042        autoscroll: bool,
21043    },
21044    Closed,
21045    TransactionUndone {
21046        transaction_id: clock::Lamport,
21047    },
21048    TransactionBegun {
21049        transaction_id: clock::Lamport,
21050    },
21051    Reloaded,
21052    CursorShapeChanged,
21053    PushedToNavHistory {
21054        anchor: Anchor,
21055        is_deactivate: bool,
21056    },
21057}
21058
21059impl EventEmitter<EditorEvent> for Editor {}
21060
21061impl Focusable for Editor {
21062    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21063        self.focus_handle.clone()
21064    }
21065}
21066
21067impl Render for Editor {
21068    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21069        let settings = ThemeSettings::get_global(cx);
21070
21071        let mut text_style = match self.mode {
21072            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21073                color: cx.theme().colors().editor_foreground,
21074                font_family: settings.ui_font.family.clone(),
21075                font_features: settings.ui_font.features.clone(),
21076                font_fallbacks: settings.ui_font.fallbacks.clone(),
21077                font_size: rems(0.875).into(),
21078                font_weight: settings.ui_font.weight,
21079                line_height: relative(settings.buffer_line_height.value()),
21080                ..Default::default()
21081            },
21082            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21083                color: cx.theme().colors().editor_foreground,
21084                font_family: settings.buffer_font.family.clone(),
21085                font_features: settings.buffer_font.features.clone(),
21086                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21087                font_size: settings.buffer_font_size(cx).into(),
21088                font_weight: settings.buffer_font.weight,
21089                line_height: relative(settings.buffer_line_height.value()),
21090                ..Default::default()
21091            },
21092        };
21093        if let Some(text_style_refinement) = &self.text_style_refinement {
21094            text_style.refine(text_style_refinement)
21095        }
21096
21097        let background = match self.mode {
21098            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21099            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
21100            EditorMode::Full { .. } => cx.theme().colors().editor_background,
21101            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
21102        };
21103
21104        EditorElement::new(
21105            &cx.entity(),
21106            EditorStyle {
21107                background,
21108                local_player: cx.theme().players().local(),
21109                text: text_style,
21110                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
21111                syntax: cx.theme().syntax().clone(),
21112                status: cx.theme().status().clone(),
21113                inlay_hints_style: make_inlay_hints_style(cx),
21114                inline_completion_styles: make_suggestion_styles(cx),
21115                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
21116                show_underlines: !self.mode.is_minimap(),
21117            },
21118        )
21119    }
21120}
21121
21122impl EntityInputHandler for Editor {
21123    fn text_for_range(
21124        &mut self,
21125        range_utf16: Range<usize>,
21126        adjusted_range: &mut Option<Range<usize>>,
21127        _: &mut Window,
21128        cx: &mut Context<Self>,
21129    ) -> Option<String> {
21130        let snapshot = self.buffer.read(cx).read(cx);
21131        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
21132        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
21133        if (start.0..end.0) != range_utf16 {
21134            adjusted_range.replace(start.0..end.0);
21135        }
21136        Some(snapshot.text_for_range(start..end).collect())
21137    }
21138
21139    fn selected_text_range(
21140        &mut self,
21141        ignore_disabled_input: bool,
21142        _: &mut Window,
21143        cx: &mut Context<Self>,
21144    ) -> Option<UTF16Selection> {
21145        // Prevent the IME menu from appearing when holding down an alphabetic key
21146        // while input is disabled.
21147        if !ignore_disabled_input && !self.input_enabled {
21148            return None;
21149        }
21150
21151        let selection = self.selections.newest::<OffsetUtf16>(cx);
21152        let range = selection.range();
21153
21154        Some(UTF16Selection {
21155            range: range.start.0..range.end.0,
21156            reversed: selection.reversed,
21157        })
21158    }
21159
21160    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
21161        let snapshot = self.buffer.read(cx).read(cx);
21162        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
21163        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
21164    }
21165
21166    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21167        self.clear_highlights::<InputComposition>(cx);
21168        self.ime_transaction.take();
21169    }
21170
21171    fn replace_text_in_range(
21172        &mut self,
21173        range_utf16: Option<Range<usize>>,
21174        text: &str,
21175        window: &mut Window,
21176        cx: &mut Context<Self>,
21177    ) {
21178        if !self.input_enabled {
21179            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21180            return;
21181        }
21182
21183        self.transact(window, cx, |this, window, cx| {
21184            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
21185                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21186                Some(this.selection_replacement_ranges(range_utf16, cx))
21187            } else {
21188                this.marked_text_ranges(cx)
21189            };
21190
21191            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
21192                let newest_selection_id = this.selections.newest_anchor().id;
21193                this.selections
21194                    .all::<OffsetUtf16>(cx)
21195                    .iter()
21196                    .zip(ranges_to_replace.iter())
21197                    .find_map(|(selection, range)| {
21198                        if selection.id == newest_selection_id {
21199                            Some(
21200                                (range.start.0 as isize - selection.head().0 as isize)
21201                                    ..(range.end.0 as isize - selection.head().0 as isize),
21202                            )
21203                        } else {
21204                            None
21205                        }
21206                    })
21207            });
21208
21209            cx.emit(EditorEvent::InputHandled {
21210                utf16_range_to_replace: range_to_replace,
21211                text: text.into(),
21212            });
21213
21214            if let Some(new_selected_ranges) = new_selected_ranges {
21215                this.change_selections(None, window, cx, |selections| {
21216                    selections.select_ranges(new_selected_ranges)
21217                });
21218                this.backspace(&Default::default(), window, cx);
21219            }
21220
21221            this.handle_input(text, window, cx);
21222        });
21223
21224        if let Some(transaction) = self.ime_transaction {
21225            self.buffer.update(cx, |buffer, cx| {
21226                buffer.group_until_transaction(transaction, cx);
21227            });
21228        }
21229
21230        self.unmark_text(window, cx);
21231    }
21232
21233    fn replace_and_mark_text_in_range(
21234        &mut self,
21235        range_utf16: Option<Range<usize>>,
21236        text: &str,
21237        new_selected_range_utf16: Option<Range<usize>>,
21238        window: &mut Window,
21239        cx: &mut Context<Self>,
21240    ) {
21241        if !self.input_enabled {
21242            return;
21243        }
21244
21245        let transaction = self.transact(window, cx, |this, window, cx| {
21246            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
21247                let snapshot = this.buffer.read(cx).read(cx);
21248                if let Some(relative_range_utf16) = range_utf16.as_ref() {
21249                    for marked_range in &mut marked_ranges {
21250                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
21251                        marked_range.start.0 += relative_range_utf16.start;
21252                        marked_range.start =
21253                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
21254                        marked_range.end =
21255                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
21256                    }
21257                }
21258                Some(marked_ranges)
21259            } else if let Some(range_utf16) = range_utf16 {
21260                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21261                Some(this.selection_replacement_ranges(range_utf16, cx))
21262            } else {
21263                None
21264            };
21265
21266            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
21267                let newest_selection_id = this.selections.newest_anchor().id;
21268                this.selections
21269                    .all::<OffsetUtf16>(cx)
21270                    .iter()
21271                    .zip(ranges_to_replace.iter())
21272                    .find_map(|(selection, range)| {
21273                        if selection.id == newest_selection_id {
21274                            Some(
21275                                (range.start.0 as isize - selection.head().0 as isize)
21276                                    ..(range.end.0 as isize - selection.head().0 as isize),
21277                            )
21278                        } else {
21279                            None
21280                        }
21281                    })
21282            });
21283
21284            cx.emit(EditorEvent::InputHandled {
21285                utf16_range_to_replace: range_to_replace,
21286                text: text.into(),
21287            });
21288
21289            if let Some(ranges) = ranges_to_replace {
21290                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
21291            }
21292
21293            let marked_ranges = {
21294                let snapshot = this.buffer.read(cx).read(cx);
21295                this.selections
21296                    .disjoint_anchors()
21297                    .iter()
21298                    .map(|selection| {
21299                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
21300                    })
21301                    .collect::<Vec<_>>()
21302            };
21303
21304            if text.is_empty() {
21305                this.unmark_text(window, cx);
21306            } else {
21307                this.highlight_text::<InputComposition>(
21308                    marked_ranges.clone(),
21309                    HighlightStyle {
21310                        underline: Some(UnderlineStyle {
21311                            thickness: px(1.),
21312                            color: None,
21313                            wavy: false,
21314                        }),
21315                        ..Default::default()
21316                    },
21317                    cx,
21318                );
21319            }
21320
21321            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
21322            let use_autoclose = this.use_autoclose;
21323            let use_auto_surround = this.use_auto_surround;
21324            this.set_use_autoclose(false);
21325            this.set_use_auto_surround(false);
21326            this.handle_input(text, window, cx);
21327            this.set_use_autoclose(use_autoclose);
21328            this.set_use_auto_surround(use_auto_surround);
21329
21330            if let Some(new_selected_range) = new_selected_range_utf16 {
21331                let snapshot = this.buffer.read(cx).read(cx);
21332                let new_selected_ranges = marked_ranges
21333                    .into_iter()
21334                    .map(|marked_range| {
21335                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
21336                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
21337                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
21338                        snapshot.clip_offset_utf16(new_start, Bias::Left)
21339                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
21340                    })
21341                    .collect::<Vec<_>>();
21342
21343                drop(snapshot);
21344                this.change_selections(None, window, cx, |selections| {
21345                    selections.select_ranges(new_selected_ranges)
21346                });
21347            }
21348        });
21349
21350        self.ime_transaction = self.ime_transaction.or(transaction);
21351        if let Some(transaction) = self.ime_transaction {
21352            self.buffer.update(cx, |buffer, cx| {
21353                buffer.group_until_transaction(transaction, cx);
21354            });
21355        }
21356
21357        if self.text_highlights::<InputComposition>(cx).is_none() {
21358            self.ime_transaction.take();
21359        }
21360    }
21361
21362    fn bounds_for_range(
21363        &mut self,
21364        range_utf16: Range<usize>,
21365        element_bounds: gpui::Bounds<Pixels>,
21366        window: &mut Window,
21367        cx: &mut Context<Self>,
21368    ) -> Option<gpui::Bounds<Pixels>> {
21369        let text_layout_details = self.text_layout_details(window);
21370        let gpui::Size {
21371            width: em_width,
21372            height: line_height,
21373        } = self.character_size(window);
21374
21375        let snapshot = self.snapshot(window, cx);
21376        let scroll_position = snapshot.scroll_position();
21377        let scroll_left = scroll_position.x * em_width;
21378
21379        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
21380        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
21381            + self.gutter_dimensions.width
21382            + self.gutter_dimensions.margin;
21383        let y = line_height * (start.row().as_f32() - scroll_position.y);
21384
21385        Some(Bounds {
21386            origin: element_bounds.origin + point(x, y),
21387            size: size(em_width, line_height),
21388        })
21389    }
21390
21391    fn character_index_for_point(
21392        &mut self,
21393        point: gpui::Point<Pixels>,
21394        _window: &mut Window,
21395        _cx: &mut Context<Self>,
21396    ) -> Option<usize> {
21397        let position_map = self.last_position_map.as_ref()?;
21398        if !position_map.text_hitbox.contains(&point) {
21399            return None;
21400        }
21401        let display_point = position_map.point_for_position(point).previous_valid;
21402        let anchor = position_map
21403            .snapshot
21404            .display_point_to_anchor(display_point, Bias::Left);
21405        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
21406        Some(utf16_offset.0)
21407    }
21408}
21409
21410trait SelectionExt {
21411    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
21412    fn spanned_rows(
21413        &self,
21414        include_end_if_at_line_start: bool,
21415        map: &DisplaySnapshot,
21416    ) -> Range<MultiBufferRow>;
21417}
21418
21419impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
21420    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
21421        let start = self
21422            .start
21423            .to_point(&map.buffer_snapshot)
21424            .to_display_point(map);
21425        let end = self
21426            .end
21427            .to_point(&map.buffer_snapshot)
21428            .to_display_point(map);
21429        if self.reversed {
21430            end..start
21431        } else {
21432            start..end
21433        }
21434    }
21435
21436    fn spanned_rows(
21437        &self,
21438        include_end_if_at_line_start: bool,
21439        map: &DisplaySnapshot,
21440    ) -> Range<MultiBufferRow> {
21441        let start = self.start.to_point(&map.buffer_snapshot);
21442        let mut end = self.end.to_point(&map.buffer_snapshot);
21443        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
21444            end.row -= 1;
21445        }
21446
21447        let buffer_start = map.prev_line_boundary(start).0;
21448        let buffer_end = map.next_line_boundary(end).0;
21449        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
21450    }
21451}
21452
21453impl<T: InvalidationRegion> InvalidationStack<T> {
21454    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
21455    where
21456        S: Clone + ToOffset,
21457    {
21458        while let Some(region) = self.last() {
21459            let all_selections_inside_invalidation_ranges =
21460                if selections.len() == region.ranges().len() {
21461                    selections
21462                        .iter()
21463                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
21464                        .all(|(selection, invalidation_range)| {
21465                            let head = selection.head().to_offset(buffer);
21466                            invalidation_range.start <= head && invalidation_range.end >= head
21467                        })
21468                } else {
21469                    false
21470                };
21471
21472            if all_selections_inside_invalidation_ranges {
21473                break;
21474            } else {
21475                self.pop();
21476            }
21477        }
21478    }
21479}
21480
21481impl<T> Default for InvalidationStack<T> {
21482    fn default() -> Self {
21483        Self(Default::default())
21484    }
21485}
21486
21487impl<T> Deref for InvalidationStack<T> {
21488    type Target = Vec<T>;
21489
21490    fn deref(&self) -> &Self::Target {
21491        &self.0
21492    }
21493}
21494
21495impl<T> DerefMut for InvalidationStack<T> {
21496    fn deref_mut(&mut self) -> &mut Self::Target {
21497        &mut self.0
21498    }
21499}
21500
21501impl InvalidationRegion for SnippetState {
21502    fn ranges(&self) -> &[Range<Anchor>] {
21503        &self.ranges[self.active_index]
21504    }
21505}
21506
21507fn inline_completion_edit_text(
21508    current_snapshot: &BufferSnapshot,
21509    edits: &[(Range<Anchor>, String)],
21510    edit_preview: &EditPreview,
21511    include_deletions: bool,
21512    cx: &App,
21513) -> HighlightedText {
21514    let edits = edits
21515        .iter()
21516        .map(|(anchor, text)| {
21517            (
21518                anchor.start.text_anchor..anchor.end.text_anchor,
21519                text.clone(),
21520            )
21521        })
21522        .collect::<Vec<_>>();
21523
21524    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21525}
21526
21527pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21528    match severity {
21529        lsp::DiagnosticSeverity::ERROR => colors.error,
21530        lsp::DiagnosticSeverity::WARNING => colors.warning,
21531        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21532        lsp::DiagnosticSeverity::HINT => colors.info,
21533        _ => colors.ignored,
21534    }
21535}
21536
21537pub fn styled_runs_for_code_label<'a>(
21538    label: &'a CodeLabel,
21539    syntax_theme: &'a theme::SyntaxTheme,
21540) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21541    let fade_out = HighlightStyle {
21542        fade_out: Some(0.35),
21543        ..Default::default()
21544    };
21545
21546    let mut prev_end = label.filter_range.end;
21547    label
21548        .runs
21549        .iter()
21550        .enumerate()
21551        .flat_map(move |(ix, (range, highlight_id))| {
21552            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21553                style
21554            } else {
21555                return Default::default();
21556            };
21557            let mut muted_style = style;
21558            muted_style.highlight(fade_out);
21559
21560            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21561            if range.start >= label.filter_range.end {
21562                if range.start > prev_end {
21563                    runs.push((prev_end..range.start, fade_out));
21564                }
21565                runs.push((range.clone(), muted_style));
21566            } else if range.end <= label.filter_range.end {
21567                runs.push((range.clone(), style));
21568            } else {
21569                runs.push((range.start..label.filter_range.end, style));
21570                runs.push((label.filter_range.end..range.end, muted_style));
21571            }
21572            prev_end = cmp::max(prev_end, range.end);
21573
21574            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21575                runs.push((prev_end..label.text.len(), fade_out));
21576            }
21577
21578            runs
21579        })
21580}
21581
21582pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21583    let mut prev_index = 0;
21584    let mut prev_codepoint: Option<char> = None;
21585    text.char_indices()
21586        .chain([(text.len(), '\0')])
21587        .filter_map(move |(index, codepoint)| {
21588            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21589            let is_boundary = index == text.len()
21590                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21591                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21592            if is_boundary {
21593                let chunk = &text[prev_index..index];
21594                prev_index = index;
21595                Some(chunk)
21596            } else {
21597                None
21598            }
21599        })
21600}
21601
21602pub trait RangeToAnchorExt: Sized {
21603    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21604
21605    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21606        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21607        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21608    }
21609}
21610
21611impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21612    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21613        let start_offset = self.start.to_offset(snapshot);
21614        let end_offset = self.end.to_offset(snapshot);
21615        if start_offset == end_offset {
21616            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21617        } else {
21618            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21619        }
21620    }
21621}
21622
21623pub trait RowExt {
21624    fn as_f32(&self) -> f32;
21625
21626    fn next_row(&self) -> Self;
21627
21628    fn previous_row(&self) -> Self;
21629
21630    fn minus(&self, other: Self) -> u32;
21631}
21632
21633impl RowExt for DisplayRow {
21634    fn as_f32(&self) -> f32 {
21635        self.0 as f32
21636    }
21637
21638    fn next_row(&self) -> Self {
21639        Self(self.0 + 1)
21640    }
21641
21642    fn previous_row(&self) -> Self {
21643        Self(self.0.saturating_sub(1))
21644    }
21645
21646    fn minus(&self, other: Self) -> u32 {
21647        self.0 - other.0
21648    }
21649}
21650
21651impl RowExt for MultiBufferRow {
21652    fn as_f32(&self) -> f32 {
21653        self.0 as f32
21654    }
21655
21656    fn next_row(&self) -> Self {
21657        Self(self.0 + 1)
21658    }
21659
21660    fn previous_row(&self) -> Self {
21661        Self(self.0.saturating_sub(1))
21662    }
21663
21664    fn minus(&self, other: Self) -> u32 {
21665        self.0 - other.0
21666    }
21667}
21668
21669trait RowRangeExt {
21670    type Row;
21671
21672    fn len(&self) -> usize;
21673
21674    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21675}
21676
21677impl RowRangeExt for Range<MultiBufferRow> {
21678    type Row = MultiBufferRow;
21679
21680    fn len(&self) -> usize {
21681        (self.end.0 - self.start.0) as usize
21682    }
21683
21684    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21685        (self.start.0..self.end.0).map(MultiBufferRow)
21686    }
21687}
21688
21689impl RowRangeExt for Range<DisplayRow> {
21690    type Row = DisplayRow;
21691
21692    fn len(&self) -> usize {
21693        (self.end.0 - self.start.0) as usize
21694    }
21695
21696    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21697        (self.start.0..self.end.0).map(DisplayRow)
21698    }
21699}
21700
21701/// If select range has more than one line, we
21702/// just point the cursor to range.start.
21703fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21704    if range.start.row == range.end.row {
21705        range
21706    } else {
21707        range.start..range.start
21708    }
21709}
21710pub struct KillRing(ClipboardItem);
21711impl Global for KillRing {}
21712
21713const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21714
21715enum BreakpointPromptEditAction {
21716    Log,
21717    Condition,
21718    HitCondition,
21719}
21720
21721struct BreakpointPromptEditor {
21722    pub(crate) prompt: Entity<Editor>,
21723    editor: WeakEntity<Editor>,
21724    breakpoint_anchor: Anchor,
21725    breakpoint: Breakpoint,
21726    edit_action: BreakpointPromptEditAction,
21727    block_ids: HashSet<CustomBlockId>,
21728    editor_margins: Arc<Mutex<EditorMargins>>,
21729    _subscriptions: Vec<Subscription>,
21730}
21731
21732impl BreakpointPromptEditor {
21733    const MAX_LINES: u8 = 4;
21734
21735    fn new(
21736        editor: WeakEntity<Editor>,
21737        breakpoint_anchor: Anchor,
21738        breakpoint: Breakpoint,
21739        edit_action: BreakpointPromptEditAction,
21740        window: &mut Window,
21741        cx: &mut Context<Self>,
21742    ) -> Self {
21743        let base_text = match edit_action {
21744            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21745            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21746            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21747        }
21748        .map(|msg| msg.to_string())
21749        .unwrap_or_default();
21750
21751        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21752        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21753
21754        let prompt = cx.new(|cx| {
21755            let mut prompt = Editor::new(
21756                EditorMode::AutoHeight {
21757                    max_lines: Self::MAX_LINES as usize,
21758                },
21759                buffer,
21760                None,
21761                window,
21762                cx,
21763            );
21764            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21765            prompt.set_show_cursor_when_unfocused(false, cx);
21766            prompt.set_placeholder_text(
21767                match edit_action {
21768                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21769                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21770                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21771                },
21772                cx,
21773            );
21774
21775            prompt
21776        });
21777
21778        Self {
21779            prompt,
21780            editor,
21781            breakpoint_anchor,
21782            breakpoint,
21783            edit_action,
21784            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21785            block_ids: Default::default(),
21786            _subscriptions: vec![],
21787        }
21788    }
21789
21790    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21791        self.block_ids.extend(block_ids)
21792    }
21793
21794    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21795        if let Some(editor) = self.editor.upgrade() {
21796            let message = self
21797                .prompt
21798                .read(cx)
21799                .buffer
21800                .read(cx)
21801                .as_singleton()
21802                .expect("A multi buffer in breakpoint prompt isn't possible")
21803                .read(cx)
21804                .as_rope()
21805                .to_string();
21806
21807            editor.update(cx, |editor, cx| {
21808                editor.edit_breakpoint_at_anchor(
21809                    self.breakpoint_anchor,
21810                    self.breakpoint.clone(),
21811                    match self.edit_action {
21812                        BreakpointPromptEditAction::Log => {
21813                            BreakpointEditAction::EditLogMessage(message.into())
21814                        }
21815                        BreakpointPromptEditAction::Condition => {
21816                            BreakpointEditAction::EditCondition(message.into())
21817                        }
21818                        BreakpointPromptEditAction::HitCondition => {
21819                            BreakpointEditAction::EditHitCondition(message.into())
21820                        }
21821                    },
21822                    cx,
21823                );
21824
21825                editor.remove_blocks(self.block_ids.clone(), None, cx);
21826                cx.focus_self(window);
21827            });
21828        }
21829    }
21830
21831    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21832        self.editor
21833            .update(cx, |editor, cx| {
21834                editor.remove_blocks(self.block_ids.clone(), None, cx);
21835                window.focus(&editor.focus_handle);
21836            })
21837            .log_err();
21838    }
21839
21840    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
21841        let settings = ThemeSettings::get_global(cx);
21842        let text_style = TextStyle {
21843            color: if self.prompt.read(cx).read_only(cx) {
21844                cx.theme().colors().text_disabled
21845            } else {
21846                cx.theme().colors().text
21847            },
21848            font_family: settings.buffer_font.family.clone(),
21849            font_fallbacks: settings.buffer_font.fallbacks.clone(),
21850            font_size: settings.buffer_font_size(cx).into(),
21851            font_weight: settings.buffer_font.weight,
21852            line_height: relative(settings.buffer_line_height.value()),
21853            ..Default::default()
21854        };
21855        EditorElement::new(
21856            &self.prompt,
21857            EditorStyle {
21858                background: cx.theme().colors().editor_background,
21859                local_player: cx.theme().players().local(),
21860                text: text_style,
21861                ..Default::default()
21862            },
21863        )
21864    }
21865}
21866
21867impl Render for BreakpointPromptEditor {
21868    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21869        let editor_margins = *self.editor_margins.lock();
21870        let gutter_dimensions = editor_margins.gutter;
21871        h_flex()
21872            .key_context("Editor")
21873            .bg(cx.theme().colors().editor_background)
21874            .border_y_1()
21875            .border_color(cx.theme().status().info_border)
21876            .size_full()
21877            .py(window.line_height() / 2.5)
21878            .on_action(cx.listener(Self::confirm))
21879            .on_action(cx.listener(Self::cancel))
21880            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
21881            .child(div().flex_1().child(self.render_prompt_editor(cx)))
21882    }
21883}
21884
21885impl Focusable for BreakpointPromptEditor {
21886    fn focus_handle(&self, cx: &App) -> FocusHandle {
21887        self.prompt.focus_handle(cx)
21888    }
21889}
21890
21891fn all_edits_insertions_or_deletions(
21892    edits: &Vec<(Range<Anchor>, String)>,
21893    snapshot: &MultiBufferSnapshot,
21894) -> bool {
21895    let mut all_insertions = true;
21896    let mut all_deletions = true;
21897
21898    for (range, new_text) in edits.iter() {
21899        let range_is_empty = range.to_offset(&snapshot).is_empty();
21900        let text_is_empty = new_text.is_empty();
21901
21902        if range_is_empty != text_is_empty {
21903            if range_is_empty {
21904                all_deletions = false;
21905            } else {
21906                all_insertions = false;
21907            }
21908        } else {
21909            return false;
21910        }
21911
21912        if !all_insertions && !all_deletions {
21913            return false;
21914        }
21915    }
21916    all_insertions || all_deletions
21917}
21918
21919struct MissingEditPredictionKeybindingTooltip;
21920
21921impl Render for MissingEditPredictionKeybindingTooltip {
21922    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21923        ui::tooltip_container(window, cx, |container, _, cx| {
21924            container
21925                .flex_shrink_0()
21926                .max_w_80()
21927                .min_h(rems_from_px(124.))
21928                .justify_between()
21929                .child(
21930                    v_flex()
21931                        .flex_1()
21932                        .text_ui_sm(cx)
21933                        .child(Label::new("Conflict with Accept Keybinding"))
21934                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
21935                )
21936                .child(
21937                    h_flex()
21938                        .pb_1()
21939                        .gap_1()
21940                        .items_end()
21941                        .w_full()
21942                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
21943                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
21944                        }))
21945                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
21946                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
21947                        })),
21948                )
21949        })
21950    }
21951}
21952
21953#[derive(Debug, Clone, Copy, PartialEq)]
21954pub struct LineHighlight {
21955    pub background: Background,
21956    pub border: Option<gpui::Hsla>,
21957    pub include_gutter: bool,
21958    pub type_id: Option<TypeId>,
21959}
21960
21961fn render_diff_hunk_controls(
21962    row: u32,
21963    status: &DiffHunkStatus,
21964    hunk_range: Range<Anchor>,
21965    is_created_file: bool,
21966    line_height: Pixels,
21967    editor: &Entity<Editor>,
21968    _window: &mut Window,
21969    cx: &mut App,
21970) -> AnyElement {
21971    h_flex()
21972        .h(line_height)
21973        .mr_1()
21974        .gap_1()
21975        .px_0p5()
21976        .pb_1()
21977        .border_x_1()
21978        .border_b_1()
21979        .border_color(cx.theme().colors().border_variant)
21980        .rounded_b_lg()
21981        .bg(cx.theme().colors().editor_background)
21982        .gap_1()
21983        .block_mouse_except_scroll()
21984        .shadow_md()
21985        .child(if status.has_secondary_hunk() {
21986            Button::new(("stage", row as u64), "Stage")
21987                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21988                .tooltip({
21989                    let focus_handle = editor.focus_handle(cx);
21990                    move |window, cx| {
21991                        Tooltip::for_action_in(
21992                            "Stage Hunk",
21993                            &::git::ToggleStaged,
21994                            &focus_handle,
21995                            window,
21996                            cx,
21997                        )
21998                    }
21999                })
22000                .on_click({
22001                    let editor = editor.clone();
22002                    move |_event, _window, cx| {
22003                        editor.update(cx, |editor, cx| {
22004                            editor.stage_or_unstage_diff_hunks(
22005                                true,
22006                                vec![hunk_range.start..hunk_range.start],
22007                                cx,
22008                            );
22009                        });
22010                    }
22011                })
22012        } else {
22013            Button::new(("unstage", row as u64), "Unstage")
22014                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22015                .tooltip({
22016                    let focus_handle = editor.focus_handle(cx);
22017                    move |window, cx| {
22018                        Tooltip::for_action_in(
22019                            "Unstage Hunk",
22020                            &::git::ToggleStaged,
22021                            &focus_handle,
22022                            window,
22023                            cx,
22024                        )
22025                    }
22026                })
22027                .on_click({
22028                    let editor = editor.clone();
22029                    move |_event, _window, cx| {
22030                        editor.update(cx, |editor, cx| {
22031                            editor.stage_or_unstage_diff_hunks(
22032                                false,
22033                                vec![hunk_range.start..hunk_range.start],
22034                                cx,
22035                            );
22036                        });
22037                    }
22038                })
22039        })
22040        .child(
22041            Button::new(("restore", row as u64), "Restore")
22042                .tooltip({
22043                    let focus_handle = editor.focus_handle(cx);
22044                    move |window, cx| {
22045                        Tooltip::for_action_in(
22046                            "Restore Hunk",
22047                            &::git::Restore,
22048                            &focus_handle,
22049                            window,
22050                            cx,
22051                        )
22052                    }
22053                })
22054                .on_click({
22055                    let editor = editor.clone();
22056                    move |_event, window, cx| {
22057                        editor.update(cx, |editor, cx| {
22058                            let snapshot = editor.snapshot(window, cx);
22059                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22060                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22061                        });
22062                    }
22063                })
22064                .disabled(is_created_file),
22065        )
22066        .when(
22067            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22068            |el| {
22069                el.child(
22070                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22071                        .shape(IconButtonShape::Square)
22072                        .icon_size(IconSize::Small)
22073                        // .disabled(!has_multiple_hunks)
22074                        .tooltip({
22075                            let focus_handle = editor.focus_handle(cx);
22076                            move |window, cx| {
22077                                Tooltip::for_action_in(
22078                                    "Next Hunk",
22079                                    &GoToHunk,
22080                                    &focus_handle,
22081                                    window,
22082                                    cx,
22083                                )
22084                            }
22085                        })
22086                        .on_click({
22087                            let editor = editor.clone();
22088                            move |_event, window, cx| {
22089                                editor.update(cx, |editor, cx| {
22090                                    let snapshot = editor.snapshot(window, cx);
22091                                    let position =
22092                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22093                                    editor.go_to_hunk_before_or_after_position(
22094                                        &snapshot,
22095                                        position,
22096                                        Direction::Next,
22097                                        window,
22098                                        cx,
22099                                    );
22100                                    editor.expand_selected_diff_hunks(cx);
22101                                });
22102                            }
22103                        }),
22104                )
22105                .child(
22106                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
22107                        .shape(IconButtonShape::Square)
22108                        .icon_size(IconSize::Small)
22109                        // .disabled(!has_multiple_hunks)
22110                        .tooltip({
22111                            let focus_handle = editor.focus_handle(cx);
22112                            move |window, cx| {
22113                                Tooltip::for_action_in(
22114                                    "Previous Hunk",
22115                                    &GoToPreviousHunk,
22116                                    &focus_handle,
22117                                    window,
22118                                    cx,
22119                                )
22120                            }
22121                        })
22122                        .on_click({
22123                            let editor = editor.clone();
22124                            move |_event, window, cx| {
22125                                editor.update(cx, |editor, cx| {
22126                                    let snapshot = editor.snapshot(window, cx);
22127                                    let point =
22128                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
22129                                    editor.go_to_hunk_before_or_after_position(
22130                                        &snapshot,
22131                                        point,
22132                                        Direction::Prev,
22133                                        window,
22134                                        cx,
22135                                    );
22136                                    editor.expand_selected_diff_hunks(cx);
22137                                });
22138                            }
22139                        }),
22140                )
22141            },
22142        )
22143        .into_any_element()
22144}