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    autoclose_regions: Vec<AutocloseRegion>,
  940    snippet_stack: InvalidationStack<SnippetState>,
  941    select_syntax_node_history: SelectSyntaxNodeHistory,
  942    ime_transaction: Option<TransactionId>,
  943    pub diagnostics_max_severity: DiagnosticSeverity,
  944    active_diagnostics: ActiveDiagnostic,
  945    show_inline_diagnostics: bool,
  946    inline_diagnostics_update: Task<()>,
  947    inline_diagnostics_enabled: bool,
  948    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  949    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  950    hard_wrap: Option<usize>,
  951
  952    // TODO: make this a access method
  953    pub project: Option<Entity<Project>>,
  954    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  955    completion_provider: Option<Rc<dyn CompletionProvider>>,
  956    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  957    blink_manager: Entity<BlinkManager>,
  958    show_cursor_names: bool,
  959    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  960    pub show_local_selections: bool,
  961    mode: EditorMode,
  962    show_breadcrumbs: bool,
  963    show_gutter: bool,
  964    show_scrollbars: ScrollbarAxes,
  965    minimap_visibility: MinimapVisibility,
  966    offset_content: bool,
  967    disable_expand_excerpt_buttons: bool,
  968    show_line_numbers: Option<bool>,
  969    use_relative_line_numbers: Option<bool>,
  970    show_git_diff_gutter: Option<bool>,
  971    show_code_actions: Option<bool>,
  972    show_runnables: Option<bool>,
  973    show_breakpoints: Option<bool>,
  974    show_wrap_guides: Option<bool>,
  975    show_indent_guides: Option<bool>,
  976    placeholder_text: Option<Arc<str>>,
  977    highlight_order: usize,
  978    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  979    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  980    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  981    scrollbar_marker_state: ScrollbarMarkerState,
  982    active_indent_guides_state: ActiveIndentGuidesState,
  983    nav_history: Option<ItemNavHistory>,
  984    context_menu: RefCell<Option<CodeContextMenu>>,
  985    context_menu_options: Option<ContextMenuOptions>,
  986    mouse_context_menu: Option<MouseContextMenu>,
  987    completion_tasks: Vec<(CompletionId, Task<Option<()>>)>,
  988    inline_blame_popover: Option<InlineBlamePopover>,
  989    signature_help_state: SignatureHelpState,
  990    auto_signature_help: Option<bool>,
  991    find_all_references_task_sources: Vec<Anchor>,
  992    next_completion_id: CompletionId,
  993    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
  994    code_actions_task: Option<Task<Result<()>>>,
  995    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  996    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
  997    document_highlights_task: Option<Task<()>>,
  998    linked_editing_range_task: Option<Task<Option<()>>>,
  999    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1000    pending_rename: Option<RenameState>,
 1001    searchable: bool,
 1002    cursor_shape: CursorShape,
 1003    current_line_highlight: Option<CurrentLineHighlight>,
 1004    collapse_matches: bool,
 1005    autoindent_mode: Option<AutoindentMode>,
 1006    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1007    input_enabled: bool,
 1008    use_modal_editing: bool,
 1009    read_only: bool,
 1010    leader_id: Option<CollaboratorId>,
 1011    remote_id: Option<ViewId>,
 1012    pub hover_state: HoverState,
 1013    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1014    gutter_hovered: bool,
 1015    hovered_link_state: Option<HoveredLinkState>,
 1016    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1017    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1018    active_inline_completion: Option<InlineCompletionState>,
 1019    /// Used to prevent flickering as the user types while the menu is open
 1020    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1021    edit_prediction_settings: EditPredictionSettings,
 1022    inline_completions_hidden_for_vim_mode: bool,
 1023    show_inline_completions_override: Option<bool>,
 1024    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1025    edit_prediction_preview: EditPredictionPreview,
 1026    edit_prediction_indent_conflict: bool,
 1027    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1028    inlay_hint_cache: InlayHintCache,
 1029    next_inlay_id: usize,
 1030    _subscriptions: Vec<Subscription>,
 1031    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1032    gutter_dimensions: GutterDimensions,
 1033    style: Option<EditorStyle>,
 1034    text_style_refinement: Option<TextStyleRefinement>,
 1035    next_editor_action_id: EditorActionId,
 1036    editor_actions:
 1037        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
 1038    use_autoclose: bool,
 1039    use_auto_surround: bool,
 1040    auto_replace_emoji_shortcode: bool,
 1041    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1042    show_git_blame_gutter: bool,
 1043    show_git_blame_inline: bool,
 1044    show_git_blame_inline_delay_task: Option<Task<()>>,
 1045    git_blame_inline_enabled: bool,
 1046    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1047    serialize_dirty_buffers: bool,
 1048    show_selection_menu: Option<bool>,
 1049    blame: Option<Entity<GitBlame>>,
 1050    blame_subscription: Option<Subscription>,
 1051    custom_context_menu: Option<
 1052        Box<
 1053            dyn 'static
 1054                + Fn(
 1055                    &mut Self,
 1056                    DisplayPoint,
 1057                    &mut Window,
 1058                    &mut Context<Self>,
 1059                ) -> Option<Entity<ui::ContextMenu>>,
 1060        >,
 1061    >,
 1062    last_bounds: Option<Bounds<Pixels>>,
 1063    last_position_map: Option<Rc<PositionMap>>,
 1064    expect_bounds_change: Option<Bounds<Pixels>>,
 1065    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1066    tasks_update_task: Option<Task<()>>,
 1067    breakpoint_store: Option<Entity<BreakpointStore>>,
 1068    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1069    in_project_search: bool,
 1070    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1071    breadcrumb_header: Option<String>,
 1072    focused_block: Option<FocusedBlock>,
 1073    next_scroll_position: NextScrollCursorCenterTopBottom,
 1074    addons: HashMap<TypeId, Box<dyn Addon>>,
 1075    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1076    load_diff_task: Option<Shared<Task<()>>>,
 1077    /// Whether we are temporarily displaying a diff other than git's
 1078    temporary_diff_override: bool,
 1079    selection_mark_mode: bool,
 1080    toggle_fold_multiple_buffers: Task<()>,
 1081    _scroll_cursor_center_top_bottom_task: Task<()>,
 1082    serialize_selections: Task<()>,
 1083    serialize_folds: Task<()>,
 1084    mouse_cursor_hidden: bool,
 1085    minimap: Option<Entity<Self>>,
 1086    hide_mouse_mode: HideMouseMode,
 1087    pub change_list: ChangeList,
 1088    inline_value_cache: InlineValueCache,
 1089}
 1090
 1091#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1092enum NextScrollCursorCenterTopBottom {
 1093    #[default]
 1094    Center,
 1095    Top,
 1096    Bottom,
 1097}
 1098
 1099impl NextScrollCursorCenterTopBottom {
 1100    fn next(&self) -> Self {
 1101        match self {
 1102            Self::Center => Self::Top,
 1103            Self::Top => Self::Bottom,
 1104            Self::Bottom => Self::Center,
 1105        }
 1106    }
 1107}
 1108
 1109#[derive(Clone)]
 1110pub struct EditorSnapshot {
 1111    pub mode: EditorMode,
 1112    show_gutter: bool,
 1113    show_line_numbers: Option<bool>,
 1114    show_git_diff_gutter: Option<bool>,
 1115    show_code_actions: Option<bool>,
 1116    show_runnables: Option<bool>,
 1117    show_breakpoints: Option<bool>,
 1118    git_blame_gutter_max_author_length: Option<usize>,
 1119    pub display_snapshot: DisplaySnapshot,
 1120    pub placeholder_text: Option<Arc<str>>,
 1121    is_focused: bool,
 1122    scroll_anchor: ScrollAnchor,
 1123    ongoing_scroll: OngoingScroll,
 1124    current_line_highlight: CurrentLineHighlight,
 1125    gutter_hovered: bool,
 1126}
 1127
 1128#[derive(Default, Debug, Clone, Copy)]
 1129pub struct GutterDimensions {
 1130    pub left_padding: Pixels,
 1131    pub right_padding: Pixels,
 1132    pub width: Pixels,
 1133    pub margin: Pixels,
 1134    pub git_blame_entries_width: Option<Pixels>,
 1135}
 1136
 1137impl GutterDimensions {
 1138    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1139        Self {
 1140            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1141            ..Default::default()
 1142        }
 1143    }
 1144
 1145    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1146        -cx.text_system().descent(font_id, font_size)
 1147    }
 1148    /// The full width of the space taken up by the gutter.
 1149    pub fn full_width(&self) -> Pixels {
 1150        self.margin + self.width
 1151    }
 1152
 1153    /// The width of the space reserved for the fold indicators,
 1154    /// use alongside 'justify_end' and `gutter_width` to
 1155    /// right align content with the line numbers
 1156    pub fn fold_area_width(&self) -> Pixels {
 1157        self.margin + self.right_padding
 1158    }
 1159}
 1160
 1161#[derive(Debug)]
 1162pub struct RemoteSelection {
 1163    pub replica_id: ReplicaId,
 1164    pub selection: Selection<Anchor>,
 1165    pub cursor_shape: CursorShape,
 1166    pub collaborator_id: CollaboratorId,
 1167    pub line_mode: bool,
 1168    pub user_name: Option<SharedString>,
 1169    pub color: PlayerColor,
 1170}
 1171
 1172#[derive(Clone, Debug)]
 1173struct SelectionHistoryEntry {
 1174    selections: Arc<[Selection<Anchor>]>,
 1175    select_next_state: Option<SelectNextState>,
 1176    select_prev_state: Option<SelectNextState>,
 1177    add_selections_state: Option<AddSelectionsState>,
 1178}
 1179
 1180enum SelectionHistoryMode {
 1181    Normal,
 1182    Undoing,
 1183    Redoing,
 1184}
 1185
 1186#[derive(Clone, PartialEq, Eq, Hash)]
 1187struct HoveredCursor {
 1188    replica_id: u16,
 1189    selection_id: usize,
 1190}
 1191
 1192impl Default for SelectionHistoryMode {
 1193    fn default() -> Self {
 1194        Self::Normal
 1195    }
 1196}
 1197
 1198#[derive(Default)]
 1199struct SelectionHistory {
 1200    #[allow(clippy::type_complexity)]
 1201    selections_by_transaction:
 1202        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1203    mode: SelectionHistoryMode,
 1204    undo_stack: VecDeque<SelectionHistoryEntry>,
 1205    redo_stack: VecDeque<SelectionHistoryEntry>,
 1206}
 1207
 1208impl SelectionHistory {
 1209    fn insert_transaction(
 1210        &mut self,
 1211        transaction_id: TransactionId,
 1212        selections: Arc<[Selection<Anchor>]>,
 1213    ) {
 1214        self.selections_by_transaction
 1215            .insert(transaction_id, (selections, None));
 1216    }
 1217
 1218    #[allow(clippy::type_complexity)]
 1219    fn transaction(
 1220        &self,
 1221        transaction_id: TransactionId,
 1222    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1223        self.selections_by_transaction.get(&transaction_id)
 1224    }
 1225
 1226    #[allow(clippy::type_complexity)]
 1227    fn transaction_mut(
 1228        &mut self,
 1229        transaction_id: TransactionId,
 1230    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1231        self.selections_by_transaction.get_mut(&transaction_id)
 1232    }
 1233
 1234    fn push(&mut self, entry: SelectionHistoryEntry) {
 1235        if !entry.selections.is_empty() {
 1236            match self.mode {
 1237                SelectionHistoryMode::Normal => {
 1238                    self.push_undo(entry);
 1239                    self.redo_stack.clear();
 1240                }
 1241                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1242                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1243            }
 1244        }
 1245    }
 1246
 1247    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1248        if self
 1249            .undo_stack
 1250            .back()
 1251            .map_or(true, |e| e.selections != entry.selections)
 1252        {
 1253            self.undo_stack.push_back(entry);
 1254            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1255                self.undo_stack.pop_front();
 1256            }
 1257        }
 1258    }
 1259
 1260    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1261        if self
 1262            .redo_stack
 1263            .back()
 1264            .map_or(true, |e| e.selections != entry.selections)
 1265        {
 1266            self.redo_stack.push_back(entry);
 1267            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1268                self.redo_stack.pop_front();
 1269            }
 1270        }
 1271    }
 1272}
 1273
 1274#[derive(Clone, Copy)]
 1275pub struct RowHighlightOptions {
 1276    pub autoscroll: bool,
 1277    pub include_gutter: bool,
 1278}
 1279
 1280impl Default for RowHighlightOptions {
 1281    fn default() -> Self {
 1282        Self {
 1283            autoscroll: Default::default(),
 1284            include_gutter: true,
 1285        }
 1286    }
 1287}
 1288
 1289struct RowHighlight {
 1290    index: usize,
 1291    range: Range<Anchor>,
 1292    color: Hsla,
 1293    options: RowHighlightOptions,
 1294    type_id: TypeId,
 1295}
 1296
 1297#[derive(Clone, Debug)]
 1298struct AddSelectionsState {
 1299    above: bool,
 1300    stack: Vec<usize>,
 1301}
 1302
 1303#[derive(Clone)]
 1304struct SelectNextState {
 1305    query: AhoCorasick,
 1306    wordwise: bool,
 1307    done: bool,
 1308}
 1309
 1310impl std::fmt::Debug for SelectNextState {
 1311    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1312        f.debug_struct(std::any::type_name::<Self>())
 1313            .field("wordwise", &self.wordwise)
 1314            .field("done", &self.done)
 1315            .finish()
 1316    }
 1317}
 1318
 1319#[derive(Debug)]
 1320struct AutocloseRegion {
 1321    selection_id: usize,
 1322    range: Range<Anchor>,
 1323    pair: BracketPair,
 1324}
 1325
 1326#[derive(Debug)]
 1327struct SnippetState {
 1328    ranges: Vec<Vec<Range<Anchor>>>,
 1329    active_index: usize,
 1330    choices: Vec<Option<Vec<String>>>,
 1331}
 1332
 1333#[doc(hidden)]
 1334pub struct RenameState {
 1335    pub range: Range<Anchor>,
 1336    pub old_name: Arc<str>,
 1337    pub editor: Entity<Editor>,
 1338    block_id: CustomBlockId,
 1339}
 1340
 1341struct InvalidationStack<T>(Vec<T>);
 1342
 1343struct RegisteredInlineCompletionProvider {
 1344    provider: Arc<dyn InlineCompletionProviderHandle>,
 1345    _subscription: Subscription,
 1346}
 1347
 1348#[derive(Debug, PartialEq, Eq)]
 1349pub struct ActiveDiagnosticGroup {
 1350    pub active_range: Range<Anchor>,
 1351    pub active_message: String,
 1352    pub group_id: usize,
 1353    pub blocks: HashSet<CustomBlockId>,
 1354}
 1355
 1356#[derive(Debug, PartialEq, Eq)]
 1357
 1358pub(crate) enum ActiveDiagnostic {
 1359    None,
 1360    All,
 1361    Group(ActiveDiagnosticGroup),
 1362}
 1363
 1364#[derive(Serialize, Deserialize, Clone, Debug)]
 1365pub struct ClipboardSelection {
 1366    /// The number of bytes in this selection.
 1367    pub len: usize,
 1368    /// Whether this was a full-line selection.
 1369    pub is_entire_line: bool,
 1370    /// The indentation of the first line when this content was originally copied.
 1371    pub first_line_indent: u32,
 1372}
 1373
 1374// selections, scroll behavior, was newest selection reversed
 1375type SelectSyntaxNodeHistoryState = (
 1376    Box<[Selection<usize>]>,
 1377    SelectSyntaxNodeScrollBehavior,
 1378    bool,
 1379);
 1380
 1381#[derive(Default)]
 1382struct SelectSyntaxNodeHistory {
 1383    stack: Vec<SelectSyntaxNodeHistoryState>,
 1384    // disable temporarily to allow changing selections without losing the stack
 1385    pub disable_clearing: bool,
 1386}
 1387
 1388impl SelectSyntaxNodeHistory {
 1389    pub fn try_clear(&mut self) {
 1390        if !self.disable_clearing {
 1391            self.stack.clear();
 1392        }
 1393    }
 1394
 1395    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1396        self.stack.push(selection);
 1397    }
 1398
 1399    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1400        self.stack.pop()
 1401    }
 1402}
 1403
 1404enum SelectSyntaxNodeScrollBehavior {
 1405    CursorTop,
 1406    FitSelection,
 1407    CursorBottom,
 1408}
 1409
 1410#[derive(Debug)]
 1411pub(crate) struct NavigationData {
 1412    cursor_anchor: Anchor,
 1413    cursor_position: Point,
 1414    scroll_anchor: ScrollAnchor,
 1415    scroll_top_row: u32,
 1416}
 1417
 1418#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1419pub enum GotoDefinitionKind {
 1420    Symbol,
 1421    Declaration,
 1422    Type,
 1423    Implementation,
 1424}
 1425
 1426#[derive(Debug, Clone)]
 1427enum InlayHintRefreshReason {
 1428    ModifiersChanged(bool),
 1429    Toggle(bool),
 1430    SettingsChange(InlayHintSettings),
 1431    NewLinesShown,
 1432    BufferEdited(HashSet<Arc<Language>>),
 1433    RefreshRequested,
 1434    ExcerptsRemoved(Vec<ExcerptId>),
 1435}
 1436
 1437impl InlayHintRefreshReason {
 1438    fn description(&self) -> &'static str {
 1439        match self {
 1440            Self::ModifiersChanged(_) => "modifiers changed",
 1441            Self::Toggle(_) => "toggle",
 1442            Self::SettingsChange(_) => "settings change",
 1443            Self::NewLinesShown => "new lines shown",
 1444            Self::BufferEdited(_) => "buffer edited",
 1445            Self::RefreshRequested => "refresh requested",
 1446            Self::ExcerptsRemoved(_) => "excerpts removed",
 1447        }
 1448    }
 1449}
 1450
 1451pub enum FormatTarget {
 1452    Buffers,
 1453    Ranges(Vec<Range<MultiBufferPoint>>),
 1454}
 1455
 1456pub(crate) struct FocusedBlock {
 1457    id: BlockId,
 1458    focus_handle: WeakFocusHandle,
 1459}
 1460
 1461#[derive(Clone)]
 1462enum JumpData {
 1463    MultiBufferRow {
 1464        row: MultiBufferRow,
 1465        line_offset_from_top: u32,
 1466    },
 1467    MultiBufferPoint {
 1468        excerpt_id: ExcerptId,
 1469        position: Point,
 1470        anchor: text::Anchor,
 1471        line_offset_from_top: u32,
 1472    },
 1473}
 1474
 1475pub enum MultibufferSelectionMode {
 1476    First,
 1477    All,
 1478}
 1479
 1480#[derive(Clone, Copy, Debug, Default)]
 1481pub struct RewrapOptions {
 1482    pub override_language_settings: bool,
 1483    pub preserve_existing_whitespace: bool,
 1484}
 1485
 1486impl Editor {
 1487    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1488        let buffer = cx.new(|cx| Buffer::local("", cx));
 1489        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1490        Self::new(
 1491            EditorMode::SingleLine { auto_width: false },
 1492            buffer,
 1493            None,
 1494            window,
 1495            cx,
 1496        )
 1497    }
 1498
 1499    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1500        let buffer = cx.new(|cx| Buffer::local("", cx));
 1501        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1502        Self::new(EditorMode::full(), buffer, None, window, cx)
 1503    }
 1504
 1505    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1506        let buffer = cx.new(|cx| Buffer::local("", cx));
 1507        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1508        Self::new(
 1509            EditorMode::SingleLine { auto_width: true },
 1510            buffer,
 1511            None,
 1512            window,
 1513            cx,
 1514        )
 1515    }
 1516
 1517    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1518        let buffer = cx.new(|cx| Buffer::local("", cx));
 1519        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1520        Self::new(
 1521            EditorMode::AutoHeight { max_lines },
 1522            buffer,
 1523            None,
 1524            window,
 1525            cx,
 1526        )
 1527    }
 1528
 1529    pub fn for_buffer(
 1530        buffer: Entity<Buffer>,
 1531        project: Option<Entity<Project>>,
 1532        window: &mut Window,
 1533        cx: &mut Context<Self>,
 1534    ) -> Self {
 1535        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1536        Self::new(EditorMode::full(), buffer, project, window, cx)
 1537    }
 1538
 1539    pub fn for_multibuffer(
 1540        buffer: Entity<MultiBuffer>,
 1541        project: Option<Entity<Project>>,
 1542        window: &mut Window,
 1543        cx: &mut Context<Self>,
 1544    ) -> Self {
 1545        Self::new(EditorMode::full(), buffer, project, window, cx)
 1546    }
 1547
 1548    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1549        let mut clone = Self::new(
 1550            self.mode.clone(),
 1551            self.buffer.clone(),
 1552            self.project.clone(),
 1553            window,
 1554            cx,
 1555        );
 1556        self.display_map.update(cx, |display_map, cx| {
 1557            let snapshot = display_map.snapshot(cx);
 1558            clone.display_map.update(cx, |display_map, cx| {
 1559                display_map.set_state(&snapshot, cx);
 1560            });
 1561        });
 1562        clone.folds_did_change(cx);
 1563        clone.selections.clone_state(&self.selections);
 1564        clone.scroll_manager.clone_state(&self.scroll_manager);
 1565        clone.searchable = self.searchable;
 1566        clone.read_only = self.read_only;
 1567        clone
 1568    }
 1569
 1570    pub fn new(
 1571        mode: EditorMode,
 1572        buffer: Entity<MultiBuffer>,
 1573        project: Option<Entity<Project>>,
 1574        window: &mut Window,
 1575        cx: &mut Context<Self>,
 1576    ) -> Self {
 1577        Editor::new_internal(mode, buffer, project, None, window, cx)
 1578    }
 1579
 1580    fn new_internal(
 1581        mode: EditorMode,
 1582        buffer: Entity<MultiBuffer>,
 1583        project: Option<Entity<Project>>,
 1584        display_map: Option<Entity<DisplayMap>>,
 1585        window: &mut Window,
 1586        cx: &mut Context<Self>,
 1587    ) -> Self {
 1588        debug_assert!(
 1589            display_map.is_none() || mode.is_minimap(),
 1590            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1591        );
 1592
 1593        let full_mode = mode.is_full();
 1594        let diagnostics_max_severity = if full_mode {
 1595            EditorSettings::get_global(cx)
 1596                .diagnostics_max_severity
 1597                .unwrap_or(DiagnosticSeverity::Hint)
 1598        } else {
 1599            DiagnosticSeverity::Off
 1600        };
 1601        let style = window.text_style();
 1602        let font_size = style.font_size.to_pixels(window.rem_size());
 1603        let editor = cx.entity().downgrade();
 1604        let fold_placeholder = FoldPlaceholder {
 1605            constrain_width: true,
 1606            render: Arc::new(move |fold_id, fold_range, cx| {
 1607                let editor = editor.clone();
 1608                div()
 1609                    .id(fold_id)
 1610                    .bg(cx.theme().colors().ghost_element_background)
 1611                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1612                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1613                    .rounded_xs()
 1614                    .size_full()
 1615                    .cursor_pointer()
 1616                    .child("")
 1617                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1618                    .on_click(move |_, _window, cx| {
 1619                        editor
 1620                            .update(cx, |editor, cx| {
 1621                                editor.unfold_ranges(
 1622                                    &[fold_range.start..fold_range.end],
 1623                                    true,
 1624                                    false,
 1625                                    cx,
 1626                                );
 1627                                cx.stop_propagation();
 1628                            })
 1629                            .ok();
 1630                    })
 1631                    .into_any()
 1632            }),
 1633            merge_adjacent: true,
 1634            ..FoldPlaceholder::default()
 1635        };
 1636        let display_map = display_map.unwrap_or_else(|| {
 1637            cx.new(|cx| {
 1638                DisplayMap::new(
 1639                    buffer.clone(),
 1640                    style.font(),
 1641                    font_size,
 1642                    None,
 1643                    FILE_HEADER_HEIGHT,
 1644                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1645                    fold_placeholder,
 1646                    diagnostics_max_severity,
 1647                    cx,
 1648                )
 1649            })
 1650        });
 1651
 1652        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1653
 1654        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1655
 1656        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1657            .then(|| language_settings::SoftWrap::None);
 1658
 1659        let mut project_subscriptions = Vec::new();
 1660        if mode.is_full() {
 1661            if let Some(project) = project.as_ref() {
 1662                project_subscriptions.push(cx.subscribe_in(
 1663                    project,
 1664                    window,
 1665                    |editor, _, event, window, cx| match event {
 1666                        project::Event::RefreshCodeLens => {
 1667                            // we always query lens with actions, without storing them, always refreshing them
 1668                        }
 1669                        project::Event::RefreshInlayHints => {
 1670                            editor
 1671                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1672                        }
 1673                        project::Event::LanguageServerAdded(..)
 1674                        | project::Event::LanguageServerRemoved(..) => {
 1675                            if editor.tasks_update_task.is_none() {
 1676                                editor.tasks_update_task =
 1677                                    Some(editor.refresh_runnables(window, cx));
 1678                            }
 1679                        }
 1680                        project::Event::SnippetEdit(id, snippet_edits) => {
 1681                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1682                                let focus_handle = editor.focus_handle(cx);
 1683                                if focus_handle.is_focused(window) {
 1684                                    let snapshot = buffer.read(cx).snapshot();
 1685                                    for (range, snippet) in snippet_edits {
 1686                                        let editor_range =
 1687                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1688                                        editor
 1689                                            .insert_snippet(
 1690                                                &[editor_range],
 1691                                                snippet.clone(),
 1692                                                window,
 1693                                                cx,
 1694                                            )
 1695                                            .ok();
 1696                                    }
 1697                                }
 1698                            }
 1699                        }
 1700                        _ => {}
 1701                    },
 1702                ));
 1703                if let Some(task_inventory) = project
 1704                    .read(cx)
 1705                    .task_store()
 1706                    .read(cx)
 1707                    .task_inventory()
 1708                    .cloned()
 1709                {
 1710                    project_subscriptions.push(cx.observe_in(
 1711                        &task_inventory,
 1712                        window,
 1713                        |editor, _, window, cx| {
 1714                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1715                        },
 1716                    ));
 1717                };
 1718
 1719                project_subscriptions.push(cx.subscribe_in(
 1720                    &project.read(cx).breakpoint_store(),
 1721                    window,
 1722                    |editor, _, event, window, cx| match event {
 1723                        BreakpointStoreEvent::ClearDebugLines => {
 1724                            editor.clear_row_highlights::<ActiveDebugLine>();
 1725                            editor.refresh_inline_values(cx);
 1726                        }
 1727                        BreakpointStoreEvent::SetDebugLine => {
 1728                            if editor.go_to_active_debug_line(window, cx) {
 1729                                cx.stop_propagation();
 1730                            }
 1731
 1732                            editor.refresh_inline_values(cx);
 1733                        }
 1734                        _ => {}
 1735                    },
 1736                ));
 1737            }
 1738        }
 1739
 1740        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1741
 1742        let inlay_hint_settings =
 1743            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1744        let focus_handle = cx.focus_handle();
 1745        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1746            .detach();
 1747        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1748            .detach();
 1749        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1750            .detach();
 1751        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1752            .detach();
 1753
 1754        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1755            Some(false)
 1756        } else {
 1757            None
 1758        };
 1759
 1760        let breakpoint_store = match (&mode, project.as_ref()) {
 1761            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1762            _ => None,
 1763        };
 1764
 1765        let mut code_action_providers = Vec::new();
 1766        let mut load_uncommitted_diff = None;
 1767        if let Some(project) = project.clone() {
 1768            load_uncommitted_diff = Some(
 1769                update_uncommitted_diff_for_buffer(
 1770                    cx.entity(),
 1771                    &project,
 1772                    buffer.read(cx).all_buffers(),
 1773                    buffer.clone(),
 1774                    cx,
 1775                )
 1776                .shared(),
 1777            );
 1778            code_action_providers.push(Rc::new(project) as Rc<_>);
 1779        }
 1780
 1781        let mut this = Self {
 1782            focus_handle,
 1783            show_cursor_when_unfocused: false,
 1784            last_focused_descendant: None,
 1785            buffer: buffer.clone(),
 1786            display_map: display_map.clone(),
 1787            selections,
 1788            scroll_manager: ScrollManager::new(cx),
 1789            columnar_selection_tail: None,
 1790            add_selections_state: None,
 1791            select_next_state: None,
 1792            select_prev_state: None,
 1793            selection_history: SelectionHistory::default(),
 1794            autoclose_regions: Vec::new(),
 1795            snippet_stack: InvalidationStack::default(),
 1796            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1797            ime_transaction: None,
 1798            active_diagnostics: ActiveDiagnostic::None,
 1799            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1800            inline_diagnostics_update: Task::ready(()),
 1801            inline_diagnostics: Vec::new(),
 1802            soft_wrap_mode_override,
 1803            diagnostics_max_severity,
 1804            hard_wrap: None,
 1805            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1806            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1807            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1808            project,
 1809            blink_manager: blink_manager.clone(),
 1810            show_local_selections: true,
 1811            show_scrollbars: ScrollbarAxes {
 1812                horizontal: full_mode,
 1813                vertical: full_mode,
 1814            },
 1815            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1816            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1817            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1818            show_gutter: mode.is_full(),
 1819            show_line_numbers: None,
 1820            use_relative_line_numbers: None,
 1821            disable_expand_excerpt_buttons: false,
 1822            show_git_diff_gutter: None,
 1823            show_code_actions: None,
 1824            show_runnables: None,
 1825            show_breakpoints: None,
 1826            show_wrap_guides: None,
 1827            show_indent_guides,
 1828            placeholder_text: None,
 1829            highlight_order: 0,
 1830            highlighted_rows: HashMap::default(),
 1831            background_highlights: TreeMap::default(),
 1832            gutter_highlights: TreeMap::default(),
 1833            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1834            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1835            nav_history: None,
 1836            context_menu: RefCell::new(None),
 1837            context_menu_options: None,
 1838            mouse_context_menu: None,
 1839            completion_tasks: Vec::new(),
 1840            inline_blame_popover: None,
 1841            signature_help_state: SignatureHelpState::default(),
 1842            auto_signature_help: None,
 1843            find_all_references_task_sources: Vec::new(),
 1844            next_completion_id: 0,
 1845            next_inlay_id: 0,
 1846            code_action_providers,
 1847            available_code_actions: None,
 1848            code_actions_task: None,
 1849            quick_selection_highlight_task: None,
 1850            debounced_selection_highlight_task: None,
 1851            document_highlights_task: None,
 1852            linked_editing_range_task: None,
 1853            pending_rename: None,
 1854            searchable: true,
 1855            cursor_shape: EditorSettings::get_global(cx)
 1856                .cursor_shape
 1857                .unwrap_or_default(),
 1858            current_line_highlight: None,
 1859            autoindent_mode: Some(AutoindentMode::EachLine),
 1860            collapse_matches: false,
 1861            workspace: None,
 1862            input_enabled: true,
 1863            use_modal_editing: mode.is_full(),
 1864            read_only: mode.is_minimap(),
 1865            use_autoclose: true,
 1866            use_auto_surround: true,
 1867            auto_replace_emoji_shortcode: false,
 1868            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1869            leader_id: None,
 1870            remote_id: None,
 1871            hover_state: HoverState::default(),
 1872            pending_mouse_down: None,
 1873            hovered_link_state: None,
 1874            edit_prediction_provider: None,
 1875            active_inline_completion: None,
 1876            stale_inline_completion_in_menu: None,
 1877            edit_prediction_preview: EditPredictionPreview::Inactive {
 1878                released_too_fast: false,
 1879            },
 1880            inline_diagnostics_enabled: mode.is_full(),
 1881            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1882            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1883
 1884            gutter_hovered: false,
 1885            pixel_position_of_newest_cursor: None,
 1886            last_bounds: None,
 1887            last_position_map: None,
 1888            expect_bounds_change: None,
 1889            gutter_dimensions: GutterDimensions::default(),
 1890            style: None,
 1891            show_cursor_names: false,
 1892            hovered_cursors: HashMap::default(),
 1893            next_editor_action_id: EditorActionId::default(),
 1894            editor_actions: Rc::default(),
 1895            inline_completions_hidden_for_vim_mode: false,
 1896            show_inline_completions_override: None,
 1897            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1898            edit_prediction_settings: EditPredictionSettings::Disabled,
 1899            edit_prediction_indent_conflict: false,
 1900            edit_prediction_requires_modifier_in_indent_conflict: true,
 1901            custom_context_menu: None,
 1902            show_git_blame_gutter: false,
 1903            show_git_blame_inline: false,
 1904            show_selection_menu: None,
 1905            show_git_blame_inline_delay_task: None,
 1906            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1907            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1908            serialize_dirty_buffers: !mode.is_minimap()
 1909                && ProjectSettings::get_global(cx)
 1910                    .session
 1911                    .restore_unsaved_buffers,
 1912            blame: None,
 1913            blame_subscription: None,
 1914            tasks: BTreeMap::default(),
 1915
 1916            breakpoint_store,
 1917            gutter_breakpoint_indicator: (None, None),
 1918            _subscriptions: vec![
 1919                cx.observe(&buffer, Self::on_buffer_changed),
 1920                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1921                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1922                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1923                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1924                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1925                cx.observe_window_activation(window, |editor, window, cx| {
 1926                    let active = window.is_window_active();
 1927                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1928                        if active {
 1929                            blink_manager.enable(cx);
 1930                        } else {
 1931                            blink_manager.disable(cx);
 1932                        }
 1933                    });
 1934                    if active {
 1935                        editor.show_mouse_cursor();
 1936                    }
 1937                }),
 1938            ],
 1939            tasks_update_task: None,
 1940            linked_edit_ranges: Default::default(),
 1941            in_project_search: false,
 1942            previous_search_ranges: None,
 1943            breadcrumb_header: None,
 1944            focused_block: None,
 1945            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1946            addons: HashMap::default(),
 1947            registered_buffers: HashMap::default(),
 1948            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1949            selection_mark_mode: false,
 1950            toggle_fold_multiple_buffers: Task::ready(()),
 1951            serialize_selections: Task::ready(()),
 1952            serialize_folds: Task::ready(()),
 1953            text_style_refinement: None,
 1954            load_diff_task: load_uncommitted_diff,
 1955            temporary_diff_override: false,
 1956            mouse_cursor_hidden: false,
 1957            minimap: None,
 1958            hide_mouse_mode: EditorSettings::get_global(cx)
 1959                .hide_mouse
 1960                .unwrap_or_default(),
 1961            change_list: ChangeList::new(),
 1962            mode,
 1963        };
 1964        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1965            this._subscriptions
 1966                .push(cx.observe(breakpoints, |_, _, cx| {
 1967                    cx.notify();
 1968                }));
 1969        }
 1970        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1971        this._subscriptions.extend(project_subscriptions);
 1972
 1973        this._subscriptions.push(cx.subscribe_in(
 1974            &cx.entity(),
 1975            window,
 1976            |editor, _, e: &EditorEvent, window, cx| match e {
 1977                EditorEvent::ScrollPositionChanged { local, .. } => {
 1978                    if *local {
 1979                        let new_anchor = editor.scroll_manager.anchor();
 1980                        let snapshot = editor.snapshot(window, cx);
 1981                        editor.update_restoration_data(cx, move |data| {
 1982                            data.scroll_position = (
 1983                                new_anchor.top_row(&snapshot.buffer_snapshot),
 1984                                new_anchor.offset,
 1985                            );
 1986                        });
 1987                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 1988                        editor.inline_blame_popover.take();
 1989                    }
 1990                }
 1991                EditorEvent::Edited { .. } => {
 1992                    if !vim_enabled(cx) {
 1993                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 1994                        let pop_state = editor
 1995                            .change_list
 1996                            .last()
 1997                            .map(|previous| {
 1998                                previous.len() == selections.len()
 1999                                    && previous.iter().enumerate().all(|(ix, p)| {
 2000                                        p.to_display_point(&map).row()
 2001                                            == selections[ix].head().row()
 2002                                    })
 2003                            })
 2004                            .unwrap_or(false);
 2005                        let new_positions = selections
 2006                            .into_iter()
 2007                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2008                            .collect();
 2009                        editor
 2010                            .change_list
 2011                            .push_to_change_list(pop_state, new_positions);
 2012                    }
 2013                }
 2014                _ => (),
 2015            },
 2016        ));
 2017
 2018        if let Some(dap_store) = this
 2019            .project
 2020            .as_ref()
 2021            .map(|project| project.read(cx).dap_store())
 2022        {
 2023            let weak_editor = cx.weak_entity();
 2024
 2025            this._subscriptions
 2026                .push(
 2027                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2028                        let session_entity = cx.entity();
 2029                        weak_editor
 2030                            .update(cx, |editor, cx| {
 2031                                editor._subscriptions.push(
 2032                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2033                                );
 2034                            })
 2035                            .ok();
 2036                    }),
 2037                );
 2038
 2039            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2040                this._subscriptions
 2041                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2042            }
 2043        }
 2044
 2045        this.end_selection(window, cx);
 2046        this.scroll_manager.show_scrollbars(window, cx);
 2047        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 2048
 2049        if full_mode {
 2050            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2051            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2052
 2053            if this.git_blame_inline_enabled {
 2054                this.start_git_blame_inline(false, window, cx);
 2055            }
 2056
 2057            this.go_to_active_debug_line(window, cx);
 2058
 2059            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2060                if let Some(project) = this.project.as_ref() {
 2061                    let handle = project.update(cx, |project, cx| {
 2062                        project.register_buffer_with_language_servers(&buffer, cx)
 2063                    });
 2064                    this.registered_buffers
 2065                        .insert(buffer.read(cx).remote_id(), handle);
 2066                }
 2067            }
 2068
 2069            this.minimap = this.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2070        }
 2071
 2072        this.report_editor_event("Editor Opened", None, cx);
 2073        this
 2074    }
 2075
 2076    pub fn deploy_mouse_context_menu(
 2077        &mut self,
 2078        position: gpui::Point<Pixels>,
 2079        context_menu: Entity<ContextMenu>,
 2080        window: &mut Window,
 2081        cx: &mut Context<Self>,
 2082    ) {
 2083        self.mouse_context_menu = Some(MouseContextMenu::new(
 2084            self,
 2085            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2086            context_menu,
 2087            window,
 2088            cx,
 2089        ));
 2090    }
 2091
 2092    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2093        self.mouse_context_menu
 2094            .as_ref()
 2095            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2096    }
 2097
 2098    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2099        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2100    }
 2101
 2102    fn key_context_internal(
 2103        &self,
 2104        has_active_edit_prediction: bool,
 2105        window: &Window,
 2106        cx: &App,
 2107    ) -> KeyContext {
 2108        let mut key_context = KeyContext::new_with_defaults();
 2109        key_context.add("Editor");
 2110        let mode = match self.mode {
 2111            EditorMode::SingleLine { .. } => "single_line",
 2112            EditorMode::AutoHeight { .. } => "auto_height",
 2113            EditorMode::Minimap { .. } => "minimap",
 2114            EditorMode::Full { .. } => "full",
 2115        };
 2116
 2117        if EditorSettings::jupyter_enabled(cx) {
 2118            key_context.add("jupyter");
 2119        }
 2120
 2121        key_context.set("mode", mode);
 2122        if self.pending_rename.is_some() {
 2123            key_context.add("renaming");
 2124        }
 2125
 2126        match self.context_menu.borrow().as_ref() {
 2127            Some(CodeContextMenu::Completions(_)) => {
 2128                key_context.add("menu");
 2129                key_context.add("showing_completions");
 2130            }
 2131            Some(CodeContextMenu::CodeActions(_)) => {
 2132                key_context.add("menu");
 2133                key_context.add("showing_code_actions")
 2134            }
 2135            None => {}
 2136        }
 2137
 2138        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2139        if !self.focus_handle(cx).contains_focused(window, cx)
 2140            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2141        {
 2142            for addon in self.addons.values() {
 2143                addon.extend_key_context(&mut key_context, cx)
 2144            }
 2145        }
 2146
 2147        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2148            if let Some(extension) = singleton_buffer
 2149                .read(cx)
 2150                .file()
 2151                .and_then(|file| file.path().extension()?.to_str())
 2152            {
 2153                key_context.set("extension", extension.to_string());
 2154            }
 2155        } else {
 2156            key_context.add("multibuffer");
 2157        }
 2158
 2159        if has_active_edit_prediction {
 2160            if self.edit_prediction_in_conflict() {
 2161                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2162            } else {
 2163                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2164                key_context.add("copilot_suggestion");
 2165            }
 2166        }
 2167
 2168        if self.selection_mark_mode {
 2169            key_context.add("selection_mode");
 2170        }
 2171
 2172        key_context
 2173    }
 2174
 2175    fn show_mouse_cursor(&mut self) {
 2176        self.mouse_cursor_hidden = false;
 2177    }
 2178
 2179    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2180        self.mouse_cursor_hidden = match origin {
 2181            HideMouseCursorOrigin::TypingAction => {
 2182                matches!(
 2183                    self.hide_mouse_mode,
 2184                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2185                )
 2186            }
 2187            HideMouseCursorOrigin::MovementAction => {
 2188                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2189            }
 2190        };
 2191    }
 2192
 2193    pub fn edit_prediction_in_conflict(&self) -> bool {
 2194        if !self.show_edit_predictions_in_menu() {
 2195            return false;
 2196        }
 2197
 2198        let showing_completions = self
 2199            .context_menu
 2200            .borrow()
 2201            .as_ref()
 2202            .map_or(false, |context| {
 2203                matches!(context, CodeContextMenu::Completions(_))
 2204            });
 2205
 2206        showing_completions
 2207            || self.edit_prediction_requires_modifier()
 2208            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2209            // bindings to insert tab characters.
 2210            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2211    }
 2212
 2213    pub fn accept_edit_prediction_keybind(
 2214        &self,
 2215        window: &Window,
 2216        cx: &App,
 2217    ) -> AcceptEditPredictionBinding {
 2218        let key_context = self.key_context_internal(true, window, cx);
 2219        let in_conflict = self.edit_prediction_in_conflict();
 2220
 2221        AcceptEditPredictionBinding(
 2222            window
 2223                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2224                .into_iter()
 2225                .filter(|binding| {
 2226                    !in_conflict
 2227                        || binding
 2228                            .keystrokes()
 2229                            .first()
 2230                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 2231                })
 2232                .rev()
 2233                .min_by_key(|binding| {
 2234                    binding
 2235                        .keystrokes()
 2236                        .first()
 2237                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 2238                }),
 2239        )
 2240    }
 2241
 2242    pub fn new_file(
 2243        workspace: &mut Workspace,
 2244        _: &workspace::NewFile,
 2245        window: &mut Window,
 2246        cx: &mut Context<Workspace>,
 2247    ) {
 2248        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2249            "Failed to create buffer",
 2250            window,
 2251            cx,
 2252            |e, _, _| match e.error_code() {
 2253                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2254                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2255                e.error_tag("required").unwrap_or("the latest version")
 2256            )),
 2257                _ => None,
 2258            },
 2259        );
 2260    }
 2261
 2262    pub fn new_in_workspace(
 2263        workspace: &mut Workspace,
 2264        window: &mut Window,
 2265        cx: &mut Context<Workspace>,
 2266    ) -> Task<Result<Entity<Editor>>> {
 2267        let project = workspace.project().clone();
 2268        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2269
 2270        cx.spawn_in(window, async move |workspace, cx| {
 2271            let buffer = create.await?;
 2272            workspace.update_in(cx, |workspace, window, cx| {
 2273                let editor =
 2274                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2275                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2276                editor
 2277            })
 2278        })
 2279    }
 2280
 2281    fn new_file_vertical(
 2282        workspace: &mut Workspace,
 2283        _: &workspace::NewFileSplitVertical,
 2284        window: &mut Window,
 2285        cx: &mut Context<Workspace>,
 2286    ) {
 2287        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2288    }
 2289
 2290    fn new_file_horizontal(
 2291        workspace: &mut Workspace,
 2292        _: &workspace::NewFileSplitHorizontal,
 2293        window: &mut Window,
 2294        cx: &mut Context<Workspace>,
 2295    ) {
 2296        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2297    }
 2298
 2299    fn new_file_in_direction(
 2300        workspace: &mut Workspace,
 2301        direction: SplitDirection,
 2302        window: &mut Window,
 2303        cx: &mut Context<Workspace>,
 2304    ) {
 2305        let project = workspace.project().clone();
 2306        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2307
 2308        cx.spawn_in(window, async move |workspace, cx| {
 2309            let buffer = create.await?;
 2310            workspace.update_in(cx, move |workspace, window, cx| {
 2311                workspace.split_item(
 2312                    direction,
 2313                    Box::new(
 2314                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2315                    ),
 2316                    window,
 2317                    cx,
 2318                )
 2319            })?;
 2320            anyhow::Ok(())
 2321        })
 2322        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2323            match e.error_code() {
 2324                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2325                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2326                e.error_tag("required").unwrap_or("the latest version")
 2327            )),
 2328                _ => None,
 2329            }
 2330        });
 2331    }
 2332
 2333    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2334        self.leader_id
 2335    }
 2336
 2337    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2338        &self.buffer
 2339    }
 2340
 2341    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2342        self.workspace.as_ref()?.0.upgrade()
 2343    }
 2344
 2345    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2346        self.buffer().read(cx).title(cx)
 2347    }
 2348
 2349    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2350        let git_blame_gutter_max_author_length = self
 2351            .render_git_blame_gutter(cx)
 2352            .then(|| {
 2353                if let Some(blame) = self.blame.as_ref() {
 2354                    let max_author_length =
 2355                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2356                    Some(max_author_length)
 2357                } else {
 2358                    None
 2359                }
 2360            })
 2361            .flatten();
 2362
 2363        EditorSnapshot {
 2364            mode: self.mode.clone(),
 2365            show_gutter: self.show_gutter,
 2366            show_line_numbers: self.show_line_numbers,
 2367            show_git_diff_gutter: self.show_git_diff_gutter,
 2368            show_code_actions: self.show_code_actions,
 2369            show_runnables: self.show_runnables,
 2370            show_breakpoints: self.show_breakpoints,
 2371            git_blame_gutter_max_author_length,
 2372            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2373            scroll_anchor: self.scroll_manager.anchor(),
 2374            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2375            placeholder_text: self.placeholder_text.clone(),
 2376            is_focused: self.focus_handle.is_focused(window),
 2377            current_line_highlight: self
 2378                .current_line_highlight
 2379                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2380            gutter_hovered: self.gutter_hovered,
 2381        }
 2382    }
 2383
 2384    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2385        self.buffer.read(cx).language_at(point, cx)
 2386    }
 2387
 2388    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2389        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2390    }
 2391
 2392    pub fn active_excerpt(
 2393        &self,
 2394        cx: &App,
 2395    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2396        self.buffer
 2397            .read(cx)
 2398            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2399    }
 2400
 2401    pub fn mode(&self) -> &EditorMode {
 2402        &self.mode
 2403    }
 2404
 2405    pub fn set_mode(&mut self, mode: EditorMode) {
 2406        self.mode = mode;
 2407    }
 2408
 2409    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2410        self.collaboration_hub.as_deref()
 2411    }
 2412
 2413    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2414        self.collaboration_hub = Some(hub);
 2415    }
 2416
 2417    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2418        self.in_project_search = in_project_search;
 2419    }
 2420
 2421    pub fn set_custom_context_menu(
 2422        &mut self,
 2423        f: impl 'static
 2424        + Fn(
 2425            &mut Self,
 2426            DisplayPoint,
 2427            &mut Window,
 2428            &mut Context<Self>,
 2429        ) -> Option<Entity<ui::ContextMenu>>,
 2430    ) {
 2431        self.custom_context_menu = Some(Box::new(f))
 2432    }
 2433
 2434    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2435        self.completion_provider = provider;
 2436    }
 2437
 2438    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2439        self.semantics_provider.clone()
 2440    }
 2441
 2442    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2443        self.semantics_provider = provider;
 2444    }
 2445
 2446    pub fn set_edit_prediction_provider<T>(
 2447        &mut self,
 2448        provider: Option<Entity<T>>,
 2449        window: &mut Window,
 2450        cx: &mut Context<Self>,
 2451    ) where
 2452        T: EditPredictionProvider,
 2453    {
 2454        self.edit_prediction_provider =
 2455            provider.map(|provider| RegisteredInlineCompletionProvider {
 2456                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2457                    if this.focus_handle.is_focused(window) {
 2458                        this.update_visible_inline_completion(window, cx);
 2459                    }
 2460                }),
 2461                provider: Arc::new(provider),
 2462            });
 2463        self.update_edit_prediction_settings(cx);
 2464        self.refresh_inline_completion(false, false, window, cx);
 2465    }
 2466
 2467    pub fn placeholder_text(&self) -> Option<&str> {
 2468        self.placeholder_text.as_deref()
 2469    }
 2470
 2471    pub fn set_placeholder_text(
 2472        &mut self,
 2473        placeholder_text: impl Into<Arc<str>>,
 2474        cx: &mut Context<Self>,
 2475    ) {
 2476        let placeholder_text = Some(placeholder_text.into());
 2477        if self.placeholder_text != placeholder_text {
 2478            self.placeholder_text = placeholder_text;
 2479            cx.notify();
 2480        }
 2481    }
 2482
 2483    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2484        self.cursor_shape = cursor_shape;
 2485
 2486        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2487        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2488
 2489        cx.notify();
 2490    }
 2491
 2492    pub fn set_current_line_highlight(
 2493        &mut self,
 2494        current_line_highlight: Option<CurrentLineHighlight>,
 2495    ) {
 2496        self.current_line_highlight = current_line_highlight;
 2497    }
 2498
 2499    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2500        self.collapse_matches = collapse_matches;
 2501    }
 2502
 2503    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2504        let buffers = self.buffer.read(cx).all_buffers();
 2505        let Some(project) = self.project.as_ref() else {
 2506            return;
 2507        };
 2508        project.update(cx, |project, cx| {
 2509            for buffer in buffers {
 2510                self.registered_buffers
 2511                    .entry(buffer.read(cx).remote_id())
 2512                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2513            }
 2514        })
 2515    }
 2516
 2517    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2518        if self.collapse_matches {
 2519            return range.start..range.start;
 2520        }
 2521        range.clone()
 2522    }
 2523
 2524    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2525        if self.display_map.read(cx).clip_at_line_ends != clip {
 2526            self.display_map
 2527                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2528        }
 2529    }
 2530
 2531    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2532        self.input_enabled = input_enabled;
 2533    }
 2534
 2535    pub fn set_inline_completions_hidden_for_vim_mode(
 2536        &mut self,
 2537        hidden: bool,
 2538        window: &mut Window,
 2539        cx: &mut Context<Self>,
 2540    ) {
 2541        if hidden != self.inline_completions_hidden_for_vim_mode {
 2542            self.inline_completions_hidden_for_vim_mode = hidden;
 2543            if hidden {
 2544                self.update_visible_inline_completion(window, cx);
 2545            } else {
 2546                self.refresh_inline_completion(true, false, window, cx);
 2547            }
 2548        }
 2549    }
 2550
 2551    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2552        self.menu_inline_completions_policy = value;
 2553    }
 2554
 2555    pub fn set_autoindent(&mut self, autoindent: bool) {
 2556        if autoindent {
 2557            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2558        } else {
 2559            self.autoindent_mode = None;
 2560        }
 2561    }
 2562
 2563    pub fn read_only(&self, cx: &App) -> bool {
 2564        self.read_only || self.buffer.read(cx).read_only()
 2565    }
 2566
 2567    pub fn set_read_only(&mut self, read_only: bool) {
 2568        self.read_only = read_only;
 2569    }
 2570
 2571    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2572        self.use_autoclose = autoclose;
 2573    }
 2574
 2575    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2576        self.use_auto_surround = auto_surround;
 2577    }
 2578
 2579    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2580        self.auto_replace_emoji_shortcode = auto_replace;
 2581    }
 2582
 2583    pub fn toggle_edit_predictions(
 2584        &mut self,
 2585        _: &ToggleEditPrediction,
 2586        window: &mut Window,
 2587        cx: &mut Context<Self>,
 2588    ) {
 2589        if self.show_inline_completions_override.is_some() {
 2590            self.set_show_edit_predictions(None, window, cx);
 2591        } else {
 2592            let show_edit_predictions = !self.edit_predictions_enabled();
 2593            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2594        }
 2595    }
 2596
 2597    pub fn set_show_edit_predictions(
 2598        &mut self,
 2599        show_edit_predictions: Option<bool>,
 2600        window: &mut Window,
 2601        cx: &mut Context<Self>,
 2602    ) {
 2603        self.show_inline_completions_override = show_edit_predictions;
 2604        self.update_edit_prediction_settings(cx);
 2605
 2606        if let Some(false) = show_edit_predictions {
 2607            self.discard_inline_completion(false, cx);
 2608        } else {
 2609            self.refresh_inline_completion(false, true, window, cx);
 2610        }
 2611    }
 2612
 2613    fn inline_completions_disabled_in_scope(
 2614        &self,
 2615        buffer: &Entity<Buffer>,
 2616        buffer_position: language::Anchor,
 2617        cx: &App,
 2618    ) -> bool {
 2619        let snapshot = buffer.read(cx).snapshot();
 2620        let settings = snapshot.settings_at(buffer_position, cx);
 2621
 2622        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2623            return false;
 2624        };
 2625
 2626        scope.override_name().map_or(false, |scope_name| {
 2627            settings
 2628                .edit_predictions_disabled_in
 2629                .iter()
 2630                .any(|s| s == scope_name)
 2631        })
 2632    }
 2633
 2634    pub fn set_use_modal_editing(&mut self, to: bool) {
 2635        self.use_modal_editing = to;
 2636    }
 2637
 2638    pub fn use_modal_editing(&self) -> bool {
 2639        self.use_modal_editing
 2640    }
 2641
 2642    fn selections_did_change(
 2643        &mut self,
 2644        local: bool,
 2645        old_cursor_position: &Anchor,
 2646        show_completions: bool,
 2647        window: &mut Window,
 2648        cx: &mut Context<Self>,
 2649    ) {
 2650        window.invalidate_character_coordinates();
 2651
 2652        // Copy selections to primary selection buffer
 2653        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2654        if local {
 2655            let selections = self.selections.all::<usize>(cx);
 2656            let buffer_handle = self.buffer.read(cx).read(cx);
 2657
 2658            let mut text = String::new();
 2659            for (index, selection) in selections.iter().enumerate() {
 2660                let text_for_selection = buffer_handle
 2661                    .text_for_range(selection.start..selection.end)
 2662                    .collect::<String>();
 2663
 2664                text.push_str(&text_for_selection);
 2665                if index != selections.len() - 1 {
 2666                    text.push('\n');
 2667                }
 2668            }
 2669
 2670            if !text.is_empty() {
 2671                cx.write_to_primary(ClipboardItem::new_string(text));
 2672            }
 2673        }
 2674
 2675        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2676            self.buffer.update(cx, |buffer, cx| {
 2677                buffer.set_active_selections(
 2678                    &self.selections.disjoint_anchors(),
 2679                    self.selections.line_mode,
 2680                    self.cursor_shape,
 2681                    cx,
 2682                )
 2683            });
 2684        }
 2685        let display_map = self
 2686            .display_map
 2687            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2688        let buffer = &display_map.buffer_snapshot;
 2689        self.add_selections_state = None;
 2690        self.select_next_state = None;
 2691        self.select_prev_state = None;
 2692        self.select_syntax_node_history.try_clear();
 2693        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2694        self.snippet_stack
 2695            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2696        self.take_rename(false, window, cx);
 2697
 2698        let new_cursor_position = self.selections.newest_anchor().head();
 2699
 2700        self.push_to_nav_history(
 2701            *old_cursor_position,
 2702            Some(new_cursor_position.to_point(buffer)),
 2703            false,
 2704            cx,
 2705        );
 2706
 2707        if local {
 2708            let new_cursor_position = self.selections.newest_anchor().head();
 2709            let mut context_menu = self.context_menu.borrow_mut();
 2710            let completion_menu = match context_menu.as_ref() {
 2711                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2712                _ => {
 2713                    *context_menu = None;
 2714                    None
 2715                }
 2716            };
 2717            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2718                if !self.registered_buffers.contains_key(&buffer_id) {
 2719                    if let Some(project) = self.project.as_ref() {
 2720                        project.update(cx, |project, cx| {
 2721                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2722                                return;
 2723                            };
 2724                            self.registered_buffers.insert(
 2725                                buffer_id,
 2726                                project.register_buffer_with_language_servers(&buffer, cx),
 2727                            );
 2728                        })
 2729                    }
 2730                }
 2731            }
 2732
 2733            if let Some(completion_menu) = completion_menu {
 2734                let cursor_position = new_cursor_position.to_offset(buffer);
 2735                let (word_range, kind) =
 2736                    buffer.surrounding_word(completion_menu.initial_position, true);
 2737                if kind == Some(CharKind::Word)
 2738                    && word_range.to_inclusive().contains(&cursor_position)
 2739                {
 2740                    let mut completion_menu = completion_menu.clone();
 2741                    drop(context_menu);
 2742
 2743                    let query = Self::completion_query(buffer, cursor_position);
 2744                    let completion_provider = self.completion_provider.clone();
 2745                    cx.spawn_in(window, async move |this, cx| {
 2746                        completion_menu
 2747                            .filter(query.as_deref(), completion_provider, this.clone(), cx)
 2748                            .await;
 2749
 2750                        this.update(cx, |this, cx| {
 2751                            let mut context_menu = this.context_menu.borrow_mut();
 2752                            let Some(CodeContextMenu::Completions(menu)) = context_menu.as_ref()
 2753                            else {
 2754                                return;
 2755                            };
 2756
 2757                            if menu.id > completion_menu.id {
 2758                                return;
 2759                            }
 2760
 2761                            *context_menu = Some(CodeContextMenu::Completions(completion_menu));
 2762                            drop(context_menu);
 2763                            cx.notify();
 2764                        })
 2765                    })
 2766                    .detach();
 2767
 2768                    if show_completions {
 2769                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2770                    }
 2771                } else {
 2772                    drop(context_menu);
 2773                    self.hide_context_menu(window, cx);
 2774                }
 2775            } else {
 2776                drop(context_menu);
 2777            }
 2778
 2779            hide_hover(self, cx);
 2780
 2781            if old_cursor_position.to_display_point(&display_map).row()
 2782                != new_cursor_position.to_display_point(&display_map).row()
 2783            {
 2784                self.available_code_actions.take();
 2785            }
 2786            self.refresh_code_actions(window, cx);
 2787            self.refresh_document_highlights(cx);
 2788            self.refresh_selected_text_highlights(false, window, cx);
 2789            refresh_matching_bracket_highlights(self, window, cx);
 2790            self.update_visible_inline_completion(window, cx);
 2791            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2792            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2793            self.inline_blame_popover.take();
 2794            if self.git_blame_inline_enabled {
 2795                self.start_inline_blame_timer(window, cx);
 2796            }
 2797        }
 2798
 2799        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2800        cx.emit(EditorEvent::SelectionsChanged { local });
 2801
 2802        let selections = &self.selections.disjoint;
 2803        if selections.len() == 1 {
 2804            cx.emit(SearchEvent::ActiveMatchChanged)
 2805        }
 2806        if local {
 2807            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2808                let inmemory_selections = selections
 2809                    .iter()
 2810                    .map(|s| {
 2811                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2812                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2813                    })
 2814                    .collect();
 2815                self.update_restoration_data(cx, |data| {
 2816                    data.selections = inmemory_selections;
 2817                });
 2818
 2819                if WorkspaceSettings::get(None, cx).restore_on_startup
 2820                    != RestoreOnStartupBehavior::None
 2821                {
 2822                    if let Some(workspace_id) =
 2823                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2824                    {
 2825                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2826                        let selections = selections.clone();
 2827                        let background_executor = cx.background_executor().clone();
 2828                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2829                        self.serialize_selections = cx.background_spawn(async move {
 2830                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2831                    let db_selections = selections
 2832                        .iter()
 2833                        .map(|selection| {
 2834                            (
 2835                                selection.start.to_offset(&snapshot),
 2836                                selection.end.to_offset(&snapshot),
 2837                            )
 2838                        })
 2839                        .collect();
 2840
 2841                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2842                        .await
 2843                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2844                        .log_err();
 2845                });
 2846                    }
 2847                }
 2848            }
 2849        }
 2850
 2851        cx.notify();
 2852    }
 2853
 2854    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2855        use text::ToOffset as _;
 2856        use text::ToPoint as _;
 2857
 2858        if self.mode.is_minimap()
 2859            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2860        {
 2861            return;
 2862        }
 2863
 2864        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2865            return;
 2866        };
 2867
 2868        let snapshot = singleton.read(cx).snapshot();
 2869        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2870            let display_snapshot = display_map.snapshot(cx);
 2871
 2872            display_snapshot
 2873                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2874                .map(|fold| {
 2875                    fold.range.start.text_anchor.to_point(&snapshot)
 2876                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2877                })
 2878                .collect()
 2879        });
 2880        self.update_restoration_data(cx, |data| {
 2881            data.folds = inmemory_folds;
 2882        });
 2883
 2884        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2885            return;
 2886        };
 2887        let background_executor = cx.background_executor().clone();
 2888        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2889        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2890            display_map
 2891                .snapshot(cx)
 2892                .folds_in_range(0..snapshot.len())
 2893                .map(|fold| {
 2894                    (
 2895                        fold.range.start.text_anchor.to_offset(&snapshot),
 2896                        fold.range.end.text_anchor.to_offset(&snapshot),
 2897                    )
 2898                })
 2899                .collect()
 2900        });
 2901        self.serialize_folds = cx.background_spawn(async move {
 2902            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2903            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2904                .await
 2905                .with_context(|| {
 2906                    format!(
 2907                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2908                    )
 2909                })
 2910                .log_err();
 2911        });
 2912    }
 2913
 2914    pub fn sync_selections(
 2915        &mut self,
 2916        other: Entity<Editor>,
 2917        cx: &mut Context<Self>,
 2918    ) -> gpui::Subscription {
 2919        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2920        self.selections.change_with(cx, |selections| {
 2921            selections.select_anchors(other_selections);
 2922        });
 2923
 2924        let other_subscription =
 2925            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2926                EditorEvent::SelectionsChanged { local: true } => {
 2927                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2928                    if other_selections.is_empty() {
 2929                        return;
 2930                    }
 2931                    this.selections.change_with(cx, |selections| {
 2932                        selections.select_anchors(other_selections);
 2933                    });
 2934                }
 2935                _ => {}
 2936            });
 2937
 2938        let this_subscription =
 2939            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2940                EditorEvent::SelectionsChanged { local: true } => {
 2941                    let these_selections = this.selections.disjoint.to_vec();
 2942                    if these_selections.is_empty() {
 2943                        return;
 2944                    }
 2945                    other.update(cx, |other_editor, cx| {
 2946                        other_editor.selections.change_with(cx, |selections| {
 2947                            selections.select_anchors(these_selections);
 2948                        })
 2949                    });
 2950                }
 2951                _ => {}
 2952            });
 2953
 2954        Subscription::join(other_subscription, this_subscription)
 2955    }
 2956
 2957    pub fn change_selections<R>(
 2958        &mut self,
 2959        autoscroll: Option<Autoscroll>,
 2960        window: &mut Window,
 2961        cx: &mut Context<Self>,
 2962        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2963    ) -> R {
 2964        self.change_selections_inner(autoscroll, true, window, cx, change)
 2965    }
 2966
 2967    fn change_selections_inner<R>(
 2968        &mut self,
 2969        autoscroll: Option<Autoscroll>,
 2970        request_completions: bool,
 2971        window: &mut Window,
 2972        cx: &mut Context<Self>,
 2973        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2974    ) -> R {
 2975        let old_cursor_position = self.selections.newest_anchor().head();
 2976        self.push_to_selection_history();
 2977
 2978        let (changed, result) = self.selections.change_with(cx, change);
 2979
 2980        if changed {
 2981            if let Some(autoscroll) = autoscroll {
 2982                self.request_autoscroll(autoscroll, cx);
 2983            }
 2984            self.selections_did_change(true, &old_cursor_position, request_completions, window, cx);
 2985
 2986            if self.should_open_signature_help_automatically(
 2987                &old_cursor_position,
 2988                self.signature_help_state.backspace_pressed(),
 2989                cx,
 2990            ) {
 2991                self.show_signature_help(&ShowSignatureHelp, window, cx);
 2992            }
 2993            self.signature_help_state.set_backspace_pressed(false);
 2994        }
 2995
 2996        result
 2997    }
 2998
 2999    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3000    where
 3001        I: IntoIterator<Item = (Range<S>, T)>,
 3002        S: ToOffset,
 3003        T: Into<Arc<str>>,
 3004    {
 3005        if self.read_only(cx) {
 3006            return;
 3007        }
 3008
 3009        self.buffer
 3010            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3011    }
 3012
 3013    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3014    where
 3015        I: IntoIterator<Item = (Range<S>, T)>,
 3016        S: ToOffset,
 3017        T: Into<Arc<str>>,
 3018    {
 3019        if self.read_only(cx) {
 3020            return;
 3021        }
 3022
 3023        self.buffer.update(cx, |buffer, cx| {
 3024            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3025        });
 3026    }
 3027
 3028    pub fn edit_with_block_indent<I, S, T>(
 3029        &mut self,
 3030        edits: I,
 3031        original_indent_columns: Vec<Option<u32>>,
 3032        cx: &mut Context<Self>,
 3033    ) where
 3034        I: IntoIterator<Item = (Range<S>, T)>,
 3035        S: ToOffset,
 3036        T: Into<Arc<str>>,
 3037    {
 3038        if self.read_only(cx) {
 3039            return;
 3040        }
 3041
 3042        self.buffer.update(cx, |buffer, cx| {
 3043            buffer.edit(
 3044                edits,
 3045                Some(AutoindentMode::Block {
 3046                    original_indent_columns,
 3047                }),
 3048                cx,
 3049            )
 3050        });
 3051    }
 3052
 3053    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3054        self.hide_context_menu(window, cx);
 3055
 3056        match phase {
 3057            SelectPhase::Begin {
 3058                position,
 3059                add,
 3060                click_count,
 3061            } => self.begin_selection(position, add, click_count, window, cx),
 3062            SelectPhase::BeginColumnar {
 3063                position,
 3064                goal_column,
 3065                reset,
 3066            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3067            SelectPhase::Extend {
 3068                position,
 3069                click_count,
 3070            } => self.extend_selection(position, click_count, window, cx),
 3071            SelectPhase::Update {
 3072                position,
 3073                goal_column,
 3074                scroll_delta,
 3075            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3076            SelectPhase::End => self.end_selection(window, cx),
 3077        }
 3078    }
 3079
 3080    fn extend_selection(
 3081        &mut self,
 3082        position: DisplayPoint,
 3083        click_count: usize,
 3084        window: &mut Window,
 3085        cx: &mut Context<Self>,
 3086    ) {
 3087        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3088        let tail = self.selections.newest::<usize>(cx).tail();
 3089        self.begin_selection(position, false, click_count, window, cx);
 3090
 3091        let position = position.to_offset(&display_map, Bias::Left);
 3092        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3093
 3094        let mut pending_selection = self
 3095            .selections
 3096            .pending_anchor()
 3097            .expect("extend_selection not called with pending selection");
 3098        if position >= tail {
 3099            pending_selection.start = tail_anchor;
 3100        } else {
 3101            pending_selection.end = tail_anchor;
 3102            pending_selection.reversed = true;
 3103        }
 3104
 3105        let mut pending_mode = self.selections.pending_mode().unwrap();
 3106        match &mut pending_mode {
 3107            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3108            _ => {}
 3109        }
 3110
 3111        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3112
 3113        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3114            s.set_pending(pending_selection, pending_mode)
 3115        });
 3116    }
 3117
 3118    fn begin_selection(
 3119        &mut self,
 3120        position: DisplayPoint,
 3121        add: bool,
 3122        click_count: usize,
 3123        window: &mut Window,
 3124        cx: &mut Context<Self>,
 3125    ) {
 3126        if !self.focus_handle.is_focused(window) {
 3127            self.last_focused_descendant = None;
 3128            window.focus(&self.focus_handle);
 3129        }
 3130
 3131        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3132        let buffer = &display_map.buffer_snapshot;
 3133        let position = display_map.clip_point(position, Bias::Left);
 3134
 3135        let start;
 3136        let end;
 3137        let mode;
 3138        let mut auto_scroll;
 3139        match click_count {
 3140            1 => {
 3141                start = buffer.anchor_before(position.to_point(&display_map));
 3142                end = start;
 3143                mode = SelectMode::Character;
 3144                auto_scroll = true;
 3145            }
 3146            2 => {
 3147                let range = movement::surrounding_word(&display_map, position);
 3148                start = buffer.anchor_before(range.start.to_point(&display_map));
 3149                end = buffer.anchor_before(range.end.to_point(&display_map));
 3150                mode = SelectMode::Word(start..end);
 3151                auto_scroll = true;
 3152            }
 3153            3 => {
 3154                let position = display_map
 3155                    .clip_point(position, Bias::Left)
 3156                    .to_point(&display_map);
 3157                let line_start = display_map.prev_line_boundary(position).0;
 3158                let next_line_start = buffer.clip_point(
 3159                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3160                    Bias::Left,
 3161                );
 3162                start = buffer.anchor_before(line_start);
 3163                end = buffer.anchor_before(next_line_start);
 3164                mode = SelectMode::Line(start..end);
 3165                auto_scroll = true;
 3166            }
 3167            _ => {
 3168                start = buffer.anchor_before(0);
 3169                end = buffer.anchor_before(buffer.len());
 3170                mode = SelectMode::All;
 3171                auto_scroll = false;
 3172            }
 3173        }
 3174        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3175
 3176        let point_to_delete: Option<usize> = {
 3177            let selected_points: Vec<Selection<Point>> =
 3178                self.selections.disjoint_in_range(start..end, cx);
 3179
 3180            if !add || click_count > 1 {
 3181                None
 3182            } else if !selected_points.is_empty() {
 3183                Some(selected_points[0].id)
 3184            } else {
 3185                let clicked_point_already_selected =
 3186                    self.selections.disjoint.iter().find(|selection| {
 3187                        selection.start.to_point(buffer) == start.to_point(buffer)
 3188                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3189                    });
 3190
 3191                clicked_point_already_selected.map(|selection| selection.id)
 3192            }
 3193        };
 3194
 3195        let selections_count = self.selections.count();
 3196
 3197        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3198            if let Some(point_to_delete) = point_to_delete {
 3199                s.delete(point_to_delete);
 3200
 3201                if selections_count == 1 {
 3202                    s.set_pending_anchor_range(start..end, mode);
 3203                }
 3204            } else {
 3205                if !add {
 3206                    s.clear_disjoint();
 3207                }
 3208
 3209                s.set_pending_anchor_range(start..end, mode);
 3210            }
 3211        });
 3212    }
 3213
 3214    fn begin_columnar_selection(
 3215        &mut self,
 3216        position: DisplayPoint,
 3217        goal_column: u32,
 3218        reset: bool,
 3219        window: &mut Window,
 3220        cx: &mut Context<Self>,
 3221    ) {
 3222        if !self.focus_handle.is_focused(window) {
 3223            self.last_focused_descendant = None;
 3224            window.focus(&self.focus_handle);
 3225        }
 3226
 3227        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3228
 3229        if reset {
 3230            let pointer_position = display_map
 3231                .buffer_snapshot
 3232                .anchor_before(position.to_point(&display_map));
 3233
 3234            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3235                s.clear_disjoint();
 3236                s.set_pending_anchor_range(
 3237                    pointer_position..pointer_position,
 3238                    SelectMode::Character,
 3239                );
 3240            });
 3241        }
 3242
 3243        let tail = self.selections.newest::<Point>(cx).tail();
 3244        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3245
 3246        if !reset {
 3247            self.select_columns(
 3248                tail.to_display_point(&display_map),
 3249                position,
 3250                goal_column,
 3251                &display_map,
 3252                window,
 3253                cx,
 3254            );
 3255        }
 3256    }
 3257
 3258    fn update_selection(
 3259        &mut self,
 3260        position: DisplayPoint,
 3261        goal_column: u32,
 3262        scroll_delta: gpui::Point<f32>,
 3263        window: &mut Window,
 3264        cx: &mut Context<Self>,
 3265    ) {
 3266        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3267
 3268        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3269            let tail = tail.to_display_point(&display_map);
 3270            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3271        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3272            let buffer = self.buffer.read(cx).snapshot(cx);
 3273            let head;
 3274            let tail;
 3275            let mode = self.selections.pending_mode().unwrap();
 3276            match &mode {
 3277                SelectMode::Character => {
 3278                    head = position.to_point(&display_map);
 3279                    tail = pending.tail().to_point(&buffer);
 3280                }
 3281                SelectMode::Word(original_range) => {
 3282                    let original_display_range = original_range.start.to_display_point(&display_map)
 3283                        ..original_range.end.to_display_point(&display_map);
 3284                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3285                        ..original_display_range.end.to_point(&display_map);
 3286                    if movement::is_inside_word(&display_map, position)
 3287                        || original_display_range.contains(&position)
 3288                    {
 3289                        let word_range = movement::surrounding_word(&display_map, position);
 3290                        if word_range.start < original_display_range.start {
 3291                            head = word_range.start.to_point(&display_map);
 3292                        } else {
 3293                            head = word_range.end.to_point(&display_map);
 3294                        }
 3295                    } else {
 3296                        head = position.to_point(&display_map);
 3297                    }
 3298
 3299                    if head <= original_buffer_range.start {
 3300                        tail = original_buffer_range.end;
 3301                    } else {
 3302                        tail = original_buffer_range.start;
 3303                    }
 3304                }
 3305                SelectMode::Line(original_range) => {
 3306                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3307
 3308                    let position = display_map
 3309                        .clip_point(position, Bias::Left)
 3310                        .to_point(&display_map);
 3311                    let line_start = display_map.prev_line_boundary(position).0;
 3312                    let next_line_start = buffer.clip_point(
 3313                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3314                        Bias::Left,
 3315                    );
 3316
 3317                    if line_start < original_range.start {
 3318                        head = line_start
 3319                    } else {
 3320                        head = next_line_start
 3321                    }
 3322
 3323                    if head <= original_range.start {
 3324                        tail = original_range.end;
 3325                    } else {
 3326                        tail = original_range.start;
 3327                    }
 3328                }
 3329                SelectMode::All => {
 3330                    return;
 3331                }
 3332            };
 3333
 3334            if head < tail {
 3335                pending.start = buffer.anchor_before(head);
 3336                pending.end = buffer.anchor_before(tail);
 3337                pending.reversed = true;
 3338            } else {
 3339                pending.start = buffer.anchor_before(tail);
 3340                pending.end = buffer.anchor_before(head);
 3341                pending.reversed = false;
 3342            }
 3343
 3344            self.change_selections(None, window, cx, |s| {
 3345                s.set_pending(pending, mode);
 3346            });
 3347        } else {
 3348            log::error!("update_selection dispatched with no pending selection");
 3349            return;
 3350        }
 3351
 3352        self.apply_scroll_delta(scroll_delta, window, cx);
 3353        cx.notify();
 3354    }
 3355
 3356    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3357        self.columnar_selection_tail.take();
 3358        if self.selections.pending_anchor().is_some() {
 3359            let selections = self.selections.all::<usize>(cx);
 3360            self.change_selections(None, window, cx, |s| {
 3361                s.select(selections);
 3362                s.clear_pending();
 3363            });
 3364        }
 3365    }
 3366
 3367    fn select_columns(
 3368        &mut self,
 3369        tail: DisplayPoint,
 3370        head: DisplayPoint,
 3371        goal_column: u32,
 3372        display_map: &DisplaySnapshot,
 3373        window: &mut Window,
 3374        cx: &mut Context<Self>,
 3375    ) {
 3376        let start_row = cmp::min(tail.row(), head.row());
 3377        let end_row = cmp::max(tail.row(), head.row());
 3378        let start_column = cmp::min(tail.column(), goal_column);
 3379        let end_column = cmp::max(tail.column(), goal_column);
 3380        let reversed = start_column < tail.column();
 3381
 3382        let selection_ranges = (start_row.0..=end_row.0)
 3383            .map(DisplayRow)
 3384            .filter_map(|row| {
 3385                if start_column <= display_map.line_len(row) && !display_map.is_block_line(row) {
 3386                    let start = display_map
 3387                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3388                        .to_point(display_map);
 3389                    let end = display_map
 3390                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3391                        .to_point(display_map);
 3392                    if reversed {
 3393                        Some(end..start)
 3394                    } else {
 3395                        Some(start..end)
 3396                    }
 3397                } else {
 3398                    None
 3399                }
 3400            })
 3401            .collect::<Vec<_>>();
 3402
 3403        self.change_selections(None, window, cx, |s| {
 3404            s.select_ranges(selection_ranges);
 3405        });
 3406        cx.notify();
 3407    }
 3408
 3409    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3410        self.selections
 3411            .all_adjusted(cx)
 3412            .iter()
 3413            .any(|selection| !selection.is_empty())
 3414    }
 3415
 3416    pub fn has_pending_nonempty_selection(&self) -> bool {
 3417        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3418            Some(Selection { start, end, .. }) => start != end,
 3419            None => false,
 3420        };
 3421
 3422        pending_nonempty_selection
 3423            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3424    }
 3425
 3426    pub fn has_pending_selection(&self) -> bool {
 3427        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3428    }
 3429
 3430    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3431        self.selection_mark_mode = false;
 3432
 3433        if self.clear_expanded_diff_hunks(cx) {
 3434            cx.notify();
 3435            return;
 3436        }
 3437        if self.dismiss_menus_and_popups(true, window, cx) {
 3438            return;
 3439        }
 3440
 3441        if self.mode.is_full()
 3442            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3443        {
 3444            return;
 3445        }
 3446
 3447        cx.propagate();
 3448    }
 3449
 3450    pub fn dismiss_menus_and_popups(
 3451        &mut self,
 3452        is_user_requested: bool,
 3453        window: &mut Window,
 3454        cx: &mut Context<Self>,
 3455    ) -> bool {
 3456        if self.take_rename(false, window, cx).is_some() {
 3457            return true;
 3458        }
 3459
 3460        if hide_hover(self, cx) {
 3461            return true;
 3462        }
 3463
 3464        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3465            return true;
 3466        }
 3467
 3468        if self.hide_context_menu(window, cx).is_some() {
 3469            return true;
 3470        }
 3471
 3472        if self.mouse_context_menu.take().is_some() {
 3473            return true;
 3474        }
 3475
 3476        if is_user_requested && self.discard_inline_completion(true, cx) {
 3477            return true;
 3478        }
 3479
 3480        if self.snippet_stack.pop().is_some() {
 3481            return true;
 3482        }
 3483
 3484        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3485            self.dismiss_diagnostics(cx);
 3486            return true;
 3487        }
 3488
 3489        false
 3490    }
 3491
 3492    fn linked_editing_ranges_for(
 3493        &self,
 3494        selection: Range<text::Anchor>,
 3495        cx: &App,
 3496    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3497        if self.linked_edit_ranges.is_empty() {
 3498            return None;
 3499        }
 3500        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3501            selection.end.buffer_id.and_then(|end_buffer_id| {
 3502                if selection.start.buffer_id != Some(end_buffer_id) {
 3503                    return None;
 3504                }
 3505                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3506                let snapshot = buffer.read(cx).snapshot();
 3507                self.linked_edit_ranges
 3508                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3509                    .map(|ranges| (ranges, snapshot, buffer))
 3510            })?;
 3511        use text::ToOffset as TO;
 3512        // find offset from the start of current range to current cursor position
 3513        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3514
 3515        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3516        let start_difference = start_offset - start_byte_offset;
 3517        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3518        let end_difference = end_offset - start_byte_offset;
 3519        // Current range has associated linked ranges.
 3520        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3521        for range in linked_ranges.iter() {
 3522            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3523            let end_offset = start_offset + end_difference;
 3524            let start_offset = start_offset + start_difference;
 3525            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3526                continue;
 3527            }
 3528            if self.selections.disjoint_anchor_ranges().any(|s| {
 3529                if s.start.buffer_id != selection.start.buffer_id
 3530                    || s.end.buffer_id != selection.end.buffer_id
 3531                {
 3532                    return false;
 3533                }
 3534                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3535                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3536            }) {
 3537                continue;
 3538            }
 3539            let start = buffer_snapshot.anchor_after(start_offset);
 3540            let end = buffer_snapshot.anchor_after(end_offset);
 3541            linked_edits
 3542                .entry(buffer.clone())
 3543                .or_default()
 3544                .push(start..end);
 3545        }
 3546        Some(linked_edits)
 3547    }
 3548
 3549    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3550        let text: Arc<str> = text.into();
 3551
 3552        if self.read_only(cx) {
 3553            return;
 3554        }
 3555
 3556        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3557
 3558        let selections = self.selections.all_adjusted(cx);
 3559        let mut bracket_inserted = false;
 3560        let mut edits = Vec::new();
 3561        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3562        let mut new_selections = Vec::with_capacity(selections.len());
 3563        let mut new_autoclose_regions = Vec::new();
 3564        let snapshot = self.buffer.read(cx).read(cx);
 3565        let mut clear_linked_edit_ranges = false;
 3566
 3567        for (selection, autoclose_region) in
 3568            self.selections_with_autoclose_regions(selections, &snapshot)
 3569        {
 3570            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3571                // Determine if the inserted text matches the opening or closing
 3572                // bracket of any of this language's bracket pairs.
 3573                let mut bracket_pair = None;
 3574                let mut is_bracket_pair_start = false;
 3575                let mut is_bracket_pair_end = false;
 3576                if !text.is_empty() {
 3577                    let mut bracket_pair_matching_end = None;
 3578                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3579                    //  and they are removing the character that triggered IME popup.
 3580                    for (pair, enabled) in scope.brackets() {
 3581                        if !pair.close && !pair.surround {
 3582                            continue;
 3583                        }
 3584
 3585                        if enabled && pair.start.ends_with(text.as_ref()) {
 3586                            let prefix_len = pair.start.len() - text.len();
 3587                            let preceding_text_matches_prefix = prefix_len == 0
 3588                                || (selection.start.column >= (prefix_len as u32)
 3589                                    && snapshot.contains_str_at(
 3590                                        Point::new(
 3591                                            selection.start.row,
 3592                                            selection.start.column - (prefix_len as u32),
 3593                                        ),
 3594                                        &pair.start[..prefix_len],
 3595                                    ));
 3596                            if preceding_text_matches_prefix {
 3597                                bracket_pair = Some(pair.clone());
 3598                                is_bracket_pair_start = true;
 3599                                break;
 3600                            }
 3601                        }
 3602                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3603                        {
 3604                            // take first bracket pair matching end, but don't break in case a later bracket
 3605                            // pair matches start
 3606                            bracket_pair_matching_end = Some(pair.clone());
 3607                        }
 3608                    }
 3609                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3610                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3611                        is_bracket_pair_end = true;
 3612                    }
 3613                }
 3614
 3615                if let Some(bracket_pair) = bracket_pair {
 3616                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3617                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3618                    let auto_surround =
 3619                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3620                    if selection.is_empty() {
 3621                        if is_bracket_pair_start {
 3622                            // If the inserted text is a suffix of an opening bracket and the
 3623                            // selection is preceded by the rest of the opening bracket, then
 3624                            // insert the closing bracket.
 3625                            let following_text_allows_autoclose = snapshot
 3626                                .chars_at(selection.start)
 3627                                .next()
 3628                                .map_or(true, |c| scope.should_autoclose_before(c));
 3629
 3630                            let preceding_text_allows_autoclose = selection.start.column == 0
 3631                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3632                                    true,
 3633                                    |c| {
 3634                                        bracket_pair.start != bracket_pair.end
 3635                                            || !snapshot
 3636                                                .char_classifier_at(selection.start)
 3637                                                .is_word(c)
 3638                                    },
 3639                                );
 3640
 3641                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3642                                && bracket_pair.start.len() == 1
 3643                            {
 3644                                let target = bracket_pair.start.chars().next().unwrap();
 3645                                let current_line_count = snapshot
 3646                                    .reversed_chars_at(selection.start)
 3647                                    .take_while(|&c| c != '\n')
 3648                                    .filter(|&c| c == target)
 3649                                    .count();
 3650                                current_line_count % 2 == 1
 3651                            } else {
 3652                                false
 3653                            };
 3654
 3655                            if autoclose
 3656                                && bracket_pair.close
 3657                                && following_text_allows_autoclose
 3658                                && preceding_text_allows_autoclose
 3659                                && !is_closing_quote
 3660                            {
 3661                                let anchor = snapshot.anchor_before(selection.end);
 3662                                new_selections.push((selection.map(|_| anchor), text.len()));
 3663                                new_autoclose_regions.push((
 3664                                    anchor,
 3665                                    text.len(),
 3666                                    selection.id,
 3667                                    bracket_pair.clone(),
 3668                                ));
 3669                                edits.push((
 3670                                    selection.range(),
 3671                                    format!("{}{}", text, bracket_pair.end).into(),
 3672                                ));
 3673                                bracket_inserted = true;
 3674                                continue;
 3675                            }
 3676                        }
 3677
 3678                        if let Some(region) = autoclose_region {
 3679                            // If the selection is followed by an auto-inserted closing bracket,
 3680                            // then don't insert that closing bracket again; just move the selection
 3681                            // past the closing bracket.
 3682                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3683                                && text.as_ref() == region.pair.end.as_str();
 3684                            if should_skip {
 3685                                let anchor = snapshot.anchor_after(selection.end);
 3686                                new_selections
 3687                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3688                                continue;
 3689                            }
 3690                        }
 3691
 3692                        let always_treat_brackets_as_autoclosed = snapshot
 3693                            .language_settings_at(selection.start, cx)
 3694                            .always_treat_brackets_as_autoclosed;
 3695                        if always_treat_brackets_as_autoclosed
 3696                            && is_bracket_pair_end
 3697                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3698                        {
 3699                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3700                            // and the inserted text is a closing bracket and the selection is followed
 3701                            // by the closing bracket then move the selection past the closing bracket.
 3702                            let anchor = snapshot.anchor_after(selection.end);
 3703                            new_selections.push((selection.map(|_| anchor), text.len()));
 3704                            continue;
 3705                        }
 3706                    }
 3707                    // If an opening bracket is 1 character long and is typed while
 3708                    // text is selected, then surround that text with the bracket pair.
 3709                    else if auto_surround
 3710                        && bracket_pair.surround
 3711                        && is_bracket_pair_start
 3712                        && bracket_pair.start.chars().count() == 1
 3713                    {
 3714                        edits.push((selection.start..selection.start, text.clone()));
 3715                        edits.push((
 3716                            selection.end..selection.end,
 3717                            bracket_pair.end.as_str().into(),
 3718                        ));
 3719                        bracket_inserted = true;
 3720                        new_selections.push((
 3721                            Selection {
 3722                                id: selection.id,
 3723                                start: snapshot.anchor_after(selection.start),
 3724                                end: snapshot.anchor_before(selection.end),
 3725                                reversed: selection.reversed,
 3726                                goal: selection.goal,
 3727                            },
 3728                            0,
 3729                        ));
 3730                        continue;
 3731                    }
 3732                }
 3733            }
 3734
 3735            if self.auto_replace_emoji_shortcode
 3736                && selection.is_empty()
 3737                && text.as_ref().ends_with(':')
 3738            {
 3739                if let Some(possible_emoji_short_code) =
 3740                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3741                {
 3742                    if !possible_emoji_short_code.is_empty() {
 3743                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3744                            let emoji_shortcode_start = Point::new(
 3745                                selection.start.row,
 3746                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3747                            );
 3748
 3749                            // Remove shortcode from buffer
 3750                            edits.push((
 3751                                emoji_shortcode_start..selection.start,
 3752                                "".to_string().into(),
 3753                            ));
 3754                            new_selections.push((
 3755                                Selection {
 3756                                    id: selection.id,
 3757                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3758                                    end: snapshot.anchor_before(selection.start),
 3759                                    reversed: selection.reversed,
 3760                                    goal: selection.goal,
 3761                                },
 3762                                0,
 3763                            ));
 3764
 3765                            // Insert emoji
 3766                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3767                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3768                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3769
 3770                            continue;
 3771                        }
 3772                    }
 3773                }
 3774            }
 3775
 3776            // If not handling any auto-close operation, then just replace the selected
 3777            // text with the given input and move the selection to the end of the
 3778            // newly inserted text.
 3779            let anchor = snapshot.anchor_after(selection.end);
 3780            if !self.linked_edit_ranges.is_empty() {
 3781                let start_anchor = snapshot.anchor_before(selection.start);
 3782
 3783                let is_word_char = text.chars().next().map_or(true, |char| {
 3784                    let classifier = snapshot
 3785                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3786                        .ignore_punctuation(true);
 3787                    classifier.is_word(char)
 3788                });
 3789
 3790                if is_word_char {
 3791                    if let Some(ranges) = self
 3792                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3793                    {
 3794                        for (buffer, edits) in ranges {
 3795                            linked_edits
 3796                                .entry(buffer.clone())
 3797                                .or_default()
 3798                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3799                        }
 3800                    }
 3801                } else {
 3802                    clear_linked_edit_ranges = true;
 3803                }
 3804            }
 3805
 3806            new_selections.push((selection.map(|_| anchor), 0));
 3807            edits.push((selection.start..selection.end, text.clone()));
 3808        }
 3809
 3810        drop(snapshot);
 3811
 3812        self.transact(window, cx, |this, window, cx| {
 3813            if clear_linked_edit_ranges {
 3814                this.linked_edit_ranges.clear();
 3815            }
 3816            let initial_buffer_versions =
 3817                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3818
 3819            this.buffer.update(cx, |buffer, cx| {
 3820                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3821            });
 3822            for (buffer, edits) in linked_edits {
 3823                buffer.update(cx, |buffer, cx| {
 3824                    let snapshot = buffer.snapshot();
 3825                    let edits = edits
 3826                        .into_iter()
 3827                        .map(|(range, text)| {
 3828                            use text::ToPoint as TP;
 3829                            let end_point = TP::to_point(&range.end, &snapshot);
 3830                            let start_point = TP::to_point(&range.start, &snapshot);
 3831                            (start_point..end_point, text)
 3832                        })
 3833                        .sorted_by_key(|(range, _)| range.start);
 3834                    buffer.edit(edits, None, cx);
 3835                })
 3836            }
 3837            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3838            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3839            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3840            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3841                .zip(new_selection_deltas)
 3842                .map(|(selection, delta)| Selection {
 3843                    id: selection.id,
 3844                    start: selection.start + delta,
 3845                    end: selection.end + delta,
 3846                    reversed: selection.reversed,
 3847                    goal: SelectionGoal::None,
 3848                })
 3849                .collect::<Vec<_>>();
 3850
 3851            let mut i = 0;
 3852            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3853                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3854                let start = map.buffer_snapshot.anchor_before(position);
 3855                let end = map.buffer_snapshot.anchor_after(position);
 3856                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3857                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3858                        Ordering::Less => i += 1,
 3859                        Ordering::Greater => break,
 3860                        Ordering::Equal => {
 3861                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3862                                Ordering::Less => i += 1,
 3863                                Ordering::Equal => break,
 3864                                Ordering::Greater => break,
 3865                            }
 3866                        }
 3867                    }
 3868                }
 3869                this.autoclose_regions.insert(
 3870                    i,
 3871                    AutocloseRegion {
 3872                        selection_id,
 3873                        range: start..end,
 3874                        pair,
 3875                    },
 3876                );
 3877            }
 3878
 3879            let had_active_inline_completion = this.has_active_inline_completion();
 3880            this.change_selections_inner(Some(Autoscroll::fit()), false, window, cx, |s| {
 3881                s.select(new_selections)
 3882            });
 3883
 3884            if !bracket_inserted {
 3885                if let Some(on_type_format_task) =
 3886                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3887                {
 3888                    on_type_format_task.detach_and_log_err(cx);
 3889                }
 3890            }
 3891
 3892            let editor_settings = EditorSettings::get_global(cx);
 3893            if bracket_inserted
 3894                && (editor_settings.auto_signature_help
 3895                    || editor_settings.show_signature_help_after_edits)
 3896            {
 3897                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3898            }
 3899
 3900            let trigger_in_words =
 3901                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3902            if this.hard_wrap.is_some() {
 3903                let latest: Range<Point> = this.selections.newest(cx).range();
 3904                if latest.is_empty()
 3905                    && this
 3906                        .buffer()
 3907                        .read(cx)
 3908                        .snapshot(cx)
 3909                        .line_len(MultiBufferRow(latest.start.row))
 3910                        == latest.start.column
 3911                {
 3912                    this.rewrap_impl(
 3913                        RewrapOptions {
 3914                            override_language_settings: true,
 3915                            preserve_existing_whitespace: true,
 3916                        },
 3917                        cx,
 3918                    )
 3919                }
 3920            }
 3921            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 3922            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 3923            this.refresh_inline_completion(true, false, window, cx);
 3924            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 3925        });
 3926    }
 3927
 3928    fn find_possible_emoji_shortcode_at_position(
 3929        snapshot: &MultiBufferSnapshot,
 3930        position: Point,
 3931    ) -> Option<String> {
 3932        let mut chars = Vec::new();
 3933        let mut found_colon = false;
 3934        for char in snapshot.reversed_chars_at(position).take(100) {
 3935            // Found a possible emoji shortcode in the middle of the buffer
 3936            if found_colon {
 3937                if char.is_whitespace() {
 3938                    chars.reverse();
 3939                    return Some(chars.iter().collect());
 3940                }
 3941                // If the previous character is not a whitespace, we are in the middle of a word
 3942                // and we only want to complete the shortcode if the word is made up of other emojis
 3943                let mut containing_word = String::new();
 3944                for ch in snapshot
 3945                    .reversed_chars_at(position)
 3946                    .skip(chars.len() + 1)
 3947                    .take(100)
 3948                {
 3949                    if ch.is_whitespace() {
 3950                        break;
 3951                    }
 3952                    containing_word.push(ch);
 3953                }
 3954                let containing_word = containing_word.chars().rev().collect::<String>();
 3955                if util::word_consists_of_emojis(containing_word.as_str()) {
 3956                    chars.reverse();
 3957                    return Some(chars.iter().collect());
 3958                }
 3959            }
 3960
 3961            if char.is_whitespace() || !char.is_ascii() {
 3962                return None;
 3963            }
 3964            if char == ':' {
 3965                found_colon = true;
 3966            } else {
 3967                chars.push(char);
 3968            }
 3969        }
 3970        // Found a possible emoji shortcode at the beginning of the buffer
 3971        chars.reverse();
 3972        Some(chars.iter().collect())
 3973    }
 3974
 3975    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 3976        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3977        self.transact(window, cx, |this, window, cx| {
 3978            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 3979                let selections = this.selections.all::<usize>(cx);
 3980                let multi_buffer = this.buffer.read(cx);
 3981                let buffer = multi_buffer.snapshot(cx);
 3982                selections
 3983                    .iter()
 3984                    .map(|selection| {
 3985                        let start_point = selection.start.to_point(&buffer);
 3986                        let mut existing_indent =
 3987                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 3988                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 3989                        let start = selection.start;
 3990                        let end = selection.end;
 3991                        let selection_is_empty = start == end;
 3992                        let language_scope = buffer.language_scope_at(start);
 3993                        let (
 3994                            comment_delimiter,
 3995                            doc_delimiter,
 3996                            insert_extra_newline,
 3997                            indent_on_newline,
 3998                            indent_on_extra_newline,
 3999                        ) = if let Some(language) = &language_scope {
 4000                            let mut insert_extra_newline =
 4001                                insert_extra_newline_brackets(&buffer, start..end, language)
 4002                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4003
 4004                            // Comment extension on newline is allowed only for cursor selections
 4005                            let comment_delimiter = maybe!({
 4006                                if !selection_is_empty {
 4007                                    return None;
 4008                                }
 4009
 4010                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4011                                    return None;
 4012                                }
 4013
 4014                                let delimiters = language.line_comment_prefixes();
 4015                                let max_len_of_delimiter =
 4016                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4017                                let (snapshot, range) =
 4018                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4019
 4020                                let num_of_whitespaces = snapshot
 4021                                    .chars_for_range(range.clone())
 4022                                    .take_while(|c| c.is_whitespace())
 4023                                    .count();
 4024                                let comment_candidate = snapshot
 4025                                    .chars_for_range(range)
 4026                                    .skip(num_of_whitespaces)
 4027                                    .take(max_len_of_delimiter)
 4028                                    .collect::<String>();
 4029                                let (delimiter, trimmed_len) = delimiters
 4030                                    .iter()
 4031                                    .filter_map(|delimiter| {
 4032                                        let prefix = delimiter.trim_end();
 4033                                        if comment_candidate.starts_with(prefix) {
 4034                                            Some((delimiter, prefix.len()))
 4035                                        } else {
 4036                                            None
 4037                                        }
 4038                                    })
 4039                                    .max_by_key(|(_, len)| *len)?;
 4040
 4041                                let cursor_is_placed_after_comment_marker =
 4042                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4043                                if cursor_is_placed_after_comment_marker {
 4044                                    Some(delimiter.clone())
 4045                                } else {
 4046                                    None
 4047                                }
 4048                            });
 4049
 4050                            let mut indent_on_newline = IndentSize::spaces(0);
 4051                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4052
 4053                            let doc_delimiter = maybe!({
 4054                                if !selection_is_empty {
 4055                                    return None;
 4056                                }
 4057
 4058                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4059                                    return None;
 4060                                }
 4061
 4062                                let DocumentationConfig {
 4063                                    start: start_tag,
 4064                                    end: end_tag,
 4065                                    prefix: delimiter,
 4066                                    tab_size: len,
 4067                                } = language.documentation()?;
 4068
 4069                                let is_within_block_comment = buffer
 4070                                    .language_scope_at(start_point)
 4071                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4072                                if !is_within_block_comment {
 4073                                    return None;
 4074                                }
 4075
 4076                                let (snapshot, range) =
 4077                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4078
 4079                                let num_of_whitespaces = snapshot
 4080                                    .chars_for_range(range.clone())
 4081                                    .take_while(|c| c.is_whitespace())
 4082                                    .count();
 4083
 4084                                // 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.
 4085                                let column = start_point.column;
 4086                                let cursor_is_after_start_tag = {
 4087                                    let start_tag_len = start_tag.len();
 4088                                    let start_tag_line = snapshot
 4089                                        .chars_for_range(range.clone())
 4090                                        .skip(num_of_whitespaces)
 4091                                        .take(start_tag_len)
 4092                                        .collect::<String>();
 4093                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4094                                        num_of_whitespaces + start_tag_len <= column as usize
 4095                                    } else {
 4096                                        false
 4097                                    }
 4098                                };
 4099
 4100                                let cursor_is_after_delimiter = {
 4101                                    let delimiter_trim = delimiter.trim_end();
 4102                                    let delimiter_line = snapshot
 4103                                        .chars_for_range(range.clone())
 4104                                        .skip(num_of_whitespaces)
 4105                                        .take(delimiter_trim.len())
 4106                                        .collect::<String>();
 4107                                    if delimiter_line.starts_with(delimiter_trim) {
 4108                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4109                                    } else {
 4110                                        false
 4111                                    }
 4112                                };
 4113
 4114                                let cursor_is_before_end_tag_if_exists = {
 4115                                    let mut char_position = 0u32;
 4116                                    let mut end_tag_offset = None;
 4117
 4118                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4119                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4120                                            let chars_before_match =
 4121                                                chunk[..byte_pos].chars().count() as u32;
 4122                                            end_tag_offset =
 4123                                                Some(char_position + chars_before_match);
 4124                                            break 'outer;
 4125                                        }
 4126                                        char_position += chunk.chars().count() as u32;
 4127                                    }
 4128
 4129                                    if let Some(end_tag_offset) = end_tag_offset {
 4130                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4131                                        if cursor_is_after_start_tag {
 4132                                            if cursor_is_before_end_tag {
 4133                                                insert_extra_newline = true;
 4134                                            }
 4135                                            let cursor_is_at_start_of_end_tag =
 4136                                                column == end_tag_offset;
 4137                                            if cursor_is_at_start_of_end_tag {
 4138                                                indent_on_extra_newline.len = (*len).into();
 4139                                            }
 4140                                        }
 4141                                        cursor_is_before_end_tag
 4142                                    } else {
 4143                                        true
 4144                                    }
 4145                                };
 4146
 4147                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4148                                    && cursor_is_before_end_tag_if_exists
 4149                                {
 4150                                    if cursor_is_after_start_tag {
 4151                                        indent_on_newline.len = (*len).into();
 4152                                    }
 4153                                    Some(delimiter.clone())
 4154                                } else {
 4155                                    None
 4156                                }
 4157                            });
 4158
 4159                            (
 4160                                comment_delimiter,
 4161                                doc_delimiter,
 4162                                insert_extra_newline,
 4163                                indent_on_newline,
 4164                                indent_on_extra_newline,
 4165                            )
 4166                        } else {
 4167                            (
 4168                                None,
 4169                                None,
 4170                                false,
 4171                                IndentSize::default(),
 4172                                IndentSize::default(),
 4173                            )
 4174                        };
 4175
 4176                        let prevent_auto_indent = doc_delimiter.is_some();
 4177                        let delimiter = comment_delimiter.or(doc_delimiter);
 4178
 4179                        let capacity_for_delimiter =
 4180                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4181                        let mut new_text = String::with_capacity(
 4182                            1 + capacity_for_delimiter
 4183                                + existing_indent.len as usize
 4184                                + indent_on_newline.len as usize
 4185                                + indent_on_extra_newline.len as usize,
 4186                        );
 4187                        new_text.push('\n');
 4188                        new_text.extend(existing_indent.chars());
 4189                        new_text.extend(indent_on_newline.chars());
 4190
 4191                        if let Some(delimiter) = &delimiter {
 4192                            new_text.push_str(delimiter);
 4193                        }
 4194
 4195                        if insert_extra_newline {
 4196                            new_text.push('\n');
 4197                            new_text.extend(existing_indent.chars());
 4198                            new_text.extend(indent_on_extra_newline.chars());
 4199                        }
 4200
 4201                        let anchor = buffer.anchor_after(end);
 4202                        let new_selection = selection.map(|_| anchor);
 4203                        (
 4204                            ((start..end, new_text), prevent_auto_indent),
 4205                            (insert_extra_newline, new_selection),
 4206                        )
 4207                    })
 4208                    .unzip()
 4209            };
 4210
 4211            let mut auto_indent_edits = Vec::new();
 4212            let mut edits = Vec::new();
 4213            for (edit, prevent_auto_indent) in edits_with_flags {
 4214                if prevent_auto_indent {
 4215                    edits.push(edit);
 4216                } else {
 4217                    auto_indent_edits.push(edit);
 4218                }
 4219            }
 4220            if !edits.is_empty() {
 4221                this.edit(edits, cx);
 4222            }
 4223            if !auto_indent_edits.is_empty() {
 4224                this.edit_with_autoindent(auto_indent_edits, cx);
 4225            }
 4226
 4227            let buffer = this.buffer.read(cx).snapshot(cx);
 4228            let new_selections = selection_info
 4229                .into_iter()
 4230                .map(|(extra_newline_inserted, new_selection)| {
 4231                    let mut cursor = new_selection.end.to_point(&buffer);
 4232                    if extra_newline_inserted {
 4233                        cursor.row -= 1;
 4234                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4235                    }
 4236                    new_selection.map(|_| cursor)
 4237                })
 4238                .collect();
 4239
 4240            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4241                s.select(new_selections)
 4242            });
 4243            this.refresh_inline_completion(true, false, window, cx);
 4244        });
 4245    }
 4246
 4247    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4248        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4249
 4250        let buffer = self.buffer.read(cx);
 4251        let snapshot = buffer.snapshot(cx);
 4252
 4253        let mut edits = Vec::new();
 4254        let mut rows = Vec::new();
 4255
 4256        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4257            let cursor = selection.head();
 4258            let row = cursor.row;
 4259
 4260            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4261
 4262            let newline = "\n".to_string();
 4263            edits.push((start_of_line..start_of_line, newline));
 4264
 4265            rows.push(row + rows_inserted as u32);
 4266        }
 4267
 4268        self.transact(window, cx, |editor, window, cx| {
 4269            editor.edit(edits, cx);
 4270
 4271            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4272                let mut index = 0;
 4273                s.move_cursors_with(|map, _, _| {
 4274                    let row = rows[index];
 4275                    index += 1;
 4276
 4277                    let point = Point::new(row, 0);
 4278                    let boundary = map.next_line_boundary(point).1;
 4279                    let clipped = map.clip_point(boundary, Bias::Left);
 4280
 4281                    (clipped, SelectionGoal::None)
 4282                });
 4283            });
 4284
 4285            let mut indent_edits = Vec::new();
 4286            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4287            for row in rows {
 4288                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4289                for (row, indent) in indents {
 4290                    if indent.len == 0 {
 4291                        continue;
 4292                    }
 4293
 4294                    let text = match indent.kind {
 4295                        IndentKind::Space => " ".repeat(indent.len as usize),
 4296                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4297                    };
 4298                    let point = Point::new(row.0, 0);
 4299                    indent_edits.push((point..point, text));
 4300                }
 4301            }
 4302            editor.edit(indent_edits, cx);
 4303        });
 4304    }
 4305
 4306    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4307        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4308
 4309        let buffer = self.buffer.read(cx);
 4310        let snapshot = buffer.snapshot(cx);
 4311
 4312        let mut edits = Vec::new();
 4313        let mut rows = Vec::new();
 4314        let mut rows_inserted = 0;
 4315
 4316        for selection in self.selections.all_adjusted(cx) {
 4317            let cursor = selection.head();
 4318            let row = cursor.row;
 4319
 4320            let point = Point::new(row + 1, 0);
 4321            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4322
 4323            let newline = "\n".to_string();
 4324            edits.push((start_of_line..start_of_line, newline));
 4325
 4326            rows_inserted += 1;
 4327            rows.push(row + rows_inserted);
 4328        }
 4329
 4330        self.transact(window, cx, |editor, window, cx| {
 4331            editor.edit(edits, cx);
 4332
 4333            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4334                let mut index = 0;
 4335                s.move_cursors_with(|map, _, _| {
 4336                    let row = rows[index];
 4337                    index += 1;
 4338
 4339                    let point = Point::new(row, 0);
 4340                    let boundary = map.next_line_boundary(point).1;
 4341                    let clipped = map.clip_point(boundary, Bias::Left);
 4342
 4343                    (clipped, SelectionGoal::None)
 4344                });
 4345            });
 4346
 4347            let mut indent_edits = Vec::new();
 4348            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4349            for row in rows {
 4350                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4351                for (row, indent) in indents {
 4352                    if indent.len == 0 {
 4353                        continue;
 4354                    }
 4355
 4356                    let text = match indent.kind {
 4357                        IndentKind::Space => " ".repeat(indent.len as usize),
 4358                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4359                    };
 4360                    let point = Point::new(row.0, 0);
 4361                    indent_edits.push((point..point, text));
 4362                }
 4363            }
 4364            editor.edit(indent_edits, cx);
 4365        });
 4366    }
 4367
 4368    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4369        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4370            original_indent_columns: Vec::new(),
 4371        });
 4372        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4373    }
 4374
 4375    fn insert_with_autoindent_mode(
 4376        &mut self,
 4377        text: &str,
 4378        autoindent_mode: Option<AutoindentMode>,
 4379        window: &mut Window,
 4380        cx: &mut Context<Self>,
 4381    ) {
 4382        if self.read_only(cx) {
 4383            return;
 4384        }
 4385
 4386        let text: Arc<str> = text.into();
 4387        self.transact(window, cx, |this, window, cx| {
 4388            let old_selections = this.selections.all_adjusted(cx);
 4389            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4390                let anchors = {
 4391                    let snapshot = buffer.read(cx);
 4392                    old_selections
 4393                        .iter()
 4394                        .map(|s| {
 4395                            let anchor = snapshot.anchor_after(s.head());
 4396                            s.map(|_| anchor)
 4397                        })
 4398                        .collect::<Vec<_>>()
 4399                };
 4400                buffer.edit(
 4401                    old_selections
 4402                        .iter()
 4403                        .map(|s| (s.start..s.end, text.clone())),
 4404                    autoindent_mode,
 4405                    cx,
 4406                );
 4407                anchors
 4408            });
 4409
 4410            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4411                s.select_anchors(selection_anchors);
 4412            });
 4413
 4414            cx.notify();
 4415        });
 4416    }
 4417
 4418    fn trigger_completion_on_input(
 4419        &mut self,
 4420        text: &str,
 4421        trigger_in_words: bool,
 4422        window: &mut Window,
 4423        cx: &mut Context<Self>,
 4424    ) {
 4425        let ignore_completion_provider = self
 4426            .context_menu
 4427            .borrow()
 4428            .as_ref()
 4429            .map(|menu| match menu {
 4430                CodeContextMenu::Completions(completions_menu) => {
 4431                    completions_menu.ignore_completion_provider
 4432                }
 4433                CodeContextMenu::CodeActions(_) => false,
 4434            })
 4435            .unwrap_or(false);
 4436
 4437        if ignore_completion_provider {
 4438            self.show_word_completions(&ShowWordCompletions, window, cx);
 4439        } else if self.is_completion_trigger(text, trigger_in_words, cx) {
 4440            self.show_completions(
 4441                &ShowCompletions {
 4442                    trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4443                },
 4444                window,
 4445                cx,
 4446            );
 4447        } else {
 4448            self.hide_context_menu(window, cx);
 4449        }
 4450    }
 4451
 4452    fn is_completion_trigger(
 4453        &self,
 4454        text: &str,
 4455        trigger_in_words: bool,
 4456        cx: &mut Context<Self>,
 4457    ) -> bool {
 4458        let position = self.selections.newest_anchor().head();
 4459        let multibuffer = self.buffer.read(cx);
 4460        let Some(buffer) = position
 4461            .buffer_id
 4462            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4463        else {
 4464            return false;
 4465        };
 4466
 4467        if let Some(completion_provider) = &self.completion_provider {
 4468            completion_provider.is_completion_trigger(
 4469                &buffer,
 4470                position.text_anchor,
 4471                text,
 4472                trigger_in_words,
 4473                cx,
 4474            )
 4475        } else {
 4476            false
 4477        }
 4478    }
 4479
 4480    /// If any empty selections is touching the start of its innermost containing autoclose
 4481    /// region, expand it to select the brackets.
 4482    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4483        let selections = self.selections.all::<usize>(cx);
 4484        let buffer = self.buffer.read(cx).read(cx);
 4485        let new_selections = self
 4486            .selections_with_autoclose_regions(selections, &buffer)
 4487            .map(|(mut selection, region)| {
 4488                if !selection.is_empty() {
 4489                    return selection;
 4490                }
 4491
 4492                if let Some(region) = region {
 4493                    let mut range = region.range.to_offset(&buffer);
 4494                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4495                        range.start -= region.pair.start.len();
 4496                        if buffer.contains_str_at(range.start, &region.pair.start)
 4497                            && buffer.contains_str_at(range.end, &region.pair.end)
 4498                        {
 4499                            range.end += region.pair.end.len();
 4500                            selection.start = range.start;
 4501                            selection.end = range.end;
 4502
 4503                            return selection;
 4504                        }
 4505                    }
 4506                }
 4507
 4508                let always_treat_brackets_as_autoclosed = buffer
 4509                    .language_settings_at(selection.start, cx)
 4510                    .always_treat_brackets_as_autoclosed;
 4511
 4512                if !always_treat_brackets_as_autoclosed {
 4513                    return selection;
 4514                }
 4515
 4516                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4517                    for (pair, enabled) in scope.brackets() {
 4518                        if !enabled || !pair.close {
 4519                            continue;
 4520                        }
 4521
 4522                        if buffer.contains_str_at(selection.start, &pair.end) {
 4523                            let pair_start_len = pair.start.len();
 4524                            if buffer.contains_str_at(
 4525                                selection.start.saturating_sub(pair_start_len),
 4526                                &pair.start,
 4527                            ) {
 4528                                selection.start -= pair_start_len;
 4529                                selection.end += pair.end.len();
 4530
 4531                                return selection;
 4532                            }
 4533                        }
 4534                    }
 4535                }
 4536
 4537                selection
 4538            })
 4539            .collect();
 4540
 4541        drop(buffer);
 4542        self.change_selections(None, window, cx, |selections| {
 4543            selections.select(new_selections)
 4544        });
 4545    }
 4546
 4547    /// Iterate the given selections, and for each one, find the smallest surrounding
 4548    /// autoclose region. This uses the ordering of the selections and the autoclose
 4549    /// regions to avoid repeated comparisons.
 4550    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4551        &'a self,
 4552        selections: impl IntoIterator<Item = Selection<D>>,
 4553        buffer: &'a MultiBufferSnapshot,
 4554    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4555        let mut i = 0;
 4556        let mut regions = self.autoclose_regions.as_slice();
 4557        selections.into_iter().map(move |selection| {
 4558            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4559
 4560            let mut enclosing = None;
 4561            while let Some(pair_state) = regions.get(i) {
 4562                if pair_state.range.end.to_offset(buffer) < range.start {
 4563                    regions = &regions[i + 1..];
 4564                    i = 0;
 4565                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4566                    break;
 4567                } else {
 4568                    if pair_state.selection_id == selection.id {
 4569                        enclosing = Some(pair_state);
 4570                    }
 4571                    i += 1;
 4572                }
 4573            }
 4574
 4575            (selection, enclosing)
 4576        })
 4577    }
 4578
 4579    /// Remove any autoclose regions that no longer contain their selection.
 4580    fn invalidate_autoclose_regions(
 4581        &mut self,
 4582        mut selections: &[Selection<Anchor>],
 4583        buffer: &MultiBufferSnapshot,
 4584    ) {
 4585        self.autoclose_regions.retain(|state| {
 4586            let mut i = 0;
 4587            while let Some(selection) = selections.get(i) {
 4588                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4589                    selections = &selections[1..];
 4590                    continue;
 4591                }
 4592                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4593                    break;
 4594                }
 4595                if selection.id == state.selection_id {
 4596                    return true;
 4597                } else {
 4598                    i += 1;
 4599                }
 4600            }
 4601            false
 4602        });
 4603    }
 4604
 4605    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4606        let offset = position.to_offset(buffer);
 4607        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4608        if offset > word_range.start && kind == Some(CharKind::Word) {
 4609            Some(
 4610                buffer
 4611                    .text_for_range(word_range.start..offset)
 4612                    .collect::<String>(),
 4613            )
 4614        } else {
 4615            None
 4616        }
 4617    }
 4618
 4619    pub fn toggle_inline_values(
 4620        &mut self,
 4621        _: &ToggleInlineValues,
 4622        _: &mut Window,
 4623        cx: &mut Context<Self>,
 4624    ) {
 4625        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4626
 4627        self.refresh_inline_values(cx);
 4628    }
 4629
 4630    pub fn toggle_inlay_hints(
 4631        &mut self,
 4632        _: &ToggleInlayHints,
 4633        _: &mut Window,
 4634        cx: &mut Context<Self>,
 4635    ) {
 4636        self.refresh_inlay_hints(
 4637            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4638            cx,
 4639        );
 4640    }
 4641
 4642    pub fn inlay_hints_enabled(&self) -> bool {
 4643        self.inlay_hint_cache.enabled
 4644    }
 4645
 4646    pub fn inline_values_enabled(&self) -> bool {
 4647        self.inline_value_cache.enabled
 4648    }
 4649
 4650    #[cfg(any(test, feature = "test-support"))]
 4651    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4652        self.display_map
 4653            .read(cx)
 4654            .current_inlays()
 4655            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4656            .cloned()
 4657            .collect()
 4658    }
 4659
 4660    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4661        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4662            return;
 4663        }
 4664
 4665        let reason_description = reason.description();
 4666        let ignore_debounce = matches!(
 4667            reason,
 4668            InlayHintRefreshReason::SettingsChange(_)
 4669                | InlayHintRefreshReason::Toggle(_)
 4670                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4671                | InlayHintRefreshReason::ModifiersChanged(_)
 4672        );
 4673        let (invalidate_cache, required_languages) = match reason {
 4674            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4675                match self.inlay_hint_cache.modifiers_override(enabled) {
 4676                    Some(enabled) => {
 4677                        if enabled {
 4678                            (InvalidationStrategy::RefreshRequested, None)
 4679                        } else {
 4680                            self.splice_inlays(
 4681                                &self
 4682                                    .visible_inlay_hints(cx)
 4683                                    .iter()
 4684                                    .map(|inlay| inlay.id)
 4685                                    .collect::<Vec<InlayId>>(),
 4686                                Vec::new(),
 4687                                cx,
 4688                            );
 4689                            return;
 4690                        }
 4691                    }
 4692                    None => return,
 4693                }
 4694            }
 4695            InlayHintRefreshReason::Toggle(enabled) => {
 4696                if self.inlay_hint_cache.toggle(enabled) {
 4697                    if enabled {
 4698                        (InvalidationStrategy::RefreshRequested, None)
 4699                    } else {
 4700                        self.splice_inlays(
 4701                            &self
 4702                                .visible_inlay_hints(cx)
 4703                                .iter()
 4704                                .map(|inlay| inlay.id)
 4705                                .collect::<Vec<InlayId>>(),
 4706                            Vec::new(),
 4707                            cx,
 4708                        );
 4709                        return;
 4710                    }
 4711                } else {
 4712                    return;
 4713                }
 4714            }
 4715            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4716                match self.inlay_hint_cache.update_settings(
 4717                    &self.buffer,
 4718                    new_settings,
 4719                    self.visible_inlay_hints(cx),
 4720                    cx,
 4721                ) {
 4722                    ControlFlow::Break(Some(InlaySplice {
 4723                        to_remove,
 4724                        to_insert,
 4725                    })) => {
 4726                        self.splice_inlays(&to_remove, to_insert, cx);
 4727                        return;
 4728                    }
 4729                    ControlFlow::Break(None) => return,
 4730                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4731                }
 4732            }
 4733            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4734                if let Some(InlaySplice {
 4735                    to_remove,
 4736                    to_insert,
 4737                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4738                {
 4739                    self.splice_inlays(&to_remove, to_insert, cx);
 4740                }
 4741                self.display_map.update(cx, |display_map, _| {
 4742                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4743                });
 4744                return;
 4745            }
 4746            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4747            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4748                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4749            }
 4750            InlayHintRefreshReason::RefreshRequested => {
 4751                (InvalidationStrategy::RefreshRequested, None)
 4752            }
 4753        };
 4754
 4755        if let Some(InlaySplice {
 4756            to_remove,
 4757            to_insert,
 4758        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4759            reason_description,
 4760            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4761            invalidate_cache,
 4762            ignore_debounce,
 4763            cx,
 4764        ) {
 4765            self.splice_inlays(&to_remove, to_insert, cx);
 4766        }
 4767    }
 4768
 4769    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4770        self.display_map
 4771            .read(cx)
 4772            .current_inlays()
 4773            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4774            .cloned()
 4775            .collect()
 4776    }
 4777
 4778    pub fn excerpts_for_inlay_hints_query(
 4779        &self,
 4780        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4781        cx: &mut Context<Editor>,
 4782    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4783        let Some(project) = self.project.as_ref() else {
 4784            return HashMap::default();
 4785        };
 4786        let project = project.read(cx);
 4787        let multi_buffer = self.buffer().read(cx);
 4788        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4789        let multi_buffer_visible_start = self
 4790            .scroll_manager
 4791            .anchor()
 4792            .anchor
 4793            .to_point(&multi_buffer_snapshot);
 4794        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4795            multi_buffer_visible_start
 4796                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4797            Bias::Left,
 4798        );
 4799        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4800        multi_buffer_snapshot
 4801            .range_to_buffer_ranges(multi_buffer_visible_range)
 4802            .into_iter()
 4803            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4804            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4805                let buffer_file = project::File::from_dyn(buffer.file())?;
 4806                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4807                let worktree_entry = buffer_worktree
 4808                    .read(cx)
 4809                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4810                if worktree_entry.is_ignored {
 4811                    return None;
 4812                }
 4813
 4814                let language = buffer.language()?;
 4815                if let Some(restrict_to_languages) = restrict_to_languages {
 4816                    if !restrict_to_languages.contains(language) {
 4817                        return None;
 4818                    }
 4819                }
 4820                Some((
 4821                    excerpt_id,
 4822                    (
 4823                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4824                        buffer.version().clone(),
 4825                        excerpt_visible_range,
 4826                    ),
 4827                ))
 4828            })
 4829            .collect()
 4830    }
 4831
 4832    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4833        TextLayoutDetails {
 4834            text_system: window.text_system().clone(),
 4835            editor_style: self.style.clone().unwrap(),
 4836            rem_size: window.rem_size(),
 4837            scroll_anchor: self.scroll_manager.anchor(),
 4838            visible_rows: self.visible_line_count(),
 4839            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4840        }
 4841    }
 4842
 4843    pub fn splice_inlays(
 4844        &self,
 4845        to_remove: &[InlayId],
 4846        to_insert: Vec<Inlay>,
 4847        cx: &mut Context<Self>,
 4848    ) {
 4849        self.display_map.update(cx, |display_map, cx| {
 4850            display_map.splice_inlays(to_remove, to_insert, cx)
 4851        });
 4852        cx.notify();
 4853    }
 4854
 4855    fn trigger_on_type_formatting(
 4856        &self,
 4857        input: String,
 4858        window: &mut Window,
 4859        cx: &mut Context<Self>,
 4860    ) -> Option<Task<Result<()>>> {
 4861        if input.len() != 1 {
 4862            return None;
 4863        }
 4864
 4865        let project = self.project.as_ref()?;
 4866        let position = self.selections.newest_anchor().head();
 4867        let (buffer, buffer_position) = self
 4868            .buffer
 4869            .read(cx)
 4870            .text_anchor_for_position(position, cx)?;
 4871
 4872        let settings = language_settings::language_settings(
 4873            buffer
 4874                .read(cx)
 4875                .language_at(buffer_position)
 4876                .map(|l| l.name()),
 4877            buffer.read(cx).file(),
 4878            cx,
 4879        );
 4880        if !settings.use_on_type_format {
 4881            return None;
 4882        }
 4883
 4884        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4885        // hence we do LSP request & edit on host side only — add formats to host's history.
 4886        let push_to_lsp_host_history = true;
 4887        // If this is not the host, append its history with new edits.
 4888        let push_to_client_history = project.read(cx).is_via_collab();
 4889
 4890        let on_type_formatting = project.update(cx, |project, cx| {
 4891            project.on_type_format(
 4892                buffer.clone(),
 4893                buffer_position,
 4894                input,
 4895                push_to_lsp_host_history,
 4896                cx,
 4897            )
 4898        });
 4899        Some(cx.spawn_in(window, async move |editor, cx| {
 4900            if let Some(transaction) = on_type_formatting.await? {
 4901                if push_to_client_history {
 4902                    buffer
 4903                        .update(cx, |buffer, _| {
 4904                            buffer.push_transaction(transaction, Instant::now());
 4905                            buffer.finalize_last_transaction();
 4906                        })
 4907                        .ok();
 4908                }
 4909                editor.update(cx, |editor, cx| {
 4910                    editor.refresh_document_highlights(cx);
 4911                })?;
 4912            }
 4913            Ok(())
 4914        }))
 4915    }
 4916
 4917    pub fn show_word_completions(
 4918        &mut self,
 4919        _: &ShowWordCompletions,
 4920        window: &mut Window,
 4921        cx: &mut Context<Self>,
 4922    ) {
 4923        self.open_completions_menu(true, None, window, cx);
 4924    }
 4925
 4926    pub fn show_completions(
 4927        &mut self,
 4928        options: &ShowCompletions,
 4929        window: &mut Window,
 4930        cx: &mut Context<Self>,
 4931    ) {
 4932        self.open_completions_menu(false, options.trigger.as_deref(), window, cx);
 4933    }
 4934
 4935    fn open_completions_menu(
 4936        &mut self,
 4937        ignore_completion_provider: bool,
 4938        trigger: Option<&str>,
 4939        window: &mut Window,
 4940        cx: &mut Context<Self>,
 4941    ) {
 4942        if self.pending_rename.is_some() {
 4943            return;
 4944        }
 4945        if !self.snippet_stack.is_empty() && self.context_menu.borrow().as_ref().is_some() {
 4946            return;
 4947        }
 4948
 4949        let position = self.selections.newest_anchor().head();
 4950        if position.diff_base_anchor.is_some() {
 4951            return;
 4952        }
 4953        let (buffer, buffer_position) =
 4954            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 4955                output
 4956            } else {
 4957                return;
 4958            };
 4959        let buffer_snapshot = buffer.read(cx).snapshot();
 4960        let show_completion_documentation = buffer_snapshot
 4961            .settings_at(buffer_position, cx)
 4962            .show_completion_documentation;
 4963
 4964        let query = Self::completion_query(&self.buffer.read(cx).read(cx), position);
 4965
 4966        let trigger_kind = match trigger {
 4967            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 4968                CompletionTriggerKind::TRIGGER_CHARACTER
 4969            }
 4970            _ => CompletionTriggerKind::INVOKED,
 4971        };
 4972        let completion_context = CompletionContext {
 4973            trigger_character: trigger.and_then(|trigger| {
 4974                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 4975                    Some(String::from(trigger))
 4976                } else {
 4977                    None
 4978                }
 4979            }),
 4980            trigger_kind,
 4981        };
 4982
 4983        let (old_range, word_kind) = buffer_snapshot.surrounding_word(buffer_position);
 4984        let (old_range, word_to_exclude) = if word_kind == Some(CharKind::Word) {
 4985            let word_to_exclude = buffer_snapshot
 4986                .text_for_range(old_range.clone())
 4987                .collect::<String>();
 4988            (
 4989                buffer_snapshot.anchor_before(old_range.start)
 4990                    ..buffer_snapshot.anchor_after(old_range.end),
 4991                Some(word_to_exclude),
 4992            )
 4993        } else {
 4994            (buffer_position..buffer_position, None)
 4995        };
 4996
 4997        let language = buffer_snapshot
 4998            .language_at(buffer_position)
 4999            .map(|language| language.name());
 5000
 5001        let completion_settings =
 5002            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5003
 5004        // The document can be large, so stay in reasonable bounds when searching for words,
 5005        // otherwise completion pop-up might be slow to appear.
 5006        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5007        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5008        let min_word_search = buffer_snapshot.clip_point(
 5009            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5010            Bias::Left,
 5011        );
 5012        let max_word_search = buffer_snapshot.clip_point(
 5013            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5014            Bias::Right,
 5015        );
 5016        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5017            ..buffer_snapshot.point_to_offset(max_word_search);
 5018
 5019        let provider = if ignore_completion_provider {
 5020            None
 5021        } else {
 5022            self.completion_provider.clone()
 5023        };
 5024        let skip_digits = query
 5025            .as_ref()
 5026            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5027
 5028        let (mut words, provided_completions) = match &provider {
 5029            Some(provider) => {
 5030                let completions = provider.completions(
 5031                    position.excerpt_id,
 5032                    &buffer,
 5033                    buffer_position,
 5034                    completion_context,
 5035                    window,
 5036                    cx,
 5037                );
 5038
 5039                let words = match completion_settings.words {
 5040                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5041                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5042                        .background_spawn(async move {
 5043                            buffer_snapshot.words_in_range(WordsQuery {
 5044                                fuzzy_contents: None,
 5045                                range: word_search_range,
 5046                                skip_digits,
 5047                            })
 5048                        }),
 5049                };
 5050
 5051                (words, completions)
 5052            }
 5053            None => (
 5054                cx.background_spawn(async move {
 5055                    buffer_snapshot.words_in_range(WordsQuery {
 5056                        fuzzy_contents: None,
 5057                        range: word_search_range,
 5058                        skip_digits,
 5059                    })
 5060                }),
 5061                Task::ready(Ok(None)),
 5062            ),
 5063        };
 5064
 5065        let sort_completions = provider
 5066            .as_ref()
 5067            .map_or(false, |provider| provider.sort_completions());
 5068
 5069        let filter_completions = provider
 5070            .as_ref()
 5071            .map_or(true, |provider| provider.filter_completions());
 5072
 5073        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5074
 5075        let id = post_inc(&mut self.next_completion_id);
 5076        let task = cx.spawn_in(window, async move |editor, cx| {
 5077            async move {
 5078                editor.update(cx, |this, _| {
 5079                    this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5080                })?;
 5081
 5082                let mut completions = Vec::new();
 5083                if let Some(provided_completions) = provided_completions.await.log_err().flatten() {
 5084                    completions.extend(provided_completions);
 5085                    if completion_settings.words == WordsCompletionMode::Fallback {
 5086                        words = Task::ready(BTreeMap::default());
 5087                    }
 5088                }
 5089
 5090                let mut words = words.await;
 5091                if let Some(word_to_exclude) = &word_to_exclude {
 5092                    words.remove(word_to_exclude);
 5093                }
 5094                for lsp_completion in &completions {
 5095                    words.remove(&lsp_completion.new_text);
 5096                }
 5097                completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5098                    replace_range: old_range.clone(),
 5099                    new_text: word.clone(),
 5100                    label: CodeLabel::plain(word, None),
 5101                    icon_path: None,
 5102                    documentation: None,
 5103                    source: CompletionSource::BufferWord {
 5104                        word_range,
 5105                        resolved: false,
 5106                    },
 5107                    insert_text_mode: Some(InsertTextMode::AS_IS),
 5108                    confirm: None,
 5109                }));
 5110
 5111                let menu = if completions.is_empty() {
 5112                    None
 5113                } else {
 5114                    let mut menu = editor.update(cx, |editor, cx| {
 5115                        let languages = editor
 5116                            .workspace
 5117                            .as_ref()
 5118                            .and_then(|(workspace, _)| workspace.upgrade())
 5119                            .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5120                        CompletionsMenu::new(
 5121                            id,
 5122                            sort_completions,
 5123                            show_completion_documentation,
 5124                            ignore_completion_provider,
 5125                            position,
 5126                            buffer.clone(),
 5127                            completions.into(),
 5128                            snippet_sort_order,
 5129                            languages,
 5130                            language,
 5131                            cx,
 5132                        )
 5133                    })?;
 5134
 5135                    menu.filter(
 5136                        if filter_completions {
 5137                            query.as_deref()
 5138                        } else {
 5139                            None
 5140                        },
 5141                        provider,
 5142                        editor.clone(),
 5143                        cx,
 5144                    )
 5145                    .await;
 5146
 5147                    menu.visible().then_some(menu)
 5148                };
 5149
 5150                editor.update_in(cx, |editor, window, cx| {
 5151                    match editor.context_menu.borrow().as_ref() {
 5152                        None => {}
 5153                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5154                            if prev_menu.id > id {
 5155                                return;
 5156                            }
 5157                        }
 5158                        _ => return,
 5159                    }
 5160
 5161                    if editor.focus_handle.is_focused(window) && menu.is_some() {
 5162                        let mut menu = menu.unwrap();
 5163                        menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
 5164                        crate::hover_popover::hide_hover(editor, cx);
 5165                        *editor.context_menu.borrow_mut() =
 5166                            Some(CodeContextMenu::Completions(menu));
 5167
 5168                        if editor.show_edit_predictions_in_menu() {
 5169                            editor.update_visible_inline_completion(window, cx);
 5170                        } else {
 5171                            editor.discard_inline_completion(false, cx);
 5172                        }
 5173
 5174                        cx.notify();
 5175                    } else if editor.completion_tasks.len() <= 1 {
 5176                        // If there are no more completion tasks and the last menu was
 5177                        // empty, we should hide it.
 5178                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5179                        // If it was already hidden and we don't show inline
 5180                        // completions in the menu, we should also show the
 5181                        // inline-completion when available.
 5182                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5183                            editor.update_visible_inline_completion(window, cx);
 5184                        }
 5185                    }
 5186                })?;
 5187
 5188                anyhow::Ok(())
 5189            }
 5190            .log_err()
 5191            .await
 5192        });
 5193
 5194        self.completion_tasks.push((id, task));
 5195    }
 5196
 5197    #[cfg(feature = "test-support")]
 5198    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5199        let menu = self.context_menu.borrow();
 5200        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5201            let completions = menu.completions.borrow();
 5202            Some(completions.to_vec())
 5203        } else {
 5204            None
 5205        }
 5206    }
 5207
 5208    pub fn with_completions_menu_matching_id<R>(
 5209        &self,
 5210        id: CompletionId,
 5211        on_absent: impl FnOnce() -> R,
 5212        on_match: impl FnOnce(&mut CompletionsMenu) -> R,
 5213    ) -> R {
 5214        let mut context_menu = self.context_menu.borrow_mut();
 5215        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5216            return on_absent();
 5217        };
 5218        if completions_menu.id != id {
 5219            return on_absent();
 5220        }
 5221        on_match(completions_menu)
 5222    }
 5223
 5224    pub fn confirm_completion(
 5225        &mut self,
 5226        action: &ConfirmCompletion,
 5227        window: &mut Window,
 5228        cx: &mut Context<Self>,
 5229    ) -> Option<Task<Result<()>>> {
 5230        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5231        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5232    }
 5233
 5234    pub fn confirm_completion_insert(
 5235        &mut self,
 5236        _: &ConfirmCompletionInsert,
 5237        window: &mut Window,
 5238        cx: &mut Context<Self>,
 5239    ) -> Option<Task<Result<()>>> {
 5240        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5241        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5242    }
 5243
 5244    pub fn confirm_completion_replace(
 5245        &mut self,
 5246        _: &ConfirmCompletionReplace,
 5247        window: &mut Window,
 5248        cx: &mut Context<Self>,
 5249    ) -> Option<Task<Result<()>>> {
 5250        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5251        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5252    }
 5253
 5254    pub fn compose_completion(
 5255        &mut self,
 5256        action: &ComposeCompletion,
 5257        window: &mut Window,
 5258        cx: &mut Context<Self>,
 5259    ) -> Option<Task<Result<()>>> {
 5260        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5261        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5262    }
 5263
 5264    fn do_completion(
 5265        &mut self,
 5266        item_ix: Option<usize>,
 5267        intent: CompletionIntent,
 5268        window: &mut Window,
 5269        cx: &mut Context<Editor>,
 5270    ) -> Option<Task<Result<()>>> {
 5271        use language::ToOffset as _;
 5272
 5273        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5274        else {
 5275            return None;
 5276        };
 5277
 5278        let candidate_id = {
 5279            let entries = completions_menu.entries.borrow();
 5280            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5281            if self.show_edit_predictions_in_menu() {
 5282                self.discard_inline_completion(true, cx);
 5283            }
 5284            mat.candidate_id
 5285        };
 5286
 5287        let buffer_handle = completions_menu.buffer;
 5288        let completion = completions_menu
 5289            .completions
 5290            .borrow()
 5291            .get(candidate_id)?
 5292            .clone();
 5293        cx.stop_propagation();
 5294
 5295        let snapshot = self.buffer.read(cx).snapshot(cx);
 5296        let newest_anchor = self.selections.newest_anchor();
 5297
 5298        let snippet;
 5299        let new_text;
 5300        if completion.is_snippet() {
 5301            let mut snippet_source = completion.new_text.clone();
 5302            if let Some(scope) = snapshot.language_scope_at(newest_anchor.head()) {
 5303                if scope.prefers_label_for_snippet_in_completion() {
 5304                    if let Some(label) = completion.label() {
 5305                        if matches!(
 5306                            completion.kind(),
 5307                            Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
 5308                        ) {
 5309                            snippet_source = label;
 5310                        }
 5311                    }
 5312                }
 5313            }
 5314            snippet = Some(Snippet::parse(&snippet_source).log_err()?);
 5315            new_text = snippet.as_ref().unwrap().text.clone();
 5316        } else {
 5317            snippet = None;
 5318            new_text = completion.new_text.clone();
 5319        };
 5320
 5321        let replace_range = choose_completion_range(&completion, intent, &buffer_handle, cx);
 5322        let buffer = buffer_handle.read(cx);
 5323        let replace_range_multibuffer = {
 5324            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5325            let multibuffer_anchor = snapshot
 5326                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5327                .unwrap()
 5328                ..snapshot
 5329                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5330                    .unwrap();
 5331            multibuffer_anchor.start.to_offset(&snapshot)
 5332                ..multibuffer_anchor.end.to_offset(&snapshot)
 5333        };
 5334        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5335            return None;
 5336        }
 5337
 5338        let old_text = buffer
 5339            .text_for_range(replace_range.clone())
 5340            .collect::<String>();
 5341        let lookbehind = newest_anchor
 5342            .start
 5343            .text_anchor
 5344            .to_offset(buffer)
 5345            .saturating_sub(replace_range.start);
 5346        let lookahead = replace_range
 5347            .end
 5348            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5349        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5350        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5351
 5352        let selections = self.selections.all::<usize>(cx);
 5353        let mut ranges = Vec::new();
 5354        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5355
 5356        for selection in &selections {
 5357            let range = if selection.id == newest_anchor.id {
 5358                replace_range_multibuffer.clone()
 5359            } else {
 5360                let mut range = selection.range();
 5361
 5362                // if prefix is present, don't duplicate it
 5363                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5364                    range.start = range.start.saturating_sub(lookbehind);
 5365
 5366                    // if suffix is also present, mimic the newest cursor and replace it
 5367                    if selection.id != newest_anchor.id
 5368                        && snapshot.contains_str_at(range.end, suffix)
 5369                    {
 5370                        range.end += lookahead;
 5371                    }
 5372                }
 5373                range
 5374            };
 5375
 5376            ranges.push(range.clone());
 5377
 5378            if !self.linked_edit_ranges.is_empty() {
 5379                let start_anchor = snapshot.anchor_before(range.start);
 5380                let end_anchor = snapshot.anchor_after(range.end);
 5381                if let Some(ranges) = self
 5382                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5383                {
 5384                    for (buffer, edits) in ranges {
 5385                        linked_edits
 5386                            .entry(buffer.clone())
 5387                            .or_default()
 5388                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5389                    }
 5390                }
 5391            }
 5392        }
 5393
 5394        cx.emit(EditorEvent::InputHandled {
 5395            utf16_range_to_replace: None,
 5396            text: new_text.clone().into(),
 5397        });
 5398
 5399        self.transact(window, cx, |this, window, cx| {
 5400            if let Some(mut snippet) = snippet {
 5401                snippet.text = new_text.to_string();
 5402                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5403            } else {
 5404                this.buffer.update(cx, |buffer, cx| {
 5405                    let auto_indent = match completion.insert_text_mode {
 5406                        Some(InsertTextMode::AS_IS) => None,
 5407                        _ => this.autoindent_mode.clone(),
 5408                    };
 5409                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5410                    buffer.edit(edits, auto_indent, cx);
 5411                });
 5412            }
 5413            for (buffer, edits) in linked_edits {
 5414                buffer.update(cx, |buffer, cx| {
 5415                    let snapshot = buffer.snapshot();
 5416                    let edits = edits
 5417                        .into_iter()
 5418                        .map(|(range, text)| {
 5419                            use text::ToPoint as TP;
 5420                            let end_point = TP::to_point(&range.end, &snapshot);
 5421                            let start_point = TP::to_point(&range.start, &snapshot);
 5422                            (start_point..end_point, text)
 5423                        })
 5424                        .sorted_by_key(|(range, _)| range.start);
 5425                    buffer.edit(edits, None, cx);
 5426                })
 5427            }
 5428
 5429            this.refresh_inline_completion(true, false, window, cx);
 5430        });
 5431
 5432        let show_new_completions_on_confirm = completion
 5433            .confirm
 5434            .as_ref()
 5435            .map_or(false, |confirm| confirm(intent, window, cx));
 5436        if show_new_completions_on_confirm {
 5437            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5438        }
 5439
 5440        let provider = self.completion_provider.as_ref()?;
 5441        drop(completion);
 5442        let apply_edits = provider.apply_additional_edits_for_completion(
 5443            buffer_handle,
 5444            completions_menu.completions.clone(),
 5445            candidate_id,
 5446            true,
 5447            cx,
 5448        );
 5449
 5450        let editor_settings = EditorSettings::get_global(cx);
 5451        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5452            // After the code completion is finished, users often want to know what signatures are needed.
 5453            // so we should automatically call signature_help
 5454            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5455        }
 5456
 5457        Some(cx.foreground_executor().spawn(async move {
 5458            apply_edits.await?;
 5459            Ok(())
 5460        }))
 5461    }
 5462
 5463    pub fn toggle_code_actions(
 5464        &mut self,
 5465        action: &ToggleCodeActions,
 5466        window: &mut Window,
 5467        cx: &mut Context<Self>,
 5468    ) {
 5469        let quick_launch = action.quick_launch;
 5470        let mut context_menu = self.context_menu.borrow_mut();
 5471        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5472            if code_actions.deployed_from == action.deployed_from {
 5473                // Toggle if we're selecting the same one
 5474                *context_menu = None;
 5475                cx.notify();
 5476                return;
 5477            } else {
 5478                // Otherwise, clear it and start a new one
 5479                *context_menu = None;
 5480                cx.notify();
 5481            }
 5482        }
 5483        drop(context_menu);
 5484        let snapshot = self.snapshot(window, cx);
 5485        let deployed_from = action.deployed_from.clone();
 5486        let mut task = self.code_actions_task.take();
 5487        let action = action.clone();
 5488        cx.spawn_in(window, async move |editor, cx| {
 5489            while let Some(prev_task) = task {
 5490                prev_task.await.log_err();
 5491                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5492            }
 5493
 5494            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5495                if editor.focus_handle.is_focused(window) {
 5496                    let multibuffer_point = match &action.deployed_from {
 5497                        Some(CodeActionSource::Indicator(row)) => {
 5498                            DisplayPoint::new(*row, 0).to_point(&snapshot)
 5499                        }
 5500                        _ => editor.selections.newest::<Point>(cx).head(),
 5501                    };
 5502                    let (buffer, buffer_row) = snapshot
 5503                        .buffer_snapshot
 5504                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5505                        .and_then(|(buffer_snapshot, range)| {
 5506                            editor
 5507                                .buffer
 5508                                .read(cx)
 5509                                .buffer(buffer_snapshot.remote_id())
 5510                                .map(|buffer| (buffer, range.start.row))
 5511                        })?;
 5512                    let (_, code_actions) = editor
 5513                        .available_code_actions
 5514                        .clone()
 5515                        .and_then(|(location, code_actions)| {
 5516                            let snapshot = location.buffer.read(cx).snapshot();
 5517                            let point_range = location.range.to_point(&snapshot);
 5518                            let point_range = point_range.start.row..=point_range.end.row;
 5519                            if point_range.contains(&buffer_row) {
 5520                                Some((location, code_actions))
 5521                            } else {
 5522                                None
 5523                            }
 5524                        })
 5525                        .unzip();
 5526                    let buffer_id = buffer.read(cx).remote_id();
 5527                    let tasks = editor
 5528                        .tasks
 5529                        .get(&(buffer_id, buffer_row))
 5530                        .map(|t| Arc::new(t.to_owned()));
 5531                    if tasks.is_none() && code_actions.is_none() {
 5532                        return None;
 5533                    }
 5534
 5535                    editor.completion_tasks.clear();
 5536                    editor.discard_inline_completion(false, cx);
 5537                    let task_context =
 5538                        tasks
 5539                            .as_ref()
 5540                            .zip(editor.project.clone())
 5541                            .map(|(tasks, project)| {
 5542                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5543                            });
 5544
 5545                    Some(cx.spawn_in(window, async move |editor, cx| {
 5546                        let task_context = match task_context {
 5547                            Some(task_context) => task_context.await,
 5548                            None => None,
 5549                        };
 5550                        let resolved_tasks =
 5551                            tasks
 5552                                .zip(task_context.clone())
 5553                                .map(|(tasks, task_context)| ResolvedTasks {
 5554                                    templates: tasks.resolve(&task_context).collect(),
 5555                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5556                                        multibuffer_point.row,
 5557                                        tasks.column,
 5558                                    )),
 5559                                });
 5560                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5561                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5562                                maybe!({
 5563                                    let project = editor.project.as_ref()?;
 5564                                    let dap_store = project.read(cx).dap_store();
 5565                                    let mut scenarios = vec![];
 5566                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5567                                    let buffer = buffer.read(cx);
 5568                                    let language = buffer.language()?;
 5569                                    let file = buffer.file();
 5570                                    let debug_adapter =
 5571                                        language_settings(language.name().into(), file, cx)
 5572                                            .debuggers
 5573                                            .first()
 5574                                            .map(SharedString::from)
 5575                                            .or_else(|| {
 5576                                                language
 5577                                                    .config()
 5578                                                    .debuggers
 5579                                                    .first()
 5580                                                    .map(SharedString::from)
 5581                                            })?;
 5582
 5583                                    dap_store.update(cx, |dap_store, cx| {
 5584                                        for (_, task) in &resolved_tasks.templates {
 5585                                            if let Some(scenario) = dap_store
 5586                                                .debug_scenario_for_build_task(
 5587                                                    task.original_task().clone(),
 5588                                                    debug_adapter.clone().into(),
 5589                                                    task.display_label().to_owned().into(),
 5590                                                    cx,
 5591                                                )
 5592                                            {
 5593                                                scenarios.push(scenario);
 5594                                            }
 5595                                        }
 5596                                    });
 5597                                    Some(scenarios)
 5598                                })
 5599                                .unwrap_or_default()
 5600                            } else {
 5601                                vec![]
 5602                            }
 5603                        })?;
 5604                        let spawn_straight_away = quick_launch
 5605                            && resolved_tasks
 5606                                .as_ref()
 5607                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5608                            && code_actions
 5609                                .as_ref()
 5610                                .map_or(true, |actions| actions.is_empty())
 5611                            && debug_scenarios.is_empty();
 5612                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5613                            crate::hover_popover::hide_hover(editor, cx);
 5614                            *editor.context_menu.borrow_mut() =
 5615                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5616                                    buffer,
 5617                                    actions: CodeActionContents::new(
 5618                                        resolved_tasks,
 5619                                        code_actions,
 5620                                        debug_scenarios,
 5621                                        task_context.unwrap_or_default(),
 5622                                    ),
 5623                                    selected_item: Default::default(),
 5624                                    scroll_handle: UniformListScrollHandle::default(),
 5625                                    deployed_from,
 5626                                }));
 5627                            if spawn_straight_away {
 5628                                if let Some(task) = editor.confirm_code_action(
 5629                                    &ConfirmCodeAction { item_ix: Some(0) },
 5630                                    window,
 5631                                    cx,
 5632                                ) {
 5633                                    cx.notify();
 5634                                    return task;
 5635                                }
 5636                            }
 5637                            cx.notify();
 5638                            Task::ready(Ok(()))
 5639                        }) {
 5640                            task.await
 5641                        } else {
 5642                            Ok(())
 5643                        }
 5644                    }))
 5645                } else {
 5646                    Some(Task::ready(Ok(())))
 5647                }
 5648            })?;
 5649            if let Some(task) = spawned_test_task {
 5650                task.await?;
 5651            }
 5652
 5653            anyhow::Ok(())
 5654        })
 5655        .detach_and_log_err(cx);
 5656    }
 5657
 5658    pub fn confirm_code_action(
 5659        &mut self,
 5660        action: &ConfirmCodeAction,
 5661        window: &mut Window,
 5662        cx: &mut Context<Self>,
 5663    ) -> Option<Task<Result<()>>> {
 5664        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5665
 5666        let actions_menu =
 5667            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5668                menu
 5669            } else {
 5670                return None;
 5671            };
 5672
 5673        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5674        let action = actions_menu.actions.get(action_ix)?;
 5675        let title = action.label();
 5676        let buffer = actions_menu.buffer;
 5677        let workspace = self.workspace()?;
 5678
 5679        match action {
 5680            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5681                workspace.update(cx, |workspace, cx| {
 5682                    workspace.schedule_resolved_task(
 5683                        task_source_kind,
 5684                        resolved_task,
 5685                        false,
 5686                        window,
 5687                        cx,
 5688                    );
 5689
 5690                    Some(Task::ready(Ok(())))
 5691                })
 5692            }
 5693            CodeActionsItem::CodeAction {
 5694                excerpt_id,
 5695                action,
 5696                provider,
 5697            } => {
 5698                let apply_code_action =
 5699                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5700                let workspace = workspace.downgrade();
 5701                Some(cx.spawn_in(window, async move |editor, cx| {
 5702                    let project_transaction = apply_code_action.await?;
 5703                    Self::open_project_transaction(
 5704                        &editor,
 5705                        workspace,
 5706                        project_transaction,
 5707                        title,
 5708                        cx,
 5709                    )
 5710                    .await
 5711                }))
 5712            }
 5713            CodeActionsItem::DebugScenario(scenario) => {
 5714                let context = actions_menu.actions.context.clone();
 5715
 5716                workspace.update(cx, |workspace, cx| {
 5717                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5718                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5719                });
 5720                Some(Task::ready(Ok(())))
 5721            }
 5722        }
 5723    }
 5724
 5725    pub async fn open_project_transaction(
 5726        this: &WeakEntity<Editor>,
 5727        workspace: WeakEntity<Workspace>,
 5728        transaction: ProjectTransaction,
 5729        title: String,
 5730        cx: &mut AsyncWindowContext,
 5731    ) -> Result<()> {
 5732        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5733        cx.update(|_, cx| {
 5734            entries.sort_unstable_by_key(|(buffer, _)| {
 5735                buffer.read(cx).file().map(|f| f.path().clone())
 5736            });
 5737        })?;
 5738
 5739        // If the project transaction's edits are all contained within this editor, then
 5740        // avoid opening a new editor to display them.
 5741
 5742        if let Some((buffer, transaction)) = entries.first() {
 5743            if entries.len() == 1 {
 5744                let excerpt = this.update(cx, |editor, cx| {
 5745                    editor
 5746                        .buffer()
 5747                        .read(cx)
 5748                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5749                })?;
 5750                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5751                    if excerpted_buffer == *buffer {
 5752                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5753                            let excerpt_range = excerpt_range.to_offset(buffer);
 5754                            buffer
 5755                                .edited_ranges_for_transaction::<usize>(transaction)
 5756                                .all(|range| {
 5757                                    excerpt_range.start <= range.start
 5758                                        && excerpt_range.end >= range.end
 5759                                })
 5760                        })?;
 5761
 5762                        if all_edits_within_excerpt {
 5763                            return Ok(());
 5764                        }
 5765                    }
 5766                }
 5767            }
 5768        } else {
 5769            return Ok(());
 5770        }
 5771
 5772        let mut ranges_to_highlight = Vec::new();
 5773        let excerpt_buffer = cx.new(|cx| {
 5774            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5775            for (buffer_handle, transaction) in &entries {
 5776                let edited_ranges = buffer_handle
 5777                    .read(cx)
 5778                    .edited_ranges_for_transaction::<Point>(transaction)
 5779                    .collect::<Vec<_>>();
 5780                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5781                    PathKey::for_buffer(buffer_handle, cx),
 5782                    buffer_handle.clone(),
 5783                    edited_ranges,
 5784                    DEFAULT_MULTIBUFFER_CONTEXT,
 5785                    cx,
 5786                );
 5787
 5788                ranges_to_highlight.extend(ranges);
 5789            }
 5790            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5791            multibuffer
 5792        })?;
 5793
 5794        workspace.update_in(cx, |workspace, window, cx| {
 5795            let project = workspace.project().clone();
 5796            let editor =
 5797                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5798            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5799            editor.update(cx, |editor, cx| {
 5800                editor.highlight_background::<Self>(
 5801                    &ranges_to_highlight,
 5802                    |theme| theme.editor_highlighted_line_background,
 5803                    cx,
 5804                );
 5805            });
 5806        })?;
 5807
 5808        Ok(())
 5809    }
 5810
 5811    pub fn clear_code_action_providers(&mut self) {
 5812        self.code_action_providers.clear();
 5813        self.available_code_actions.take();
 5814    }
 5815
 5816    pub fn add_code_action_provider(
 5817        &mut self,
 5818        provider: Rc<dyn CodeActionProvider>,
 5819        window: &mut Window,
 5820        cx: &mut Context<Self>,
 5821    ) {
 5822        if self
 5823            .code_action_providers
 5824            .iter()
 5825            .any(|existing_provider| existing_provider.id() == provider.id())
 5826        {
 5827            return;
 5828        }
 5829
 5830        self.code_action_providers.push(provider);
 5831        self.refresh_code_actions(window, cx);
 5832    }
 5833
 5834    pub fn remove_code_action_provider(
 5835        &mut self,
 5836        id: Arc<str>,
 5837        window: &mut Window,
 5838        cx: &mut Context<Self>,
 5839    ) {
 5840        self.code_action_providers
 5841            .retain(|provider| provider.id() != id);
 5842        self.refresh_code_actions(window, cx);
 5843    }
 5844
 5845    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 5846        !self.code_action_providers.is_empty()
 5847            && EditorSettings::get_global(cx).toolbar.code_actions
 5848    }
 5849
 5850    pub fn has_available_code_actions(&self) -> bool {
 5851        self.available_code_actions
 5852            .as_ref()
 5853            .is_some_and(|(_, actions)| !actions.is_empty())
 5854    }
 5855
 5856    fn render_inline_code_actions(
 5857        &self,
 5858        icon_size: ui::IconSize,
 5859        display_row: DisplayRow,
 5860        is_active: bool,
 5861        cx: &mut Context<Self>,
 5862    ) -> AnyElement {
 5863        let show_tooltip = !self.context_menu_visible();
 5864        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 5865            .icon_size(icon_size)
 5866            .shape(ui::IconButtonShape::Square)
 5867            .style(ButtonStyle::Transparent)
 5868            .icon_color(ui::Color::Hidden)
 5869            .toggle_state(is_active)
 5870            .when(show_tooltip, |this| {
 5871                this.tooltip({
 5872                    let focus_handle = self.focus_handle.clone();
 5873                    move |window, cx| {
 5874                        Tooltip::for_action_in(
 5875                            "Toggle Code Actions",
 5876                            &ToggleCodeActions {
 5877                                deployed_from: None,
 5878                                quick_launch: false,
 5879                            },
 5880                            &focus_handle,
 5881                            window,
 5882                            cx,
 5883                        )
 5884                    }
 5885                })
 5886            })
 5887            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 5888                window.focus(&editor.focus_handle(cx));
 5889                editor.toggle_code_actions(
 5890                    &crate::actions::ToggleCodeActions {
 5891                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 5892                            display_row,
 5893                        )),
 5894                        quick_launch: false,
 5895                    },
 5896                    window,
 5897                    cx,
 5898                );
 5899            }))
 5900            .into_any_element()
 5901    }
 5902
 5903    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 5904        &self.context_menu
 5905    }
 5906
 5907    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 5908        let newest_selection = self.selections.newest_anchor().clone();
 5909        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 5910        let buffer = self.buffer.read(cx);
 5911        if newest_selection.head().diff_base_anchor.is_some() {
 5912            return None;
 5913        }
 5914        let (start_buffer, start) =
 5915            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 5916        let (end_buffer, end) =
 5917            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 5918        if start_buffer != end_buffer {
 5919            return None;
 5920        }
 5921
 5922        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 5923            cx.background_executor()
 5924                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 5925                .await;
 5926
 5927            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 5928                let providers = this.code_action_providers.clone();
 5929                let tasks = this
 5930                    .code_action_providers
 5931                    .iter()
 5932                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 5933                    .collect::<Vec<_>>();
 5934                (providers, tasks)
 5935            })?;
 5936
 5937            let mut actions = Vec::new();
 5938            for (provider, provider_actions) in
 5939                providers.into_iter().zip(future::join_all(tasks).await)
 5940            {
 5941                if let Some(provider_actions) = provider_actions.log_err() {
 5942                    actions.extend(provider_actions.into_iter().map(|action| {
 5943                        AvailableCodeAction {
 5944                            excerpt_id: newest_selection.start.excerpt_id,
 5945                            action,
 5946                            provider: provider.clone(),
 5947                        }
 5948                    }));
 5949                }
 5950            }
 5951
 5952            this.update(cx, |this, cx| {
 5953                this.available_code_actions = if actions.is_empty() {
 5954                    None
 5955                } else {
 5956                    Some((
 5957                        Location {
 5958                            buffer: start_buffer,
 5959                            range: start..end,
 5960                        },
 5961                        actions.into(),
 5962                    ))
 5963                };
 5964                cx.notify();
 5965            })
 5966        }));
 5967        None
 5968    }
 5969
 5970    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5971        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 5972            self.show_git_blame_inline = false;
 5973
 5974            self.show_git_blame_inline_delay_task =
 5975                Some(cx.spawn_in(window, async move |this, cx| {
 5976                    cx.background_executor().timer(delay).await;
 5977
 5978                    this.update(cx, |this, cx| {
 5979                        this.show_git_blame_inline = true;
 5980                        cx.notify();
 5981                    })
 5982                    .log_err();
 5983                }));
 5984        }
 5985    }
 5986
 5987    fn show_blame_popover(
 5988        &mut self,
 5989        blame_entry: &BlameEntry,
 5990        position: gpui::Point<Pixels>,
 5991        cx: &mut Context<Self>,
 5992    ) {
 5993        if let Some(state) = &mut self.inline_blame_popover {
 5994            state.hide_task.take();
 5995            cx.notify();
 5996        } else {
 5997            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 5998            let show_task = cx.spawn(async move |editor, cx| {
 5999                cx.background_executor()
 6000                    .timer(std::time::Duration::from_millis(delay))
 6001                    .await;
 6002                editor
 6003                    .update(cx, |editor, cx| {
 6004                        if let Some(state) = &mut editor.inline_blame_popover {
 6005                            state.show_task = None;
 6006                            cx.notify();
 6007                        }
 6008                    })
 6009                    .ok();
 6010            });
 6011            let Some(blame) = self.blame.as_ref() else {
 6012                return;
 6013            };
 6014            let blame = blame.read(cx);
 6015            let details = blame.details_for_entry(&blame_entry);
 6016            let markdown = cx.new(|cx| {
 6017                Markdown::new(
 6018                    details
 6019                        .as_ref()
 6020                        .map(|message| message.message.clone())
 6021                        .unwrap_or_default(),
 6022                    None,
 6023                    None,
 6024                    cx,
 6025                )
 6026            });
 6027            self.inline_blame_popover = Some(InlineBlamePopover {
 6028                position,
 6029                show_task: Some(show_task),
 6030                hide_task: None,
 6031                popover_bounds: None,
 6032                popover_state: InlineBlamePopoverState {
 6033                    scroll_handle: ScrollHandle::new(),
 6034                    commit_message: details,
 6035                    markdown,
 6036                },
 6037            });
 6038        }
 6039    }
 6040
 6041    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6042        if let Some(state) = &mut self.inline_blame_popover {
 6043            if state.show_task.is_some() {
 6044                self.inline_blame_popover.take();
 6045                cx.notify();
 6046            } else {
 6047                let hide_task = cx.spawn(async move |editor, cx| {
 6048                    cx.background_executor()
 6049                        .timer(std::time::Duration::from_millis(100))
 6050                        .await;
 6051                    editor
 6052                        .update(cx, |editor, cx| {
 6053                            editor.inline_blame_popover.take();
 6054                            cx.notify();
 6055                        })
 6056                        .ok();
 6057                });
 6058                state.hide_task = Some(hide_task);
 6059            }
 6060        }
 6061    }
 6062
 6063    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6064        if self.pending_rename.is_some() {
 6065            return None;
 6066        }
 6067
 6068        let provider = self.semantics_provider.clone()?;
 6069        let buffer = self.buffer.read(cx);
 6070        let newest_selection = self.selections.newest_anchor().clone();
 6071        let cursor_position = newest_selection.head();
 6072        let (cursor_buffer, cursor_buffer_position) =
 6073            buffer.text_anchor_for_position(cursor_position, cx)?;
 6074        let (tail_buffer, tail_buffer_position) =
 6075            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6076        if cursor_buffer != tail_buffer {
 6077            return None;
 6078        }
 6079
 6080        let snapshot = cursor_buffer.read(cx).snapshot();
 6081        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6082        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6083        if start_word_range != end_word_range {
 6084            self.document_highlights_task.take();
 6085            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6086            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6087            return None;
 6088        }
 6089
 6090        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6091        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6092            cx.background_executor()
 6093                .timer(Duration::from_millis(debounce))
 6094                .await;
 6095
 6096            let highlights = if let Some(highlights) = cx
 6097                .update(|cx| {
 6098                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6099                })
 6100                .ok()
 6101                .flatten()
 6102            {
 6103                highlights.await.log_err()
 6104            } else {
 6105                None
 6106            };
 6107
 6108            if let Some(highlights) = highlights {
 6109                this.update(cx, |this, cx| {
 6110                    if this.pending_rename.is_some() {
 6111                        return;
 6112                    }
 6113
 6114                    let buffer_id = cursor_position.buffer_id;
 6115                    let buffer = this.buffer.read(cx);
 6116                    if !buffer
 6117                        .text_anchor_for_position(cursor_position, cx)
 6118                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6119                    {
 6120                        return;
 6121                    }
 6122
 6123                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6124                    let mut write_ranges = Vec::new();
 6125                    let mut read_ranges = Vec::new();
 6126                    for highlight in highlights {
 6127                        for (excerpt_id, excerpt_range) in
 6128                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6129                        {
 6130                            let start = highlight
 6131                                .range
 6132                                .start
 6133                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6134                            let end = highlight
 6135                                .range
 6136                                .end
 6137                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6138                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6139                                continue;
 6140                            }
 6141
 6142                            let range = Anchor {
 6143                                buffer_id,
 6144                                excerpt_id,
 6145                                text_anchor: start,
 6146                                diff_base_anchor: None,
 6147                            }..Anchor {
 6148                                buffer_id,
 6149                                excerpt_id,
 6150                                text_anchor: end,
 6151                                diff_base_anchor: None,
 6152                            };
 6153                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6154                                write_ranges.push(range);
 6155                            } else {
 6156                                read_ranges.push(range);
 6157                            }
 6158                        }
 6159                    }
 6160
 6161                    this.highlight_background::<DocumentHighlightRead>(
 6162                        &read_ranges,
 6163                        |theme| theme.editor_document_highlight_read_background,
 6164                        cx,
 6165                    );
 6166                    this.highlight_background::<DocumentHighlightWrite>(
 6167                        &write_ranges,
 6168                        |theme| theme.editor_document_highlight_write_background,
 6169                        cx,
 6170                    );
 6171                    cx.notify();
 6172                })
 6173                .log_err();
 6174            }
 6175        }));
 6176        None
 6177    }
 6178
 6179    fn prepare_highlight_query_from_selection(
 6180        &mut self,
 6181        cx: &mut Context<Editor>,
 6182    ) -> Option<(String, Range<Anchor>)> {
 6183        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6184            return None;
 6185        }
 6186        if !EditorSettings::get_global(cx).selection_highlight {
 6187            return None;
 6188        }
 6189        if self.selections.count() != 1 || self.selections.line_mode {
 6190            return None;
 6191        }
 6192        let selection = self.selections.newest::<Point>(cx);
 6193        if selection.is_empty() || selection.start.row != selection.end.row {
 6194            return None;
 6195        }
 6196        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6197        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6198        let query = multi_buffer_snapshot
 6199            .text_for_range(selection_anchor_range.clone())
 6200            .collect::<String>();
 6201        if query.trim().is_empty() {
 6202            return None;
 6203        }
 6204        Some((query, selection_anchor_range))
 6205    }
 6206
 6207    fn update_selection_occurrence_highlights(
 6208        &mut self,
 6209        query_text: String,
 6210        query_range: Range<Anchor>,
 6211        multi_buffer_range_to_query: Range<Point>,
 6212        use_debounce: bool,
 6213        window: &mut Window,
 6214        cx: &mut Context<Editor>,
 6215    ) -> Task<()> {
 6216        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6217        cx.spawn_in(window, async move |editor, cx| {
 6218            if use_debounce {
 6219                cx.background_executor()
 6220                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6221                    .await;
 6222            }
 6223            let match_task = cx.background_spawn(async move {
 6224                let buffer_ranges = multi_buffer_snapshot
 6225                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6226                    .into_iter()
 6227                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6228                let mut match_ranges = Vec::new();
 6229                let Ok(regex) = project::search::SearchQuery::text(
 6230                    query_text.clone(),
 6231                    false,
 6232                    false,
 6233                    false,
 6234                    Default::default(),
 6235                    Default::default(),
 6236                    false,
 6237                    None,
 6238                ) else {
 6239                    return Vec::default();
 6240                };
 6241                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6242                    match_ranges.extend(
 6243                        regex
 6244                            .search(&buffer_snapshot, Some(search_range.clone()))
 6245                            .await
 6246                            .into_iter()
 6247                            .filter_map(|match_range| {
 6248                                let match_start = buffer_snapshot
 6249                                    .anchor_after(search_range.start + match_range.start);
 6250                                let match_end = buffer_snapshot
 6251                                    .anchor_before(search_range.start + match_range.end);
 6252                                let match_anchor_range = Anchor::range_in_buffer(
 6253                                    excerpt_id,
 6254                                    buffer_snapshot.remote_id(),
 6255                                    match_start..match_end,
 6256                                );
 6257                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6258                            }),
 6259                    );
 6260                }
 6261                match_ranges
 6262            });
 6263            let match_ranges = match_task.await;
 6264            editor
 6265                .update_in(cx, |editor, _, cx| {
 6266                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6267                    if !match_ranges.is_empty() {
 6268                        editor.highlight_background::<SelectedTextHighlight>(
 6269                            &match_ranges,
 6270                            |theme| theme.editor_document_highlight_bracket_background,
 6271                            cx,
 6272                        )
 6273                    }
 6274                })
 6275                .log_err();
 6276        })
 6277    }
 6278
 6279    fn refresh_selected_text_highlights(
 6280        &mut self,
 6281        on_buffer_edit: bool,
 6282        window: &mut Window,
 6283        cx: &mut Context<Editor>,
 6284    ) {
 6285        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6286        else {
 6287            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6288            self.quick_selection_highlight_task.take();
 6289            self.debounced_selection_highlight_task.take();
 6290            return;
 6291        };
 6292        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6293        if on_buffer_edit
 6294            || self
 6295                .quick_selection_highlight_task
 6296                .as_ref()
 6297                .map_or(true, |(prev_anchor_range, _)| {
 6298                    prev_anchor_range != &query_range
 6299                })
 6300        {
 6301            let multi_buffer_visible_start = self
 6302                .scroll_manager
 6303                .anchor()
 6304                .anchor
 6305                .to_point(&multi_buffer_snapshot);
 6306            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6307                multi_buffer_visible_start
 6308                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6309                Bias::Left,
 6310            );
 6311            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6312            self.quick_selection_highlight_task = Some((
 6313                query_range.clone(),
 6314                self.update_selection_occurrence_highlights(
 6315                    query_text.clone(),
 6316                    query_range.clone(),
 6317                    multi_buffer_visible_range,
 6318                    false,
 6319                    window,
 6320                    cx,
 6321                ),
 6322            ));
 6323        }
 6324        if on_buffer_edit
 6325            || self
 6326                .debounced_selection_highlight_task
 6327                .as_ref()
 6328                .map_or(true, |(prev_anchor_range, _)| {
 6329                    prev_anchor_range != &query_range
 6330                })
 6331        {
 6332            let multi_buffer_start = multi_buffer_snapshot
 6333                .anchor_before(0)
 6334                .to_point(&multi_buffer_snapshot);
 6335            let multi_buffer_end = multi_buffer_snapshot
 6336                .anchor_after(multi_buffer_snapshot.len())
 6337                .to_point(&multi_buffer_snapshot);
 6338            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6339            self.debounced_selection_highlight_task = Some((
 6340                query_range.clone(),
 6341                self.update_selection_occurrence_highlights(
 6342                    query_text,
 6343                    query_range,
 6344                    multi_buffer_full_range,
 6345                    true,
 6346                    window,
 6347                    cx,
 6348                ),
 6349            ));
 6350        }
 6351    }
 6352
 6353    pub fn refresh_inline_completion(
 6354        &mut self,
 6355        debounce: bool,
 6356        user_requested: bool,
 6357        window: &mut Window,
 6358        cx: &mut Context<Self>,
 6359    ) -> Option<()> {
 6360        let provider = self.edit_prediction_provider()?;
 6361        let cursor = self.selections.newest_anchor().head();
 6362        let (buffer, cursor_buffer_position) =
 6363            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6364
 6365        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6366            self.discard_inline_completion(false, cx);
 6367            return None;
 6368        }
 6369
 6370        if !user_requested
 6371            && (!self.should_show_edit_predictions()
 6372                || !self.is_focused(window)
 6373                || buffer.read(cx).is_empty())
 6374        {
 6375            self.discard_inline_completion(false, cx);
 6376            return None;
 6377        }
 6378
 6379        self.update_visible_inline_completion(window, cx);
 6380        provider.refresh(
 6381            self.project.clone(),
 6382            buffer,
 6383            cursor_buffer_position,
 6384            debounce,
 6385            cx,
 6386        );
 6387        Some(())
 6388    }
 6389
 6390    fn show_edit_predictions_in_menu(&self) -> bool {
 6391        match self.edit_prediction_settings {
 6392            EditPredictionSettings::Disabled => false,
 6393            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6394        }
 6395    }
 6396
 6397    pub fn edit_predictions_enabled(&self) -> bool {
 6398        match self.edit_prediction_settings {
 6399            EditPredictionSettings::Disabled => false,
 6400            EditPredictionSettings::Enabled { .. } => true,
 6401        }
 6402    }
 6403
 6404    fn edit_prediction_requires_modifier(&self) -> bool {
 6405        match self.edit_prediction_settings {
 6406            EditPredictionSettings::Disabled => false,
 6407            EditPredictionSettings::Enabled {
 6408                preview_requires_modifier,
 6409                ..
 6410            } => preview_requires_modifier,
 6411        }
 6412    }
 6413
 6414    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6415        if self.edit_prediction_provider.is_none() {
 6416            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6417        } else {
 6418            let selection = self.selections.newest_anchor();
 6419            let cursor = selection.head();
 6420
 6421            if let Some((buffer, cursor_buffer_position)) =
 6422                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6423            {
 6424                self.edit_prediction_settings =
 6425                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6426            }
 6427        }
 6428    }
 6429
 6430    fn edit_prediction_settings_at_position(
 6431        &self,
 6432        buffer: &Entity<Buffer>,
 6433        buffer_position: language::Anchor,
 6434        cx: &App,
 6435    ) -> EditPredictionSettings {
 6436        if !self.mode.is_full()
 6437            || !self.show_inline_completions_override.unwrap_or(true)
 6438            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6439        {
 6440            return EditPredictionSettings::Disabled;
 6441        }
 6442
 6443        let buffer = buffer.read(cx);
 6444
 6445        let file = buffer.file();
 6446
 6447        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6448            return EditPredictionSettings::Disabled;
 6449        };
 6450
 6451        let by_provider = matches!(
 6452            self.menu_inline_completions_policy,
 6453            MenuInlineCompletionsPolicy::ByProvider
 6454        );
 6455
 6456        let show_in_menu = by_provider
 6457            && self
 6458                .edit_prediction_provider
 6459                .as_ref()
 6460                .map_or(false, |provider| {
 6461                    provider.provider.show_completions_in_menu()
 6462                });
 6463
 6464        let preview_requires_modifier =
 6465            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6466
 6467        EditPredictionSettings::Enabled {
 6468            show_in_menu,
 6469            preview_requires_modifier,
 6470        }
 6471    }
 6472
 6473    fn should_show_edit_predictions(&self) -> bool {
 6474        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6475    }
 6476
 6477    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6478        matches!(
 6479            self.edit_prediction_preview,
 6480            EditPredictionPreview::Active { .. }
 6481        )
 6482    }
 6483
 6484    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6485        let cursor = self.selections.newest_anchor().head();
 6486        if let Some((buffer, cursor_position)) =
 6487            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6488        {
 6489            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6490        } else {
 6491            false
 6492        }
 6493    }
 6494
 6495    pub fn supports_minimap(&self, cx: &App) -> bool {
 6496        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6497    }
 6498
 6499    fn edit_predictions_enabled_in_buffer(
 6500        &self,
 6501        buffer: &Entity<Buffer>,
 6502        buffer_position: language::Anchor,
 6503        cx: &App,
 6504    ) -> bool {
 6505        maybe!({
 6506            if self.read_only(cx) {
 6507                return Some(false);
 6508            }
 6509            let provider = self.edit_prediction_provider()?;
 6510            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6511                return Some(false);
 6512            }
 6513            let buffer = buffer.read(cx);
 6514            let Some(file) = buffer.file() else {
 6515                return Some(true);
 6516            };
 6517            let settings = all_language_settings(Some(file), cx);
 6518            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6519        })
 6520        .unwrap_or(false)
 6521    }
 6522
 6523    fn cycle_inline_completion(
 6524        &mut self,
 6525        direction: Direction,
 6526        window: &mut Window,
 6527        cx: &mut Context<Self>,
 6528    ) -> Option<()> {
 6529        let provider = self.edit_prediction_provider()?;
 6530        let cursor = self.selections.newest_anchor().head();
 6531        let (buffer, cursor_buffer_position) =
 6532            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6533        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6534            return None;
 6535        }
 6536
 6537        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6538        self.update_visible_inline_completion(window, cx);
 6539
 6540        Some(())
 6541    }
 6542
 6543    pub fn show_inline_completion(
 6544        &mut self,
 6545        _: &ShowEditPrediction,
 6546        window: &mut Window,
 6547        cx: &mut Context<Self>,
 6548    ) {
 6549        if !self.has_active_inline_completion() {
 6550            self.refresh_inline_completion(false, true, window, cx);
 6551            return;
 6552        }
 6553
 6554        self.update_visible_inline_completion(window, cx);
 6555    }
 6556
 6557    pub fn display_cursor_names(
 6558        &mut self,
 6559        _: &DisplayCursorNames,
 6560        window: &mut Window,
 6561        cx: &mut Context<Self>,
 6562    ) {
 6563        self.show_cursor_names(window, cx);
 6564    }
 6565
 6566    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6567        self.show_cursor_names = true;
 6568        cx.notify();
 6569        cx.spawn_in(window, async move |this, cx| {
 6570            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6571            this.update(cx, |this, cx| {
 6572                this.show_cursor_names = false;
 6573                cx.notify()
 6574            })
 6575            .ok()
 6576        })
 6577        .detach();
 6578    }
 6579
 6580    pub fn next_edit_prediction(
 6581        &mut self,
 6582        _: &NextEditPrediction,
 6583        window: &mut Window,
 6584        cx: &mut Context<Self>,
 6585    ) {
 6586        if self.has_active_inline_completion() {
 6587            self.cycle_inline_completion(Direction::Next, window, cx);
 6588        } else {
 6589            let is_copilot_disabled = self
 6590                .refresh_inline_completion(false, true, window, cx)
 6591                .is_none();
 6592            if is_copilot_disabled {
 6593                cx.propagate();
 6594            }
 6595        }
 6596    }
 6597
 6598    pub fn previous_edit_prediction(
 6599        &mut self,
 6600        _: &PreviousEditPrediction,
 6601        window: &mut Window,
 6602        cx: &mut Context<Self>,
 6603    ) {
 6604        if self.has_active_inline_completion() {
 6605            self.cycle_inline_completion(Direction::Prev, window, cx);
 6606        } else {
 6607            let is_copilot_disabled = self
 6608                .refresh_inline_completion(false, true, window, cx)
 6609                .is_none();
 6610            if is_copilot_disabled {
 6611                cx.propagate();
 6612            }
 6613        }
 6614    }
 6615
 6616    pub fn accept_edit_prediction(
 6617        &mut self,
 6618        _: &AcceptEditPrediction,
 6619        window: &mut Window,
 6620        cx: &mut Context<Self>,
 6621    ) {
 6622        if self.show_edit_predictions_in_menu() {
 6623            self.hide_context_menu(window, cx);
 6624        }
 6625
 6626        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6627            return;
 6628        };
 6629
 6630        self.report_inline_completion_event(
 6631            active_inline_completion.completion_id.clone(),
 6632            true,
 6633            cx,
 6634        );
 6635
 6636        match &active_inline_completion.completion {
 6637            InlineCompletion::Move { target, .. } => {
 6638                let target = *target;
 6639
 6640                if let Some(position_map) = &self.last_position_map {
 6641                    if position_map
 6642                        .visible_row_range
 6643                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6644                        || !self.edit_prediction_requires_modifier()
 6645                    {
 6646                        self.unfold_ranges(&[target..target], true, false, cx);
 6647                        // Note that this is also done in vim's handler of the Tab action.
 6648                        self.change_selections(
 6649                            Some(Autoscroll::newest()),
 6650                            window,
 6651                            cx,
 6652                            |selections| {
 6653                                selections.select_anchor_ranges([target..target]);
 6654                            },
 6655                        );
 6656                        self.clear_row_highlights::<EditPredictionPreview>();
 6657
 6658                        self.edit_prediction_preview
 6659                            .set_previous_scroll_position(None);
 6660                    } else {
 6661                        self.edit_prediction_preview
 6662                            .set_previous_scroll_position(Some(
 6663                                position_map.snapshot.scroll_anchor,
 6664                            ));
 6665
 6666                        self.highlight_rows::<EditPredictionPreview>(
 6667                            target..target,
 6668                            cx.theme().colors().editor_highlighted_line_background,
 6669                            RowHighlightOptions {
 6670                                autoscroll: true,
 6671                                ..Default::default()
 6672                            },
 6673                            cx,
 6674                        );
 6675                        self.request_autoscroll(Autoscroll::fit(), cx);
 6676                    }
 6677                }
 6678            }
 6679            InlineCompletion::Edit { edits, .. } => {
 6680                if let Some(provider) = self.edit_prediction_provider() {
 6681                    provider.accept(cx);
 6682                }
 6683
 6684                // Store the transaction ID and selections before applying the edit
 6685                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 6686
 6687                let snapshot = self.buffer.read(cx).snapshot(cx);
 6688                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6689
 6690                self.buffer.update(cx, |buffer, cx| {
 6691                    buffer.edit(edits.iter().cloned(), None, cx)
 6692                });
 6693
 6694                self.change_selections(None, window, cx, |s| {
 6695                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6696                });
 6697
 6698                let selections = self.selections.disjoint_anchors();
 6699                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 6700                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6701                    if has_new_transaction {
 6702                        self.selection_history
 6703                            .insert_transaction(transaction_id_now, selections);
 6704                    }
 6705                }
 6706
 6707                self.update_visible_inline_completion(window, cx);
 6708                if self.active_inline_completion.is_none() {
 6709                    self.refresh_inline_completion(true, true, window, cx);
 6710                }
 6711
 6712                cx.notify();
 6713            }
 6714        }
 6715
 6716        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6717    }
 6718
 6719    pub fn accept_partial_inline_completion(
 6720        &mut self,
 6721        _: &AcceptPartialEditPrediction,
 6722        window: &mut Window,
 6723        cx: &mut Context<Self>,
 6724    ) {
 6725        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6726            return;
 6727        };
 6728        if self.selections.count() != 1 {
 6729            return;
 6730        }
 6731
 6732        self.report_inline_completion_event(
 6733            active_inline_completion.completion_id.clone(),
 6734            true,
 6735            cx,
 6736        );
 6737
 6738        match &active_inline_completion.completion {
 6739            InlineCompletion::Move { target, .. } => {
 6740                let target = *target;
 6741                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6742                    selections.select_anchor_ranges([target..target]);
 6743                });
 6744            }
 6745            InlineCompletion::Edit { edits, .. } => {
 6746                // Find an insertion that starts at the cursor position.
 6747                let snapshot = self.buffer.read(cx).snapshot(cx);
 6748                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6749                let insertion = edits.iter().find_map(|(range, text)| {
 6750                    let range = range.to_offset(&snapshot);
 6751                    if range.is_empty() && range.start == cursor_offset {
 6752                        Some(text)
 6753                    } else {
 6754                        None
 6755                    }
 6756                });
 6757
 6758                if let Some(text) = insertion {
 6759                    let mut partial_completion = text
 6760                        .chars()
 6761                        .by_ref()
 6762                        .take_while(|c| c.is_alphabetic())
 6763                        .collect::<String>();
 6764                    if partial_completion.is_empty() {
 6765                        partial_completion = text
 6766                            .chars()
 6767                            .by_ref()
 6768                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6769                            .collect::<String>();
 6770                    }
 6771
 6772                    cx.emit(EditorEvent::InputHandled {
 6773                        utf16_range_to_replace: None,
 6774                        text: partial_completion.clone().into(),
 6775                    });
 6776
 6777                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6778
 6779                    self.refresh_inline_completion(true, true, window, cx);
 6780                    cx.notify();
 6781                } else {
 6782                    self.accept_edit_prediction(&Default::default(), window, cx);
 6783                }
 6784            }
 6785        }
 6786    }
 6787
 6788    fn discard_inline_completion(
 6789        &mut self,
 6790        should_report_inline_completion_event: bool,
 6791        cx: &mut Context<Self>,
 6792    ) -> bool {
 6793        if should_report_inline_completion_event {
 6794            let completion_id = self
 6795                .active_inline_completion
 6796                .as_ref()
 6797                .and_then(|active_completion| active_completion.completion_id.clone());
 6798
 6799            self.report_inline_completion_event(completion_id, false, cx);
 6800        }
 6801
 6802        if let Some(provider) = self.edit_prediction_provider() {
 6803            provider.discard(cx);
 6804        }
 6805
 6806        self.take_active_inline_completion(cx)
 6807    }
 6808
 6809    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6810        let Some(provider) = self.edit_prediction_provider() else {
 6811            return;
 6812        };
 6813
 6814        let Some((_, buffer, _)) = self
 6815            .buffer
 6816            .read(cx)
 6817            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6818        else {
 6819            return;
 6820        };
 6821
 6822        let extension = buffer
 6823            .read(cx)
 6824            .file()
 6825            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 6826
 6827        let event_type = match accepted {
 6828            true => "Edit Prediction Accepted",
 6829            false => "Edit Prediction Discarded",
 6830        };
 6831        telemetry::event!(
 6832            event_type,
 6833            provider = provider.name(),
 6834            prediction_id = id,
 6835            suggestion_accepted = accepted,
 6836            file_extension = extension,
 6837        );
 6838    }
 6839
 6840    pub fn has_active_inline_completion(&self) -> bool {
 6841        self.active_inline_completion.is_some()
 6842    }
 6843
 6844    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 6845        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 6846            return false;
 6847        };
 6848
 6849        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 6850        self.clear_highlights::<InlineCompletionHighlight>(cx);
 6851        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 6852        true
 6853    }
 6854
 6855    /// Returns true when we're displaying the edit prediction popover below the cursor
 6856    /// like we are not previewing and the LSP autocomplete menu is visible
 6857    /// or we are in `when_holding_modifier` mode.
 6858    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 6859        if self.edit_prediction_preview_is_active()
 6860            || !self.show_edit_predictions_in_menu()
 6861            || !self.edit_predictions_enabled()
 6862        {
 6863            return false;
 6864        }
 6865
 6866        if self.has_visible_completions_menu() {
 6867            return true;
 6868        }
 6869
 6870        has_completion && self.edit_prediction_requires_modifier()
 6871    }
 6872
 6873    fn handle_modifiers_changed(
 6874        &mut self,
 6875        modifiers: Modifiers,
 6876        position_map: &PositionMap,
 6877        window: &mut Window,
 6878        cx: &mut Context<Self>,
 6879    ) {
 6880        if self.show_edit_predictions_in_menu() {
 6881            self.update_edit_prediction_preview(&modifiers, window, cx);
 6882        }
 6883
 6884        self.update_selection_mode(&modifiers, position_map, window, cx);
 6885
 6886        let mouse_position = window.mouse_position();
 6887        if !position_map.text_hitbox.is_hovered(window) {
 6888            return;
 6889        }
 6890
 6891        self.update_hovered_link(
 6892            position_map.point_for_position(mouse_position),
 6893            &position_map.snapshot,
 6894            modifiers,
 6895            window,
 6896            cx,
 6897        )
 6898    }
 6899
 6900    fn update_selection_mode(
 6901        &mut self,
 6902        modifiers: &Modifiers,
 6903        position_map: &PositionMap,
 6904        window: &mut Window,
 6905        cx: &mut Context<Self>,
 6906    ) {
 6907        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 6908            return;
 6909        }
 6910
 6911        let mouse_position = window.mouse_position();
 6912        let point_for_position = position_map.point_for_position(mouse_position);
 6913        let position = point_for_position.previous_valid;
 6914
 6915        self.select(
 6916            SelectPhase::BeginColumnar {
 6917                position,
 6918                reset: false,
 6919                goal_column: point_for_position.exact_unclipped.column(),
 6920            },
 6921            window,
 6922            cx,
 6923        );
 6924    }
 6925
 6926    fn update_edit_prediction_preview(
 6927        &mut self,
 6928        modifiers: &Modifiers,
 6929        window: &mut Window,
 6930        cx: &mut Context<Self>,
 6931    ) {
 6932        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 6933        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 6934            return;
 6935        };
 6936
 6937        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 6938            if matches!(
 6939                self.edit_prediction_preview,
 6940                EditPredictionPreview::Inactive { .. }
 6941            ) {
 6942                self.edit_prediction_preview = EditPredictionPreview::Active {
 6943                    previous_scroll_position: None,
 6944                    since: Instant::now(),
 6945                };
 6946
 6947                self.update_visible_inline_completion(window, cx);
 6948                cx.notify();
 6949            }
 6950        } else if let EditPredictionPreview::Active {
 6951            previous_scroll_position,
 6952            since,
 6953        } = self.edit_prediction_preview
 6954        {
 6955            if let (Some(previous_scroll_position), Some(position_map)) =
 6956                (previous_scroll_position, self.last_position_map.as_ref())
 6957            {
 6958                self.set_scroll_position(
 6959                    previous_scroll_position
 6960                        .scroll_position(&position_map.snapshot.display_snapshot),
 6961                    window,
 6962                    cx,
 6963                );
 6964            }
 6965
 6966            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 6967                released_too_fast: since.elapsed() < Duration::from_millis(200),
 6968            };
 6969            self.clear_row_highlights::<EditPredictionPreview>();
 6970            self.update_visible_inline_completion(window, cx);
 6971            cx.notify();
 6972        }
 6973    }
 6974
 6975    fn update_visible_inline_completion(
 6976        &mut self,
 6977        _window: &mut Window,
 6978        cx: &mut Context<Self>,
 6979    ) -> Option<()> {
 6980        let selection = self.selections.newest_anchor();
 6981        let cursor = selection.head();
 6982        let multibuffer = self.buffer.read(cx).snapshot(cx);
 6983        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 6984        let excerpt_id = cursor.excerpt_id;
 6985
 6986        let show_in_menu = self.show_edit_predictions_in_menu();
 6987        let completions_menu_has_precedence = !show_in_menu
 6988            && (self.context_menu.borrow().is_some()
 6989                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 6990
 6991        if completions_menu_has_precedence
 6992            || !offset_selection.is_empty()
 6993            || self
 6994                .active_inline_completion
 6995                .as_ref()
 6996                .map_or(false, |completion| {
 6997                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 6998                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 6999                    !invalidation_range.contains(&offset_selection.head())
 7000                })
 7001        {
 7002            self.discard_inline_completion(false, cx);
 7003            return None;
 7004        }
 7005
 7006        self.take_active_inline_completion(cx);
 7007        let Some(provider) = self.edit_prediction_provider() else {
 7008            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7009            return None;
 7010        };
 7011
 7012        let (buffer, cursor_buffer_position) =
 7013            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7014
 7015        self.edit_prediction_settings =
 7016            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7017
 7018        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7019
 7020        if self.edit_prediction_indent_conflict {
 7021            let cursor_point = cursor.to_point(&multibuffer);
 7022
 7023            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7024
 7025            if let Some((_, indent)) = indents.iter().next() {
 7026                if indent.len == cursor_point.column {
 7027                    self.edit_prediction_indent_conflict = false;
 7028                }
 7029            }
 7030        }
 7031
 7032        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7033        let edits = inline_completion
 7034            .edits
 7035            .into_iter()
 7036            .flat_map(|(range, new_text)| {
 7037                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7038                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7039                Some((start..end, new_text))
 7040            })
 7041            .collect::<Vec<_>>();
 7042        if edits.is_empty() {
 7043            return None;
 7044        }
 7045
 7046        let first_edit_start = edits.first().unwrap().0.start;
 7047        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7048        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7049
 7050        let last_edit_end = edits.last().unwrap().0.end;
 7051        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7052        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7053
 7054        let cursor_row = cursor.to_point(&multibuffer).row;
 7055
 7056        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7057
 7058        let mut inlay_ids = Vec::new();
 7059        let invalidation_row_range;
 7060        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7061            Some(cursor_row..edit_end_row)
 7062        } else if cursor_row > edit_end_row {
 7063            Some(edit_start_row..cursor_row)
 7064        } else {
 7065            None
 7066        };
 7067        let is_move =
 7068            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7069        let completion = if is_move {
 7070            invalidation_row_range =
 7071                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7072            let target = first_edit_start;
 7073            InlineCompletion::Move { target, snapshot }
 7074        } else {
 7075            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7076                && !self.inline_completions_hidden_for_vim_mode;
 7077
 7078            if show_completions_in_buffer {
 7079                if edits
 7080                    .iter()
 7081                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7082                {
 7083                    let mut inlays = Vec::new();
 7084                    for (range, new_text) in &edits {
 7085                        let inlay = Inlay::inline_completion(
 7086                            post_inc(&mut self.next_inlay_id),
 7087                            range.start,
 7088                            new_text.as_str(),
 7089                        );
 7090                        inlay_ids.push(inlay.id);
 7091                        inlays.push(inlay);
 7092                    }
 7093
 7094                    self.splice_inlays(&[], inlays, cx);
 7095                } else {
 7096                    let background_color = cx.theme().status().deleted_background;
 7097                    self.highlight_text::<InlineCompletionHighlight>(
 7098                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7099                        HighlightStyle {
 7100                            background_color: Some(background_color),
 7101                            ..Default::default()
 7102                        },
 7103                        cx,
 7104                    );
 7105                }
 7106            }
 7107
 7108            invalidation_row_range = edit_start_row..edit_end_row;
 7109
 7110            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7111                if provider.show_tab_accept_marker() {
 7112                    EditDisplayMode::TabAccept
 7113                } else {
 7114                    EditDisplayMode::Inline
 7115                }
 7116            } else {
 7117                EditDisplayMode::DiffPopover
 7118            };
 7119
 7120            InlineCompletion::Edit {
 7121                edits,
 7122                edit_preview: inline_completion.edit_preview,
 7123                display_mode,
 7124                snapshot,
 7125            }
 7126        };
 7127
 7128        let invalidation_range = multibuffer
 7129            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7130            ..multibuffer.anchor_after(Point::new(
 7131                invalidation_row_range.end,
 7132                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7133            ));
 7134
 7135        self.stale_inline_completion_in_menu = None;
 7136        self.active_inline_completion = Some(InlineCompletionState {
 7137            inlay_ids,
 7138            completion,
 7139            completion_id: inline_completion.id,
 7140            invalidation_range,
 7141        });
 7142
 7143        cx.notify();
 7144
 7145        Some(())
 7146    }
 7147
 7148    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7149        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7150    }
 7151
 7152    fn clear_tasks(&mut self) {
 7153        self.tasks.clear()
 7154    }
 7155
 7156    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7157        if self.tasks.insert(key, value).is_some() {
 7158            // This case should hopefully be rare, but just in case...
 7159            log::error!(
 7160                "multiple different run targets found on a single line, only the last target will be rendered"
 7161            )
 7162        }
 7163    }
 7164
 7165    /// Get all display points of breakpoints that will be rendered within editor
 7166    ///
 7167    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7168    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7169    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7170    fn active_breakpoints(
 7171        &self,
 7172        range: Range<DisplayRow>,
 7173        window: &mut Window,
 7174        cx: &mut Context<Self>,
 7175    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7176        let mut breakpoint_display_points = HashMap::default();
 7177
 7178        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7179            return breakpoint_display_points;
 7180        };
 7181
 7182        let snapshot = self.snapshot(window, cx);
 7183
 7184        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7185        let Some(project) = self.project.as_ref() else {
 7186            return breakpoint_display_points;
 7187        };
 7188
 7189        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7190            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7191
 7192        for (buffer_snapshot, range, excerpt_id) in
 7193            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7194        {
 7195            let Some(buffer) = project
 7196                .read(cx)
 7197                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7198            else {
 7199                continue;
 7200            };
 7201            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7202                &buffer,
 7203                Some(
 7204                    buffer_snapshot.anchor_before(range.start)
 7205                        ..buffer_snapshot.anchor_after(range.end),
 7206                ),
 7207                buffer_snapshot,
 7208                cx,
 7209            );
 7210            for (breakpoint, state) in breakpoints {
 7211                let multi_buffer_anchor =
 7212                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7213                let position = multi_buffer_anchor
 7214                    .to_point(&multi_buffer_snapshot)
 7215                    .to_display_point(&snapshot);
 7216
 7217                breakpoint_display_points.insert(
 7218                    position.row(),
 7219                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7220                );
 7221            }
 7222        }
 7223
 7224        breakpoint_display_points
 7225    }
 7226
 7227    fn breakpoint_context_menu(
 7228        &self,
 7229        anchor: Anchor,
 7230        window: &mut Window,
 7231        cx: &mut Context<Self>,
 7232    ) -> Entity<ui::ContextMenu> {
 7233        let weak_editor = cx.weak_entity();
 7234        let focus_handle = self.focus_handle(cx);
 7235
 7236        let row = self
 7237            .buffer
 7238            .read(cx)
 7239            .snapshot(cx)
 7240            .summary_for_anchor::<Point>(&anchor)
 7241            .row;
 7242
 7243        let breakpoint = self
 7244            .breakpoint_at_row(row, window, cx)
 7245            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7246
 7247        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7248            "Edit Log Breakpoint"
 7249        } else {
 7250            "Set Log Breakpoint"
 7251        };
 7252
 7253        let condition_breakpoint_msg = if breakpoint
 7254            .as_ref()
 7255            .is_some_and(|bp| bp.1.condition.is_some())
 7256        {
 7257            "Edit Condition Breakpoint"
 7258        } else {
 7259            "Set Condition Breakpoint"
 7260        };
 7261
 7262        let hit_condition_breakpoint_msg = if breakpoint
 7263            .as_ref()
 7264            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7265        {
 7266            "Edit Hit Condition Breakpoint"
 7267        } else {
 7268            "Set Hit Condition Breakpoint"
 7269        };
 7270
 7271        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7272            "Unset Breakpoint"
 7273        } else {
 7274            "Set Breakpoint"
 7275        };
 7276
 7277        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7278            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7279
 7280        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7281            BreakpointState::Enabled => Some("Disable"),
 7282            BreakpointState::Disabled => Some("Enable"),
 7283        });
 7284
 7285        let (anchor, breakpoint) =
 7286            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7287
 7288        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7289            menu.on_blur_subscription(Subscription::new(|| {}))
 7290                .context(focus_handle)
 7291                .when(run_to_cursor, |this| {
 7292                    let weak_editor = weak_editor.clone();
 7293                    this.entry("Run to cursor", None, move |window, cx| {
 7294                        weak_editor
 7295                            .update(cx, |editor, cx| {
 7296                                editor.change_selections(None, window, cx, |s| {
 7297                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7298                                });
 7299                            })
 7300                            .ok();
 7301
 7302                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7303                    })
 7304                    .separator()
 7305                })
 7306                .when_some(toggle_state_msg, |this, msg| {
 7307                    this.entry(msg, None, {
 7308                        let weak_editor = weak_editor.clone();
 7309                        let breakpoint = breakpoint.clone();
 7310                        move |_window, cx| {
 7311                            weak_editor
 7312                                .update(cx, |this, cx| {
 7313                                    this.edit_breakpoint_at_anchor(
 7314                                        anchor,
 7315                                        breakpoint.as_ref().clone(),
 7316                                        BreakpointEditAction::InvertState,
 7317                                        cx,
 7318                                    );
 7319                                })
 7320                                .log_err();
 7321                        }
 7322                    })
 7323                })
 7324                .entry(set_breakpoint_msg, None, {
 7325                    let weak_editor = weak_editor.clone();
 7326                    let breakpoint = breakpoint.clone();
 7327                    move |_window, cx| {
 7328                        weak_editor
 7329                            .update(cx, |this, cx| {
 7330                                this.edit_breakpoint_at_anchor(
 7331                                    anchor,
 7332                                    breakpoint.as_ref().clone(),
 7333                                    BreakpointEditAction::Toggle,
 7334                                    cx,
 7335                                );
 7336                            })
 7337                            .log_err();
 7338                    }
 7339                })
 7340                .entry(log_breakpoint_msg, None, {
 7341                    let breakpoint = breakpoint.clone();
 7342                    let weak_editor = weak_editor.clone();
 7343                    move |window, cx| {
 7344                        weak_editor
 7345                            .update(cx, |this, cx| {
 7346                                this.add_edit_breakpoint_block(
 7347                                    anchor,
 7348                                    breakpoint.as_ref(),
 7349                                    BreakpointPromptEditAction::Log,
 7350                                    window,
 7351                                    cx,
 7352                                );
 7353                            })
 7354                            .log_err();
 7355                    }
 7356                })
 7357                .entry(condition_breakpoint_msg, None, {
 7358                    let breakpoint = breakpoint.clone();
 7359                    let weak_editor = weak_editor.clone();
 7360                    move |window, cx| {
 7361                        weak_editor
 7362                            .update(cx, |this, cx| {
 7363                                this.add_edit_breakpoint_block(
 7364                                    anchor,
 7365                                    breakpoint.as_ref(),
 7366                                    BreakpointPromptEditAction::Condition,
 7367                                    window,
 7368                                    cx,
 7369                                );
 7370                            })
 7371                            .log_err();
 7372                    }
 7373                })
 7374                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7375                    weak_editor
 7376                        .update(cx, |this, cx| {
 7377                            this.add_edit_breakpoint_block(
 7378                                anchor,
 7379                                breakpoint.as_ref(),
 7380                                BreakpointPromptEditAction::HitCondition,
 7381                                window,
 7382                                cx,
 7383                            );
 7384                        })
 7385                        .log_err();
 7386                })
 7387        })
 7388    }
 7389
 7390    fn render_breakpoint(
 7391        &self,
 7392        position: Anchor,
 7393        row: DisplayRow,
 7394        breakpoint: &Breakpoint,
 7395        state: Option<BreakpointSessionState>,
 7396        cx: &mut Context<Self>,
 7397    ) -> IconButton {
 7398        let is_rejected = state.is_some_and(|s| !s.verified);
 7399        // Is it a breakpoint that shows up when hovering over gutter?
 7400        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7401            (false, false),
 7402            |PhantomBreakpointIndicator {
 7403                 is_active,
 7404                 display_row,
 7405                 collides_with_existing_breakpoint,
 7406             }| {
 7407                (
 7408                    is_active && display_row == row,
 7409                    collides_with_existing_breakpoint,
 7410                )
 7411            },
 7412        );
 7413
 7414        let (color, icon) = {
 7415            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7416                (false, false) => ui::IconName::DebugBreakpoint,
 7417                (true, false) => ui::IconName::DebugLogBreakpoint,
 7418                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7419                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7420            };
 7421
 7422            let color = if is_phantom {
 7423                Color::Hint
 7424            } else if is_rejected {
 7425                Color::Disabled
 7426            } else {
 7427                Color::Debugger
 7428            };
 7429
 7430            (color, icon)
 7431        };
 7432
 7433        let breakpoint = Arc::from(breakpoint.clone());
 7434
 7435        let alt_as_text = gpui::Keystroke {
 7436            modifiers: Modifiers::secondary_key(),
 7437            ..Default::default()
 7438        };
 7439        let primary_action_text = if breakpoint.is_disabled() {
 7440            "Enable breakpoint"
 7441        } else if is_phantom && !collides_with_existing {
 7442            "Set breakpoint"
 7443        } else {
 7444            "Unset breakpoint"
 7445        };
 7446        let focus_handle = self.focus_handle.clone();
 7447
 7448        let meta = if is_rejected {
 7449            SharedString::from("No executable code is associated with this line.")
 7450        } else if collides_with_existing && !breakpoint.is_disabled() {
 7451            SharedString::from(format!(
 7452                "{alt_as_text}-click to disable,\nright-click for more options."
 7453            ))
 7454        } else {
 7455            SharedString::from("Right-click for more options.")
 7456        };
 7457        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7458            .icon_size(IconSize::XSmall)
 7459            .size(ui::ButtonSize::None)
 7460            .when(is_rejected, |this| {
 7461                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7462            })
 7463            .icon_color(color)
 7464            .style(ButtonStyle::Transparent)
 7465            .on_click(cx.listener({
 7466                let breakpoint = breakpoint.clone();
 7467
 7468                move |editor, event: &ClickEvent, window, cx| {
 7469                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7470                        BreakpointEditAction::InvertState
 7471                    } else {
 7472                        BreakpointEditAction::Toggle
 7473                    };
 7474
 7475                    window.focus(&editor.focus_handle(cx));
 7476                    editor.edit_breakpoint_at_anchor(
 7477                        position,
 7478                        breakpoint.as_ref().clone(),
 7479                        edit_action,
 7480                        cx,
 7481                    );
 7482                }
 7483            }))
 7484            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7485                editor.set_breakpoint_context_menu(
 7486                    row,
 7487                    Some(position),
 7488                    event.down.position,
 7489                    window,
 7490                    cx,
 7491                );
 7492            }))
 7493            .tooltip(move |window, cx| {
 7494                Tooltip::with_meta_in(
 7495                    primary_action_text,
 7496                    Some(&ToggleBreakpoint),
 7497                    meta.clone(),
 7498                    &focus_handle,
 7499                    window,
 7500                    cx,
 7501                )
 7502            })
 7503    }
 7504
 7505    fn build_tasks_context(
 7506        project: &Entity<Project>,
 7507        buffer: &Entity<Buffer>,
 7508        buffer_row: u32,
 7509        tasks: &Arc<RunnableTasks>,
 7510        cx: &mut Context<Self>,
 7511    ) -> Task<Option<task::TaskContext>> {
 7512        let position = Point::new(buffer_row, tasks.column);
 7513        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7514        let location = Location {
 7515            buffer: buffer.clone(),
 7516            range: range_start..range_start,
 7517        };
 7518        // Fill in the environmental variables from the tree-sitter captures
 7519        let mut captured_task_variables = TaskVariables::default();
 7520        for (capture_name, value) in tasks.extra_variables.clone() {
 7521            captured_task_variables.insert(
 7522                task::VariableName::Custom(capture_name.into()),
 7523                value.clone(),
 7524            );
 7525        }
 7526        project.update(cx, |project, cx| {
 7527            project.task_store().update(cx, |task_store, cx| {
 7528                task_store.task_context_for_location(captured_task_variables, location, cx)
 7529            })
 7530        })
 7531    }
 7532
 7533    pub fn spawn_nearest_task(
 7534        &mut self,
 7535        action: &SpawnNearestTask,
 7536        window: &mut Window,
 7537        cx: &mut Context<Self>,
 7538    ) {
 7539        let Some((workspace, _)) = self.workspace.clone() else {
 7540            return;
 7541        };
 7542        let Some(project) = self.project.clone() else {
 7543            return;
 7544        };
 7545
 7546        // Try to find a closest, enclosing node using tree-sitter that has a
 7547        // task
 7548        let Some((buffer, buffer_row, tasks)) = self
 7549            .find_enclosing_node_task(cx)
 7550            // Or find the task that's closest in row-distance.
 7551            .or_else(|| self.find_closest_task(cx))
 7552        else {
 7553            return;
 7554        };
 7555
 7556        let reveal_strategy = action.reveal;
 7557        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7558        cx.spawn_in(window, async move |_, cx| {
 7559            let context = task_context.await?;
 7560            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7561
 7562            let resolved = &mut resolved_task.resolved;
 7563            resolved.reveal = reveal_strategy;
 7564
 7565            workspace
 7566                .update_in(cx, |workspace, window, cx| {
 7567                    workspace.schedule_resolved_task(
 7568                        task_source_kind,
 7569                        resolved_task,
 7570                        false,
 7571                        window,
 7572                        cx,
 7573                    );
 7574                })
 7575                .ok()
 7576        })
 7577        .detach();
 7578    }
 7579
 7580    fn find_closest_task(
 7581        &mut self,
 7582        cx: &mut Context<Self>,
 7583    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7584        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7585
 7586        let ((buffer_id, row), tasks) = self
 7587            .tasks
 7588            .iter()
 7589            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7590
 7591        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7592        let tasks = Arc::new(tasks.to_owned());
 7593        Some((buffer, *row, tasks))
 7594    }
 7595
 7596    fn find_enclosing_node_task(
 7597        &mut self,
 7598        cx: &mut Context<Self>,
 7599    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7600        let snapshot = self.buffer.read(cx).snapshot(cx);
 7601        let offset = self.selections.newest::<usize>(cx).head();
 7602        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7603        let buffer_id = excerpt.buffer().remote_id();
 7604
 7605        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7606        let mut cursor = layer.node().walk();
 7607
 7608        while cursor.goto_first_child_for_byte(offset).is_some() {
 7609            if cursor.node().end_byte() == offset {
 7610                cursor.goto_next_sibling();
 7611            }
 7612        }
 7613
 7614        // Ascend to the smallest ancestor that contains the range and has a task.
 7615        loop {
 7616            let node = cursor.node();
 7617            let node_range = node.byte_range();
 7618            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7619
 7620            // Check if this node contains our offset
 7621            if node_range.start <= offset && node_range.end >= offset {
 7622                // If it contains offset, check for task
 7623                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7624                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7625                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7626                }
 7627            }
 7628
 7629            if !cursor.goto_parent() {
 7630                break;
 7631            }
 7632        }
 7633        None
 7634    }
 7635
 7636    fn render_run_indicator(
 7637        &self,
 7638        _style: &EditorStyle,
 7639        is_active: bool,
 7640        row: DisplayRow,
 7641        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7642        cx: &mut Context<Self>,
 7643    ) -> IconButton {
 7644        let color = Color::Muted;
 7645        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7646
 7647        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7648            .shape(ui::IconButtonShape::Square)
 7649            .icon_size(IconSize::XSmall)
 7650            .icon_color(color)
 7651            .toggle_state(is_active)
 7652            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7653                let quick_launch = e.down.button == MouseButton::Left;
 7654                window.focus(&editor.focus_handle(cx));
 7655                editor.toggle_code_actions(
 7656                    &ToggleCodeActions {
 7657                        deployed_from: Some(CodeActionSource::Indicator(row)),
 7658                        quick_launch,
 7659                    },
 7660                    window,
 7661                    cx,
 7662                );
 7663            }))
 7664            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7665                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7666            }))
 7667    }
 7668
 7669    pub fn context_menu_visible(&self) -> bool {
 7670        !self.edit_prediction_preview_is_active()
 7671            && self
 7672                .context_menu
 7673                .borrow()
 7674                .as_ref()
 7675                .map_or(false, |menu| menu.visible())
 7676    }
 7677
 7678    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7679        self.context_menu
 7680            .borrow()
 7681            .as_ref()
 7682            .map(|menu| menu.origin())
 7683    }
 7684
 7685    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7686        self.context_menu_options = Some(options);
 7687    }
 7688
 7689    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7690    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7691
 7692    fn render_edit_prediction_popover(
 7693        &mut self,
 7694        text_bounds: &Bounds<Pixels>,
 7695        content_origin: gpui::Point<Pixels>,
 7696        right_margin: Pixels,
 7697        editor_snapshot: &EditorSnapshot,
 7698        visible_row_range: Range<DisplayRow>,
 7699        scroll_top: f32,
 7700        scroll_bottom: f32,
 7701        line_layouts: &[LineWithInvisibles],
 7702        line_height: Pixels,
 7703        scroll_pixel_position: gpui::Point<Pixels>,
 7704        newest_selection_head: Option<DisplayPoint>,
 7705        editor_width: Pixels,
 7706        style: &EditorStyle,
 7707        window: &mut Window,
 7708        cx: &mut App,
 7709    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7710        if self.mode().is_minimap() {
 7711            return None;
 7712        }
 7713        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7714
 7715        if self.edit_prediction_visible_in_cursor_popover(true) {
 7716            return None;
 7717        }
 7718
 7719        match &active_inline_completion.completion {
 7720            InlineCompletion::Move { target, .. } => {
 7721                let target_display_point = target.to_display_point(editor_snapshot);
 7722
 7723                if self.edit_prediction_requires_modifier() {
 7724                    if !self.edit_prediction_preview_is_active() {
 7725                        return None;
 7726                    }
 7727
 7728                    self.render_edit_prediction_modifier_jump_popover(
 7729                        text_bounds,
 7730                        content_origin,
 7731                        visible_row_range,
 7732                        line_layouts,
 7733                        line_height,
 7734                        scroll_pixel_position,
 7735                        newest_selection_head,
 7736                        target_display_point,
 7737                        window,
 7738                        cx,
 7739                    )
 7740                } else {
 7741                    self.render_edit_prediction_eager_jump_popover(
 7742                        text_bounds,
 7743                        content_origin,
 7744                        editor_snapshot,
 7745                        visible_row_range,
 7746                        scroll_top,
 7747                        scroll_bottom,
 7748                        line_height,
 7749                        scroll_pixel_position,
 7750                        target_display_point,
 7751                        editor_width,
 7752                        window,
 7753                        cx,
 7754                    )
 7755                }
 7756            }
 7757            InlineCompletion::Edit {
 7758                display_mode: EditDisplayMode::Inline,
 7759                ..
 7760            } => None,
 7761            InlineCompletion::Edit {
 7762                display_mode: EditDisplayMode::TabAccept,
 7763                edits,
 7764                ..
 7765            } => {
 7766                let range = &edits.first()?.0;
 7767                let target_display_point = range.end.to_display_point(editor_snapshot);
 7768
 7769                self.render_edit_prediction_end_of_line_popover(
 7770                    "Accept",
 7771                    editor_snapshot,
 7772                    visible_row_range,
 7773                    target_display_point,
 7774                    line_height,
 7775                    scroll_pixel_position,
 7776                    content_origin,
 7777                    editor_width,
 7778                    window,
 7779                    cx,
 7780                )
 7781            }
 7782            InlineCompletion::Edit {
 7783                edits,
 7784                edit_preview,
 7785                display_mode: EditDisplayMode::DiffPopover,
 7786                snapshot,
 7787            } => self.render_edit_prediction_diff_popover(
 7788                text_bounds,
 7789                content_origin,
 7790                right_margin,
 7791                editor_snapshot,
 7792                visible_row_range,
 7793                line_layouts,
 7794                line_height,
 7795                scroll_pixel_position,
 7796                newest_selection_head,
 7797                editor_width,
 7798                style,
 7799                edits,
 7800                edit_preview,
 7801                snapshot,
 7802                window,
 7803                cx,
 7804            ),
 7805        }
 7806    }
 7807
 7808    fn render_edit_prediction_modifier_jump_popover(
 7809        &mut self,
 7810        text_bounds: &Bounds<Pixels>,
 7811        content_origin: gpui::Point<Pixels>,
 7812        visible_row_range: Range<DisplayRow>,
 7813        line_layouts: &[LineWithInvisibles],
 7814        line_height: Pixels,
 7815        scroll_pixel_position: gpui::Point<Pixels>,
 7816        newest_selection_head: Option<DisplayPoint>,
 7817        target_display_point: DisplayPoint,
 7818        window: &mut Window,
 7819        cx: &mut App,
 7820    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7821        let scrolled_content_origin =
 7822            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7823
 7824        const SCROLL_PADDING_Y: Pixels = px(12.);
 7825
 7826        if target_display_point.row() < visible_row_range.start {
 7827            return self.render_edit_prediction_scroll_popover(
 7828                |_| SCROLL_PADDING_Y,
 7829                IconName::ArrowUp,
 7830                visible_row_range,
 7831                line_layouts,
 7832                newest_selection_head,
 7833                scrolled_content_origin,
 7834                window,
 7835                cx,
 7836            );
 7837        } else if target_display_point.row() >= visible_row_range.end {
 7838            return self.render_edit_prediction_scroll_popover(
 7839                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 7840                IconName::ArrowDown,
 7841                visible_row_range,
 7842                line_layouts,
 7843                newest_selection_head,
 7844                scrolled_content_origin,
 7845                window,
 7846                cx,
 7847            );
 7848        }
 7849
 7850        const POLE_WIDTH: Pixels = px(2.);
 7851
 7852        let line_layout =
 7853            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 7854        let target_column = target_display_point.column() as usize;
 7855
 7856        let target_x = line_layout.x_for_index(target_column);
 7857        let target_y =
 7858            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 7859
 7860        let flag_on_right = target_x < text_bounds.size.width / 2.;
 7861
 7862        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 7863        border_color.l += 0.001;
 7864
 7865        let mut element = v_flex()
 7866            .items_end()
 7867            .when(flag_on_right, |el| el.items_start())
 7868            .child(if flag_on_right {
 7869                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7870                    .rounded_bl(px(0.))
 7871                    .rounded_tl(px(0.))
 7872                    .border_l_2()
 7873                    .border_color(border_color)
 7874            } else {
 7875                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 7876                    .rounded_br(px(0.))
 7877                    .rounded_tr(px(0.))
 7878                    .border_r_2()
 7879                    .border_color(border_color)
 7880            })
 7881            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 7882            .into_any();
 7883
 7884        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7885
 7886        let mut origin = scrolled_content_origin + point(target_x, target_y)
 7887            - point(
 7888                if flag_on_right {
 7889                    POLE_WIDTH
 7890                } else {
 7891                    size.width - POLE_WIDTH
 7892                },
 7893                size.height - line_height,
 7894            );
 7895
 7896        origin.x = origin.x.max(content_origin.x);
 7897
 7898        element.prepaint_at(origin, window, cx);
 7899
 7900        Some((element, origin))
 7901    }
 7902
 7903    fn render_edit_prediction_scroll_popover(
 7904        &mut self,
 7905        to_y: impl Fn(Size<Pixels>) -> Pixels,
 7906        scroll_icon: IconName,
 7907        visible_row_range: Range<DisplayRow>,
 7908        line_layouts: &[LineWithInvisibles],
 7909        newest_selection_head: Option<DisplayPoint>,
 7910        scrolled_content_origin: gpui::Point<Pixels>,
 7911        window: &mut Window,
 7912        cx: &mut App,
 7913    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7914        let mut element = self
 7915            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 7916            .into_any();
 7917
 7918        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7919
 7920        let cursor = newest_selection_head?;
 7921        let cursor_row_layout =
 7922            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 7923        let cursor_column = cursor.column() as usize;
 7924
 7925        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 7926
 7927        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 7928
 7929        element.prepaint_at(origin, window, cx);
 7930        Some((element, origin))
 7931    }
 7932
 7933    fn render_edit_prediction_eager_jump_popover(
 7934        &mut self,
 7935        text_bounds: &Bounds<Pixels>,
 7936        content_origin: gpui::Point<Pixels>,
 7937        editor_snapshot: &EditorSnapshot,
 7938        visible_row_range: Range<DisplayRow>,
 7939        scroll_top: f32,
 7940        scroll_bottom: f32,
 7941        line_height: Pixels,
 7942        scroll_pixel_position: gpui::Point<Pixels>,
 7943        target_display_point: DisplayPoint,
 7944        editor_width: Pixels,
 7945        window: &mut Window,
 7946        cx: &mut App,
 7947    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7948        if target_display_point.row().as_f32() < scroll_top {
 7949            let mut element = self
 7950                .render_edit_prediction_line_popover(
 7951                    "Jump to Edit",
 7952                    Some(IconName::ArrowUp),
 7953                    window,
 7954                    cx,
 7955                )?
 7956                .into_any();
 7957
 7958            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7959            let offset = point(
 7960                (text_bounds.size.width - size.width) / 2.,
 7961                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7962            );
 7963
 7964            let origin = text_bounds.origin + offset;
 7965            element.prepaint_at(origin, window, cx);
 7966            Some((element, origin))
 7967        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 7968            let mut element = self
 7969                .render_edit_prediction_line_popover(
 7970                    "Jump to Edit",
 7971                    Some(IconName::ArrowDown),
 7972                    window,
 7973                    cx,
 7974                )?
 7975                .into_any();
 7976
 7977            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 7978            let offset = point(
 7979                (text_bounds.size.width - size.width) / 2.,
 7980                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 7981            );
 7982
 7983            let origin = text_bounds.origin + offset;
 7984            element.prepaint_at(origin, window, cx);
 7985            Some((element, origin))
 7986        } else {
 7987            self.render_edit_prediction_end_of_line_popover(
 7988                "Jump to Edit",
 7989                editor_snapshot,
 7990                visible_row_range,
 7991                target_display_point,
 7992                line_height,
 7993                scroll_pixel_position,
 7994                content_origin,
 7995                editor_width,
 7996                window,
 7997                cx,
 7998            )
 7999        }
 8000    }
 8001
 8002    fn render_edit_prediction_end_of_line_popover(
 8003        self: &mut Editor,
 8004        label: &'static str,
 8005        editor_snapshot: &EditorSnapshot,
 8006        visible_row_range: Range<DisplayRow>,
 8007        target_display_point: DisplayPoint,
 8008        line_height: Pixels,
 8009        scroll_pixel_position: gpui::Point<Pixels>,
 8010        content_origin: gpui::Point<Pixels>,
 8011        editor_width: Pixels,
 8012        window: &mut Window,
 8013        cx: &mut App,
 8014    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8015        let target_line_end = DisplayPoint::new(
 8016            target_display_point.row(),
 8017            editor_snapshot.line_len(target_display_point.row()),
 8018        );
 8019
 8020        let mut element = self
 8021            .render_edit_prediction_line_popover(label, None, window, cx)?
 8022            .into_any();
 8023
 8024        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8025
 8026        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8027
 8028        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8029        let mut origin = start_point
 8030            + line_origin
 8031            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8032        origin.x = origin.x.max(content_origin.x);
 8033
 8034        let max_x = content_origin.x + editor_width - size.width;
 8035
 8036        if origin.x > max_x {
 8037            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8038
 8039            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8040                origin.y += offset;
 8041                IconName::ArrowUp
 8042            } else {
 8043                origin.y -= offset;
 8044                IconName::ArrowDown
 8045            };
 8046
 8047            element = self
 8048                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8049                .into_any();
 8050
 8051            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8052
 8053            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8054        }
 8055
 8056        element.prepaint_at(origin, window, cx);
 8057        Some((element, origin))
 8058    }
 8059
 8060    fn render_edit_prediction_diff_popover(
 8061        self: &Editor,
 8062        text_bounds: &Bounds<Pixels>,
 8063        content_origin: gpui::Point<Pixels>,
 8064        right_margin: Pixels,
 8065        editor_snapshot: &EditorSnapshot,
 8066        visible_row_range: Range<DisplayRow>,
 8067        line_layouts: &[LineWithInvisibles],
 8068        line_height: Pixels,
 8069        scroll_pixel_position: gpui::Point<Pixels>,
 8070        newest_selection_head: Option<DisplayPoint>,
 8071        editor_width: Pixels,
 8072        style: &EditorStyle,
 8073        edits: &Vec<(Range<Anchor>, String)>,
 8074        edit_preview: &Option<language::EditPreview>,
 8075        snapshot: &language::BufferSnapshot,
 8076        window: &mut Window,
 8077        cx: &mut App,
 8078    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8079        let edit_start = edits
 8080            .first()
 8081            .unwrap()
 8082            .0
 8083            .start
 8084            .to_display_point(editor_snapshot);
 8085        let edit_end = edits
 8086            .last()
 8087            .unwrap()
 8088            .0
 8089            .end
 8090            .to_display_point(editor_snapshot);
 8091
 8092        let is_visible = visible_row_range.contains(&edit_start.row())
 8093            || visible_row_range.contains(&edit_end.row());
 8094        if !is_visible {
 8095            return None;
 8096        }
 8097
 8098        let highlighted_edits =
 8099            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8100
 8101        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8102        let line_count = highlighted_edits.text.lines().count();
 8103
 8104        const BORDER_WIDTH: Pixels = px(1.);
 8105
 8106        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8107        let has_keybind = keybind.is_some();
 8108
 8109        let mut element = h_flex()
 8110            .items_start()
 8111            .child(
 8112                h_flex()
 8113                    .bg(cx.theme().colors().editor_background)
 8114                    .border(BORDER_WIDTH)
 8115                    .shadow_sm()
 8116                    .border_color(cx.theme().colors().border)
 8117                    .rounded_l_lg()
 8118                    .when(line_count > 1, |el| el.rounded_br_lg())
 8119                    .pr_1()
 8120                    .child(styled_text),
 8121            )
 8122            .child(
 8123                h_flex()
 8124                    .h(line_height + BORDER_WIDTH * 2.)
 8125                    .px_1p5()
 8126                    .gap_1()
 8127                    // Workaround: For some reason, there's a gap if we don't do this
 8128                    .ml(-BORDER_WIDTH)
 8129                    .shadow(vec![gpui::BoxShadow {
 8130                        color: gpui::black().opacity(0.05),
 8131                        offset: point(px(1.), px(1.)),
 8132                        blur_radius: px(2.),
 8133                        spread_radius: px(0.),
 8134                    }])
 8135                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8136                    .border(BORDER_WIDTH)
 8137                    .border_color(cx.theme().colors().border)
 8138                    .rounded_r_lg()
 8139                    .id("edit_prediction_diff_popover_keybind")
 8140                    .when(!has_keybind, |el| {
 8141                        let status_colors = cx.theme().status();
 8142
 8143                        el.bg(status_colors.error_background)
 8144                            .border_color(status_colors.error.opacity(0.6))
 8145                            .child(Icon::new(IconName::Info).color(Color::Error))
 8146                            .cursor_default()
 8147                            .hoverable_tooltip(move |_window, cx| {
 8148                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8149                            })
 8150                    })
 8151                    .children(keybind),
 8152            )
 8153            .into_any();
 8154
 8155        let longest_row =
 8156            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8157        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8158            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8159        } else {
 8160            layout_line(
 8161                longest_row,
 8162                editor_snapshot,
 8163                style,
 8164                editor_width,
 8165                |_| false,
 8166                window,
 8167                cx,
 8168            )
 8169            .width
 8170        };
 8171
 8172        let viewport_bounds =
 8173            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8174                right: -right_margin,
 8175                ..Default::default()
 8176            });
 8177
 8178        let x_after_longest =
 8179            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8180                - scroll_pixel_position.x;
 8181
 8182        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8183
 8184        // Fully visible if it can be displayed within the window (allow overlapping other
 8185        // panes). However, this is only allowed if the popover starts within text_bounds.
 8186        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8187            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8188
 8189        let mut origin = if can_position_to_the_right {
 8190            point(
 8191                x_after_longest,
 8192                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8193                    - scroll_pixel_position.y,
 8194            )
 8195        } else {
 8196            let cursor_row = newest_selection_head.map(|head| head.row());
 8197            let above_edit = edit_start
 8198                .row()
 8199                .0
 8200                .checked_sub(line_count as u32)
 8201                .map(DisplayRow);
 8202            let below_edit = Some(edit_end.row() + 1);
 8203            let above_cursor =
 8204                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8205            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8206
 8207            // Place the edit popover adjacent to the edit if there is a location
 8208            // available that is onscreen and does not obscure the cursor. Otherwise,
 8209            // place it adjacent to the cursor.
 8210            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8211                .into_iter()
 8212                .flatten()
 8213                .find(|&start_row| {
 8214                    let end_row = start_row + line_count as u32;
 8215                    visible_row_range.contains(&start_row)
 8216                        && visible_row_range.contains(&end_row)
 8217                        && cursor_row.map_or(true, |cursor_row| {
 8218                            !((start_row..end_row).contains(&cursor_row))
 8219                        })
 8220                })?;
 8221
 8222            content_origin
 8223                + point(
 8224                    -scroll_pixel_position.x,
 8225                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8226                )
 8227        };
 8228
 8229        origin.x -= BORDER_WIDTH;
 8230
 8231        window.defer_draw(element, origin, 1);
 8232
 8233        // Do not return an element, since it will already be drawn due to defer_draw.
 8234        None
 8235    }
 8236
 8237    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8238        px(30.)
 8239    }
 8240
 8241    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8242        if self.read_only(cx) {
 8243            cx.theme().players().read_only()
 8244        } else {
 8245            self.style.as_ref().unwrap().local_player
 8246        }
 8247    }
 8248
 8249    fn render_edit_prediction_accept_keybind(
 8250        &self,
 8251        window: &mut Window,
 8252        cx: &App,
 8253    ) -> Option<AnyElement> {
 8254        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8255        let accept_keystroke = accept_binding.keystroke()?;
 8256
 8257        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8258
 8259        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8260            Color::Accent
 8261        } else {
 8262            Color::Muted
 8263        };
 8264
 8265        h_flex()
 8266            .px_0p5()
 8267            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8268            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8269            .text_size(TextSize::XSmall.rems(cx))
 8270            .child(h_flex().children(ui::render_modifiers(
 8271                &accept_keystroke.modifiers,
 8272                PlatformStyle::platform(),
 8273                Some(modifiers_color),
 8274                Some(IconSize::XSmall.rems().into()),
 8275                true,
 8276            )))
 8277            .when(is_platform_style_mac, |parent| {
 8278                parent.child(accept_keystroke.key.clone())
 8279            })
 8280            .when(!is_platform_style_mac, |parent| {
 8281                parent.child(
 8282                    Key::new(
 8283                        util::capitalize(&accept_keystroke.key),
 8284                        Some(Color::Default),
 8285                    )
 8286                    .size(Some(IconSize::XSmall.rems().into())),
 8287                )
 8288            })
 8289            .into_any()
 8290            .into()
 8291    }
 8292
 8293    fn render_edit_prediction_line_popover(
 8294        &self,
 8295        label: impl Into<SharedString>,
 8296        icon: Option<IconName>,
 8297        window: &mut Window,
 8298        cx: &App,
 8299    ) -> Option<Stateful<Div>> {
 8300        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8301
 8302        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8303        let has_keybind = keybind.is_some();
 8304
 8305        let result = h_flex()
 8306            .id("ep-line-popover")
 8307            .py_0p5()
 8308            .pl_1()
 8309            .pr(padding_right)
 8310            .gap_1()
 8311            .rounded_md()
 8312            .border_1()
 8313            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8314            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8315            .shadow_sm()
 8316            .when(!has_keybind, |el| {
 8317                let status_colors = cx.theme().status();
 8318
 8319                el.bg(status_colors.error_background)
 8320                    .border_color(status_colors.error.opacity(0.6))
 8321                    .pl_2()
 8322                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8323                    .cursor_default()
 8324                    .hoverable_tooltip(move |_window, cx| {
 8325                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8326                    })
 8327            })
 8328            .children(keybind)
 8329            .child(
 8330                Label::new(label)
 8331                    .size(LabelSize::Small)
 8332                    .when(!has_keybind, |el| {
 8333                        el.color(cx.theme().status().error.into()).strikethrough()
 8334                    }),
 8335            )
 8336            .when(!has_keybind, |el| {
 8337                el.child(
 8338                    h_flex().ml_1().child(
 8339                        Icon::new(IconName::Info)
 8340                            .size(IconSize::Small)
 8341                            .color(cx.theme().status().error.into()),
 8342                    ),
 8343                )
 8344            })
 8345            .when_some(icon, |element, icon| {
 8346                element.child(
 8347                    div()
 8348                        .mt(px(1.5))
 8349                        .child(Icon::new(icon).size(IconSize::Small)),
 8350                )
 8351            });
 8352
 8353        Some(result)
 8354    }
 8355
 8356    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8357        let accent_color = cx.theme().colors().text_accent;
 8358        let editor_bg_color = cx.theme().colors().editor_background;
 8359        editor_bg_color.blend(accent_color.opacity(0.1))
 8360    }
 8361
 8362    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8363        let accent_color = cx.theme().colors().text_accent;
 8364        let editor_bg_color = cx.theme().colors().editor_background;
 8365        editor_bg_color.blend(accent_color.opacity(0.6))
 8366    }
 8367
 8368    fn render_edit_prediction_cursor_popover(
 8369        &self,
 8370        min_width: Pixels,
 8371        max_width: Pixels,
 8372        cursor_point: Point,
 8373        style: &EditorStyle,
 8374        accept_keystroke: Option<&gpui::Keystroke>,
 8375        _window: &Window,
 8376        cx: &mut Context<Editor>,
 8377    ) -> Option<AnyElement> {
 8378        let provider = self.edit_prediction_provider.as_ref()?;
 8379
 8380        if provider.provider.needs_terms_acceptance(cx) {
 8381            return Some(
 8382                h_flex()
 8383                    .min_w(min_width)
 8384                    .flex_1()
 8385                    .px_2()
 8386                    .py_1()
 8387                    .gap_3()
 8388                    .elevation_2(cx)
 8389                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8390                    .id("accept-terms")
 8391                    .cursor_pointer()
 8392                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8393                    .on_click(cx.listener(|this, _event, window, cx| {
 8394                        cx.stop_propagation();
 8395                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8396                        window.dispatch_action(
 8397                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8398                            cx,
 8399                        );
 8400                    }))
 8401                    .child(
 8402                        h_flex()
 8403                            .flex_1()
 8404                            .gap_2()
 8405                            .child(Icon::new(IconName::ZedPredict))
 8406                            .child(Label::new("Accept Terms of Service"))
 8407                            .child(div().w_full())
 8408                            .child(
 8409                                Icon::new(IconName::ArrowUpRight)
 8410                                    .color(Color::Muted)
 8411                                    .size(IconSize::Small),
 8412                            )
 8413                            .into_any_element(),
 8414                    )
 8415                    .into_any(),
 8416            );
 8417        }
 8418
 8419        let is_refreshing = provider.provider.is_refreshing(cx);
 8420
 8421        fn pending_completion_container() -> Div {
 8422            h_flex()
 8423                .h_full()
 8424                .flex_1()
 8425                .gap_2()
 8426                .child(Icon::new(IconName::ZedPredict))
 8427        }
 8428
 8429        let completion = match &self.active_inline_completion {
 8430            Some(prediction) => {
 8431                if !self.has_visible_completions_menu() {
 8432                    const RADIUS: Pixels = px(6.);
 8433                    const BORDER_WIDTH: Pixels = px(1.);
 8434
 8435                    return Some(
 8436                        h_flex()
 8437                            .elevation_2(cx)
 8438                            .border(BORDER_WIDTH)
 8439                            .border_color(cx.theme().colors().border)
 8440                            .when(accept_keystroke.is_none(), |el| {
 8441                                el.border_color(cx.theme().status().error)
 8442                            })
 8443                            .rounded(RADIUS)
 8444                            .rounded_tl(px(0.))
 8445                            .overflow_hidden()
 8446                            .child(div().px_1p5().child(match &prediction.completion {
 8447                                InlineCompletion::Move { target, snapshot } => {
 8448                                    use text::ToPoint as _;
 8449                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8450                                    {
 8451                                        Icon::new(IconName::ZedPredictDown)
 8452                                    } else {
 8453                                        Icon::new(IconName::ZedPredictUp)
 8454                                    }
 8455                                }
 8456                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8457                            }))
 8458                            .child(
 8459                                h_flex()
 8460                                    .gap_1()
 8461                                    .py_1()
 8462                                    .px_2()
 8463                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8464                                    .border_l_1()
 8465                                    .border_color(cx.theme().colors().border)
 8466                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8467                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8468                                        el.child(
 8469                                            Label::new("Hold")
 8470                                                .size(LabelSize::Small)
 8471                                                .when(accept_keystroke.is_none(), |el| {
 8472                                                    el.strikethrough()
 8473                                                })
 8474                                                .line_height_style(LineHeightStyle::UiLabel),
 8475                                        )
 8476                                    })
 8477                                    .id("edit_prediction_cursor_popover_keybind")
 8478                                    .when(accept_keystroke.is_none(), |el| {
 8479                                        let status_colors = cx.theme().status();
 8480
 8481                                        el.bg(status_colors.error_background)
 8482                                            .border_color(status_colors.error.opacity(0.6))
 8483                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8484                                            .cursor_default()
 8485                                            .hoverable_tooltip(move |_window, cx| {
 8486                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8487                                                    .into()
 8488                                            })
 8489                                    })
 8490                                    .when_some(
 8491                                        accept_keystroke.as_ref(),
 8492                                        |el, accept_keystroke| {
 8493                                            el.child(h_flex().children(ui::render_modifiers(
 8494                                                &accept_keystroke.modifiers,
 8495                                                PlatformStyle::platform(),
 8496                                                Some(Color::Default),
 8497                                                Some(IconSize::XSmall.rems().into()),
 8498                                                false,
 8499                                            )))
 8500                                        },
 8501                                    ),
 8502                            )
 8503                            .into_any(),
 8504                    );
 8505                }
 8506
 8507                self.render_edit_prediction_cursor_popover_preview(
 8508                    prediction,
 8509                    cursor_point,
 8510                    style,
 8511                    cx,
 8512                )?
 8513            }
 8514
 8515            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8516                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8517                    stale_completion,
 8518                    cursor_point,
 8519                    style,
 8520                    cx,
 8521                )?,
 8522
 8523                None => {
 8524                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8525                }
 8526            },
 8527
 8528            None => pending_completion_container().child(Label::new("No Prediction")),
 8529        };
 8530
 8531        let completion = if is_refreshing {
 8532            completion
 8533                .with_animation(
 8534                    "loading-completion",
 8535                    Animation::new(Duration::from_secs(2))
 8536                        .repeat()
 8537                        .with_easing(pulsating_between(0.4, 0.8)),
 8538                    |label, delta| label.opacity(delta),
 8539                )
 8540                .into_any_element()
 8541        } else {
 8542            completion.into_any_element()
 8543        };
 8544
 8545        let has_completion = self.active_inline_completion.is_some();
 8546
 8547        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8548        Some(
 8549            h_flex()
 8550                .min_w(min_width)
 8551                .max_w(max_width)
 8552                .flex_1()
 8553                .elevation_2(cx)
 8554                .border_color(cx.theme().colors().border)
 8555                .child(
 8556                    div()
 8557                        .flex_1()
 8558                        .py_1()
 8559                        .px_2()
 8560                        .overflow_hidden()
 8561                        .child(completion),
 8562                )
 8563                .when_some(accept_keystroke, |el, accept_keystroke| {
 8564                    if !accept_keystroke.modifiers.modified() {
 8565                        return el;
 8566                    }
 8567
 8568                    el.child(
 8569                        h_flex()
 8570                            .h_full()
 8571                            .border_l_1()
 8572                            .rounded_r_lg()
 8573                            .border_color(cx.theme().colors().border)
 8574                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8575                            .gap_1()
 8576                            .py_1()
 8577                            .px_2()
 8578                            .child(
 8579                                h_flex()
 8580                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8581                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8582                                    .child(h_flex().children(ui::render_modifiers(
 8583                                        &accept_keystroke.modifiers,
 8584                                        PlatformStyle::platform(),
 8585                                        Some(if !has_completion {
 8586                                            Color::Muted
 8587                                        } else {
 8588                                            Color::Default
 8589                                        }),
 8590                                        None,
 8591                                        false,
 8592                                    ))),
 8593                            )
 8594                            .child(Label::new("Preview").into_any_element())
 8595                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8596                    )
 8597                })
 8598                .into_any(),
 8599        )
 8600    }
 8601
 8602    fn render_edit_prediction_cursor_popover_preview(
 8603        &self,
 8604        completion: &InlineCompletionState,
 8605        cursor_point: Point,
 8606        style: &EditorStyle,
 8607        cx: &mut Context<Editor>,
 8608    ) -> Option<Div> {
 8609        use text::ToPoint as _;
 8610
 8611        fn render_relative_row_jump(
 8612            prefix: impl Into<String>,
 8613            current_row: u32,
 8614            target_row: u32,
 8615        ) -> Div {
 8616            let (row_diff, arrow) = if target_row < current_row {
 8617                (current_row - target_row, IconName::ArrowUp)
 8618            } else {
 8619                (target_row - current_row, IconName::ArrowDown)
 8620            };
 8621
 8622            h_flex()
 8623                .child(
 8624                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8625                        .color(Color::Muted)
 8626                        .size(LabelSize::Small),
 8627                )
 8628                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8629        }
 8630
 8631        match &completion.completion {
 8632            InlineCompletion::Move {
 8633                target, snapshot, ..
 8634            } => Some(
 8635                h_flex()
 8636                    .px_2()
 8637                    .gap_2()
 8638                    .flex_1()
 8639                    .child(
 8640                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8641                            Icon::new(IconName::ZedPredictDown)
 8642                        } else {
 8643                            Icon::new(IconName::ZedPredictUp)
 8644                        },
 8645                    )
 8646                    .child(Label::new("Jump to Edit")),
 8647            ),
 8648
 8649            InlineCompletion::Edit {
 8650                edits,
 8651                edit_preview,
 8652                snapshot,
 8653                display_mode: _,
 8654            } => {
 8655                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8656
 8657                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8658                    &snapshot,
 8659                    &edits,
 8660                    edit_preview.as_ref()?,
 8661                    true,
 8662                    cx,
 8663                )
 8664                .first_line_preview();
 8665
 8666                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8667                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8668
 8669                let preview = h_flex()
 8670                    .gap_1()
 8671                    .min_w_16()
 8672                    .child(styled_text)
 8673                    .when(has_more_lines, |parent| parent.child(""));
 8674
 8675                let left = if first_edit_row != cursor_point.row {
 8676                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8677                        .into_any_element()
 8678                } else {
 8679                    Icon::new(IconName::ZedPredict).into_any_element()
 8680                };
 8681
 8682                Some(
 8683                    h_flex()
 8684                        .h_full()
 8685                        .flex_1()
 8686                        .gap_2()
 8687                        .pr_1()
 8688                        .overflow_x_hidden()
 8689                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8690                        .child(left)
 8691                        .child(preview),
 8692                )
 8693            }
 8694        }
 8695    }
 8696
 8697    pub fn render_context_menu(
 8698        &self,
 8699        style: &EditorStyle,
 8700        max_height_in_lines: u32,
 8701        window: &mut Window,
 8702        cx: &mut Context<Editor>,
 8703    ) -> Option<AnyElement> {
 8704        let menu = self.context_menu.borrow();
 8705        let menu = menu.as_ref()?;
 8706        if !menu.visible() {
 8707            return None;
 8708        };
 8709        Some(menu.render(style, max_height_in_lines, window, cx))
 8710    }
 8711
 8712    fn render_context_menu_aside(
 8713        &mut self,
 8714        max_size: Size<Pixels>,
 8715        window: &mut Window,
 8716        cx: &mut Context<Editor>,
 8717    ) -> Option<AnyElement> {
 8718        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8719            if menu.visible() {
 8720                menu.render_aside(max_size, window, cx)
 8721            } else {
 8722                None
 8723            }
 8724        })
 8725    }
 8726
 8727    fn hide_context_menu(
 8728        &mut self,
 8729        window: &mut Window,
 8730        cx: &mut Context<Self>,
 8731    ) -> Option<CodeContextMenu> {
 8732        cx.notify();
 8733        self.completion_tasks.clear();
 8734        let context_menu = self.context_menu.borrow_mut().take();
 8735        self.stale_inline_completion_in_menu.take();
 8736        self.update_visible_inline_completion(window, cx);
 8737        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 8738            if let Some(completion_provider) = &self.completion_provider {
 8739                completion_provider.selection_changed(None, window, cx);
 8740            }
 8741        }
 8742        context_menu
 8743    }
 8744
 8745    fn show_snippet_choices(
 8746        &mut self,
 8747        choices: &Vec<String>,
 8748        selection: Range<Anchor>,
 8749        cx: &mut Context<Self>,
 8750    ) {
 8751        if selection.start.buffer_id.is_none() {
 8752            return;
 8753        }
 8754        let buffer_id = selection.start.buffer_id.unwrap();
 8755        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8756        let id = post_inc(&mut self.next_completion_id);
 8757        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8758
 8759        if let Some(buffer) = buffer {
 8760            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8761                CompletionsMenu::new_snippet_choices(
 8762                    id,
 8763                    true,
 8764                    choices,
 8765                    selection,
 8766                    buffer,
 8767                    snippet_sort_order,
 8768                ),
 8769            ));
 8770        }
 8771    }
 8772
 8773    pub fn insert_snippet(
 8774        &mut self,
 8775        insertion_ranges: &[Range<usize>],
 8776        snippet: Snippet,
 8777        window: &mut Window,
 8778        cx: &mut Context<Self>,
 8779    ) -> Result<()> {
 8780        struct Tabstop<T> {
 8781            is_end_tabstop: bool,
 8782            ranges: Vec<Range<T>>,
 8783            choices: Option<Vec<String>>,
 8784        }
 8785
 8786        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8787            let snippet_text: Arc<str> = snippet.text.clone().into();
 8788            let edits = insertion_ranges
 8789                .iter()
 8790                .cloned()
 8791                .map(|range| (range, snippet_text.clone()));
 8792            buffer.edit(edits, Some(AutoindentMode::EachLine), cx);
 8793
 8794            let snapshot = &*buffer.read(cx);
 8795            let snippet = &snippet;
 8796            snippet
 8797                .tabstops
 8798                .iter()
 8799                .map(|tabstop| {
 8800                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8801                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8802                    });
 8803                    let mut tabstop_ranges = tabstop
 8804                        .ranges
 8805                        .iter()
 8806                        .flat_map(|tabstop_range| {
 8807                            let mut delta = 0_isize;
 8808                            insertion_ranges.iter().map(move |insertion_range| {
 8809                                let insertion_start = insertion_range.start as isize + delta;
 8810                                delta +=
 8811                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8812
 8813                                let start = ((insertion_start + tabstop_range.start) as usize)
 8814                                    .min(snapshot.len());
 8815                                let end = ((insertion_start + tabstop_range.end) as usize)
 8816                                    .min(snapshot.len());
 8817                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8818                            })
 8819                        })
 8820                        .collect::<Vec<_>>();
 8821                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 8822
 8823                    Tabstop {
 8824                        is_end_tabstop,
 8825                        ranges: tabstop_ranges,
 8826                        choices: tabstop.choices.clone(),
 8827                    }
 8828                })
 8829                .collect::<Vec<_>>()
 8830        });
 8831        if let Some(tabstop) = tabstops.first() {
 8832            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8833                s.select_ranges(tabstop.ranges.iter().cloned());
 8834            });
 8835
 8836            if let Some(choices) = &tabstop.choices {
 8837                if let Some(selection) = tabstop.ranges.first() {
 8838                    self.show_snippet_choices(choices, selection.clone(), cx)
 8839                }
 8840            }
 8841
 8842            // If we're already at the last tabstop and it's at the end of the snippet,
 8843            // we're done, we don't need to keep the state around.
 8844            if !tabstop.is_end_tabstop {
 8845                let choices = tabstops
 8846                    .iter()
 8847                    .map(|tabstop| tabstop.choices.clone())
 8848                    .collect();
 8849
 8850                let ranges = tabstops
 8851                    .into_iter()
 8852                    .map(|tabstop| tabstop.ranges)
 8853                    .collect::<Vec<_>>();
 8854
 8855                self.snippet_stack.push(SnippetState {
 8856                    active_index: 0,
 8857                    ranges,
 8858                    choices,
 8859                });
 8860            }
 8861
 8862            // Check whether the just-entered snippet ends with an auto-closable bracket.
 8863            if self.autoclose_regions.is_empty() {
 8864                let snapshot = self.buffer.read(cx).snapshot(cx);
 8865                for selection in &mut self.selections.all::<Point>(cx) {
 8866                    let selection_head = selection.head();
 8867                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 8868                        continue;
 8869                    };
 8870
 8871                    let mut bracket_pair = None;
 8872                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 8873                    let prev_chars = snapshot
 8874                        .reversed_chars_at(selection_head)
 8875                        .collect::<String>();
 8876                    for (pair, enabled) in scope.brackets() {
 8877                        if enabled
 8878                            && pair.close
 8879                            && prev_chars.starts_with(pair.start.as_str())
 8880                            && next_chars.starts_with(pair.end.as_str())
 8881                        {
 8882                            bracket_pair = Some(pair.clone());
 8883                            break;
 8884                        }
 8885                    }
 8886                    if let Some(pair) = bracket_pair {
 8887                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 8888                        let autoclose_enabled =
 8889                            self.use_autoclose && snapshot_settings.use_autoclose;
 8890                        if autoclose_enabled {
 8891                            let start = snapshot.anchor_after(selection_head);
 8892                            let end = snapshot.anchor_after(selection_head);
 8893                            self.autoclose_regions.push(AutocloseRegion {
 8894                                selection_id: selection.id,
 8895                                range: start..end,
 8896                                pair,
 8897                            });
 8898                        }
 8899                    }
 8900                }
 8901            }
 8902        }
 8903        Ok(())
 8904    }
 8905
 8906    pub fn move_to_next_snippet_tabstop(
 8907        &mut self,
 8908        window: &mut Window,
 8909        cx: &mut Context<Self>,
 8910    ) -> bool {
 8911        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 8912    }
 8913
 8914    pub fn move_to_prev_snippet_tabstop(
 8915        &mut self,
 8916        window: &mut Window,
 8917        cx: &mut Context<Self>,
 8918    ) -> bool {
 8919        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 8920    }
 8921
 8922    pub fn move_to_snippet_tabstop(
 8923        &mut self,
 8924        bias: Bias,
 8925        window: &mut Window,
 8926        cx: &mut Context<Self>,
 8927    ) -> bool {
 8928        if let Some(mut snippet) = self.snippet_stack.pop() {
 8929            match bias {
 8930                Bias::Left => {
 8931                    if snippet.active_index > 0 {
 8932                        snippet.active_index -= 1;
 8933                    } else {
 8934                        self.snippet_stack.push(snippet);
 8935                        return false;
 8936                    }
 8937                }
 8938                Bias::Right => {
 8939                    if snippet.active_index + 1 < snippet.ranges.len() {
 8940                        snippet.active_index += 1;
 8941                    } else {
 8942                        self.snippet_stack.push(snippet);
 8943                        return false;
 8944                    }
 8945                }
 8946            }
 8947            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 8948                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 8949                    s.select_anchor_ranges(current_ranges.iter().cloned())
 8950                });
 8951
 8952                if let Some(choices) = &snippet.choices[snippet.active_index] {
 8953                    if let Some(selection) = current_ranges.first() {
 8954                        self.show_snippet_choices(&choices, selection.clone(), cx);
 8955                    }
 8956                }
 8957
 8958                // If snippet state is not at the last tabstop, push it back on the stack
 8959                if snippet.active_index + 1 < snippet.ranges.len() {
 8960                    self.snippet_stack.push(snippet);
 8961                }
 8962                return true;
 8963            }
 8964        }
 8965
 8966        false
 8967    }
 8968
 8969    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8970        self.transact(window, cx, |this, window, cx| {
 8971            this.select_all(&SelectAll, window, cx);
 8972            this.insert("", window, cx);
 8973        });
 8974    }
 8975
 8976    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 8977        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 8978        self.transact(window, cx, |this, window, cx| {
 8979            this.select_autoclose_pair(window, cx);
 8980            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 8981            if !this.linked_edit_ranges.is_empty() {
 8982                let selections = this.selections.all::<MultiBufferPoint>(cx);
 8983                let snapshot = this.buffer.read(cx).snapshot(cx);
 8984
 8985                for selection in selections.iter() {
 8986                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 8987                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 8988                    if selection_start.buffer_id != selection_end.buffer_id {
 8989                        continue;
 8990                    }
 8991                    if let Some(ranges) =
 8992                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 8993                    {
 8994                        for (buffer, entries) in ranges {
 8995                            linked_ranges.entry(buffer).or_default().extend(entries);
 8996                        }
 8997                    }
 8998                }
 8999            }
 9000
 9001            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9002            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9003            for selection in &mut selections {
 9004                if selection.is_empty() {
 9005                    let old_head = selection.head();
 9006                    let mut new_head =
 9007                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9008                            .to_point(&display_map);
 9009                    if let Some((buffer, line_buffer_range)) = display_map
 9010                        .buffer_snapshot
 9011                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9012                    {
 9013                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9014                        let indent_len = match indent_size.kind {
 9015                            IndentKind::Space => {
 9016                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9017                            }
 9018                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9019                        };
 9020                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9021                            let indent_len = indent_len.get();
 9022                            new_head = cmp::min(
 9023                                new_head,
 9024                                MultiBufferPoint::new(
 9025                                    old_head.row,
 9026                                    ((old_head.column - 1) / indent_len) * indent_len,
 9027                                ),
 9028                            );
 9029                        }
 9030                    }
 9031
 9032                    selection.set_head(new_head, SelectionGoal::None);
 9033                }
 9034            }
 9035
 9036            this.signature_help_state.set_backspace_pressed(true);
 9037            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9038                s.select(selections)
 9039            });
 9040            this.insert("", window, cx);
 9041            let empty_str: Arc<str> = Arc::from("");
 9042            for (buffer, edits) in linked_ranges {
 9043                let snapshot = buffer.read(cx).snapshot();
 9044                use text::ToPoint as TP;
 9045
 9046                let edits = edits
 9047                    .into_iter()
 9048                    .map(|range| {
 9049                        let end_point = TP::to_point(&range.end, &snapshot);
 9050                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9051
 9052                        if end_point == start_point {
 9053                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9054                                .saturating_sub(1);
 9055                            start_point =
 9056                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9057                        };
 9058
 9059                        (start_point..end_point, empty_str.clone())
 9060                    })
 9061                    .sorted_by_key(|(range, _)| range.start)
 9062                    .collect::<Vec<_>>();
 9063                buffer.update(cx, |this, cx| {
 9064                    this.edit(edits, None, cx);
 9065                })
 9066            }
 9067            this.refresh_inline_completion(true, false, window, cx);
 9068            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9069        });
 9070    }
 9071
 9072    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9073        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9074        self.transact(window, cx, |this, window, cx| {
 9075            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9076                s.move_with(|map, selection| {
 9077                    if selection.is_empty() {
 9078                        let cursor = movement::right(map, selection.head());
 9079                        selection.end = cursor;
 9080                        selection.reversed = true;
 9081                        selection.goal = SelectionGoal::None;
 9082                    }
 9083                })
 9084            });
 9085            this.insert("", window, cx);
 9086            this.refresh_inline_completion(true, false, window, cx);
 9087        });
 9088    }
 9089
 9090    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9091        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9092        if self.move_to_prev_snippet_tabstop(window, cx) {
 9093            return;
 9094        }
 9095        self.outdent(&Outdent, window, cx);
 9096    }
 9097
 9098    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9099        if self.move_to_next_snippet_tabstop(window, cx) {
 9100            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9101            return;
 9102        }
 9103        if self.read_only(cx) {
 9104            return;
 9105        }
 9106        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9107        let mut selections = self.selections.all_adjusted(cx);
 9108        let buffer = self.buffer.read(cx);
 9109        let snapshot = buffer.snapshot(cx);
 9110        let rows_iter = selections.iter().map(|s| s.head().row);
 9111        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9112
 9113        let has_some_cursor_in_whitespace = selections
 9114            .iter()
 9115            .filter(|selection| selection.is_empty())
 9116            .any(|selection| {
 9117                let cursor = selection.head();
 9118                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9119                cursor.column < current_indent.len
 9120            });
 9121
 9122        let mut edits = Vec::new();
 9123        let mut prev_edited_row = 0;
 9124        let mut row_delta = 0;
 9125        for selection in &mut selections {
 9126            if selection.start.row != prev_edited_row {
 9127                row_delta = 0;
 9128            }
 9129            prev_edited_row = selection.end.row;
 9130
 9131            // If the selection is non-empty, then increase the indentation of the selected lines.
 9132            if !selection.is_empty() {
 9133                row_delta =
 9134                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9135                continue;
 9136            }
 9137
 9138            let cursor = selection.head();
 9139            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9140            if let Some(suggested_indent) =
 9141                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9142            {
 9143                // Don't do anything if already at suggested indent
 9144                // and there is any other cursor which is not
 9145                if has_some_cursor_in_whitespace
 9146                    && cursor.column == current_indent.len
 9147                    && current_indent.len == suggested_indent.len
 9148                {
 9149                    continue;
 9150                }
 9151
 9152                // Adjust line and move cursor to suggested indent
 9153                // if cursor is not at suggested indent
 9154                if cursor.column < suggested_indent.len
 9155                    && cursor.column <= current_indent.len
 9156                    && current_indent.len <= suggested_indent.len
 9157                {
 9158                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9159                    selection.end = selection.start;
 9160                    if row_delta == 0 {
 9161                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9162                            cursor.row,
 9163                            current_indent,
 9164                            suggested_indent,
 9165                        ));
 9166                        row_delta = suggested_indent.len - current_indent.len;
 9167                    }
 9168                    continue;
 9169                }
 9170
 9171                // If current indent is more than suggested indent
 9172                // only move cursor to current indent and skip indent
 9173                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9174                    selection.start = Point::new(cursor.row, current_indent.len);
 9175                    selection.end = selection.start;
 9176                    continue;
 9177                }
 9178            }
 9179
 9180            // Otherwise, insert a hard or soft tab.
 9181            let settings = buffer.language_settings_at(cursor, cx);
 9182            let tab_size = if settings.hard_tabs {
 9183                IndentSize::tab()
 9184            } else {
 9185                let tab_size = settings.tab_size.get();
 9186                let indent_remainder = snapshot
 9187                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9188                    .flat_map(str::chars)
 9189                    .fold(row_delta % tab_size, |counter: u32, c| {
 9190                        if c == '\t' {
 9191                            0
 9192                        } else {
 9193                            (counter + 1) % tab_size
 9194                        }
 9195                    });
 9196
 9197                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9198                IndentSize::spaces(chars_to_next_tab_stop)
 9199            };
 9200            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9201            selection.end = selection.start;
 9202            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9203            row_delta += tab_size.len;
 9204        }
 9205
 9206        self.transact(window, cx, |this, window, cx| {
 9207            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9208            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9209                s.select(selections)
 9210            });
 9211            this.refresh_inline_completion(true, false, window, cx);
 9212        });
 9213    }
 9214
 9215    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9216        if self.read_only(cx) {
 9217            return;
 9218        }
 9219        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9220        let mut selections = self.selections.all::<Point>(cx);
 9221        let mut prev_edited_row = 0;
 9222        let mut row_delta = 0;
 9223        let mut edits = Vec::new();
 9224        let buffer = self.buffer.read(cx);
 9225        let snapshot = buffer.snapshot(cx);
 9226        for selection in &mut selections {
 9227            if selection.start.row != prev_edited_row {
 9228                row_delta = 0;
 9229            }
 9230            prev_edited_row = selection.end.row;
 9231
 9232            row_delta =
 9233                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9234        }
 9235
 9236        self.transact(window, cx, |this, window, cx| {
 9237            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9238            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9239                s.select(selections)
 9240            });
 9241        });
 9242    }
 9243
 9244    fn indent_selection(
 9245        buffer: &MultiBuffer,
 9246        snapshot: &MultiBufferSnapshot,
 9247        selection: &mut Selection<Point>,
 9248        edits: &mut Vec<(Range<Point>, String)>,
 9249        delta_for_start_row: u32,
 9250        cx: &App,
 9251    ) -> u32 {
 9252        let settings = buffer.language_settings_at(selection.start, cx);
 9253        let tab_size = settings.tab_size.get();
 9254        let indent_kind = if settings.hard_tabs {
 9255            IndentKind::Tab
 9256        } else {
 9257            IndentKind::Space
 9258        };
 9259        let mut start_row = selection.start.row;
 9260        let mut end_row = selection.end.row + 1;
 9261
 9262        // If a selection ends at the beginning of a line, don't indent
 9263        // that last line.
 9264        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9265            end_row -= 1;
 9266        }
 9267
 9268        // Avoid re-indenting a row that has already been indented by a
 9269        // previous selection, but still update this selection's column
 9270        // to reflect that indentation.
 9271        if delta_for_start_row > 0 {
 9272            start_row += 1;
 9273            selection.start.column += delta_for_start_row;
 9274            if selection.end.row == selection.start.row {
 9275                selection.end.column += delta_for_start_row;
 9276            }
 9277        }
 9278
 9279        let mut delta_for_end_row = 0;
 9280        let has_multiple_rows = start_row + 1 != end_row;
 9281        for row in start_row..end_row {
 9282            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9283            let indent_delta = match (current_indent.kind, indent_kind) {
 9284                (IndentKind::Space, IndentKind::Space) => {
 9285                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9286                    IndentSize::spaces(columns_to_next_tab_stop)
 9287                }
 9288                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9289                (_, IndentKind::Tab) => IndentSize::tab(),
 9290            };
 9291
 9292            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9293                0
 9294            } else {
 9295                selection.start.column
 9296            };
 9297            let row_start = Point::new(row, start);
 9298            edits.push((
 9299                row_start..row_start,
 9300                indent_delta.chars().collect::<String>(),
 9301            ));
 9302
 9303            // Update this selection's endpoints to reflect the indentation.
 9304            if row == selection.start.row {
 9305                selection.start.column += indent_delta.len;
 9306            }
 9307            if row == selection.end.row {
 9308                selection.end.column += indent_delta.len;
 9309                delta_for_end_row = indent_delta.len;
 9310            }
 9311        }
 9312
 9313        if selection.start.row == selection.end.row {
 9314            delta_for_start_row + delta_for_end_row
 9315        } else {
 9316            delta_for_end_row
 9317        }
 9318    }
 9319
 9320    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9321        if self.read_only(cx) {
 9322            return;
 9323        }
 9324        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9325        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9326        let selections = self.selections.all::<Point>(cx);
 9327        let mut deletion_ranges = Vec::new();
 9328        let mut last_outdent = None;
 9329        {
 9330            let buffer = self.buffer.read(cx);
 9331            let snapshot = buffer.snapshot(cx);
 9332            for selection in &selections {
 9333                let settings = buffer.language_settings_at(selection.start, cx);
 9334                let tab_size = settings.tab_size.get();
 9335                let mut rows = selection.spanned_rows(false, &display_map);
 9336
 9337                // Avoid re-outdenting a row that has already been outdented by a
 9338                // previous selection.
 9339                if let Some(last_row) = last_outdent {
 9340                    if last_row == rows.start {
 9341                        rows.start = rows.start.next_row();
 9342                    }
 9343                }
 9344                let has_multiple_rows = rows.len() > 1;
 9345                for row in rows.iter_rows() {
 9346                    let indent_size = snapshot.indent_size_for_line(row);
 9347                    if indent_size.len > 0 {
 9348                        let deletion_len = match indent_size.kind {
 9349                            IndentKind::Space => {
 9350                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9351                                if columns_to_prev_tab_stop == 0 {
 9352                                    tab_size
 9353                                } else {
 9354                                    columns_to_prev_tab_stop
 9355                                }
 9356                            }
 9357                            IndentKind::Tab => 1,
 9358                        };
 9359                        let start = if has_multiple_rows
 9360                            || deletion_len > selection.start.column
 9361                            || indent_size.len < selection.start.column
 9362                        {
 9363                            0
 9364                        } else {
 9365                            selection.start.column - deletion_len
 9366                        };
 9367                        deletion_ranges.push(
 9368                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9369                        );
 9370                        last_outdent = Some(row);
 9371                    }
 9372                }
 9373            }
 9374        }
 9375
 9376        self.transact(window, cx, |this, window, cx| {
 9377            this.buffer.update(cx, |buffer, cx| {
 9378                let empty_str: Arc<str> = Arc::default();
 9379                buffer.edit(
 9380                    deletion_ranges
 9381                        .into_iter()
 9382                        .map(|range| (range, empty_str.clone())),
 9383                    None,
 9384                    cx,
 9385                );
 9386            });
 9387            let selections = this.selections.all::<usize>(cx);
 9388            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9389                s.select(selections)
 9390            });
 9391        });
 9392    }
 9393
 9394    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9395        if self.read_only(cx) {
 9396            return;
 9397        }
 9398        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9399        let selections = self
 9400            .selections
 9401            .all::<usize>(cx)
 9402            .into_iter()
 9403            .map(|s| s.range());
 9404
 9405        self.transact(window, cx, |this, window, cx| {
 9406            this.buffer.update(cx, |buffer, cx| {
 9407                buffer.autoindent_ranges(selections, cx);
 9408            });
 9409            let selections = this.selections.all::<usize>(cx);
 9410            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9411                s.select(selections)
 9412            });
 9413        });
 9414    }
 9415
 9416    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9417        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9418        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9419        let selections = self.selections.all::<Point>(cx);
 9420
 9421        let mut new_cursors = Vec::new();
 9422        let mut edit_ranges = Vec::new();
 9423        let mut selections = selections.iter().peekable();
 9424        while let Some(selection) = selections.next() {
 9425            let mut rows = selection.spanned_rows(false, &display_map);
 9426            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9427
 9428            // Accumulate contiguous regions of rows that we want to delete.
 9429            while let Some(next_selection) = selections.peek() {
 9430                let next_rows = next_selection.spanned_rows(false, &display_map);
 9431                if next_rows.start <= rows.end {
 9432                    rows.end = next_rows.end;
 9433                    selections.next().unwrap();
 9434                } else {
 9435                    break;
 9436                }
 9437            }
 9438
 9439            let buffer = &display_map.buffer_snapshot;
 9440            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9441            let edit_end;
 9442            let cursor_buffer_row;
 9443            if buffer.max_point().row >= rows.end.0 {
 9444                // If there's a line after the range, delete the \n from the end of the row range
 9445                // and position the cursor on the next line.
 9446                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9447                cursor_buffer_row = rows.end;
 9448            } else {
 9449                // If there isn't a line after the range, delete the \n from the line before the
 9450                // start of the row range and position the cursor there.
 9451                edit_start = edit_start.saturating_sub(1);
 9452                edit_end = buffer.len();
 9453                cursor_buffer_row = rows.start.previous_row();
 9454            }
 9455
 9456            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9457            *cursor.column_mut() =
 9458                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9459
 9460            new_cursors.push((
 9461                selection.id,
 9462                buffer.anchor_after(cursor.to_point(&display_map)),
 9463            ));
 9464            edit_ranges.push(edit_start..edit_end);
 9465        }
 9466
 9467        self.transact(window, cx, |this, window, cx| {
 9468            let buffer = this.buffer.update(cx, |buffer, cx| {
 9469                let empty_str: Arc<str> = Arc::default();
 9470                buffer.edit(
 9471                    edit_ranges
 9472                        .into_iter()
 9473                        .map(|range| (range, empty_str.clone())),
 9474                    None,
 9475                    cx,
 9476                );
 9477                buffer.snapshot(cx)
 9478            });
 9479            let new_selections = new_cursors
 9480                .into_iter()
 9481                .map(|(id, cursor)| {
 9482                    let cursor = cursor.to_point(&buffer);
 9483                    Selection {
 9484                        id,
 9485                        start: cursor,
 9486                        end: cursor,
 9487                        reversed: false,
 9488                        goal: SelectionGoal::None,
 9489                    }
 9490                })
 9491                .collect();
 9492
 9493            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9494                s.select(new_selections);
 9495            });
 9496        });
 9497    }
 9498
 9499    pub fn join_lines_impl(
 9500        &mut self,
 9501        insert_whitespace: bool,
 9502        window: &mut Window,
 9503        cx: &mut Context<Self>,
 9504    ) {
 9505        if self.read_only(cx) {
 9506            return;
 9507        }
 9508        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9509        for selection in self.selections.all::<Point>(cx) {
 9510            let start = MultiBufferRow(selection.start.row);
 9511            // Treat single line selections as if they include the next line. Otherwise this action
 9512            // would do nothing for single line selections individual cursors.
 9513            let end = if selection.start.row == selection.end.row {
 9514                MultiBufferRow(selection.start.row + 1)
 9515            } else {
 9516                MultiBufferRow(selection.end.row)
 9517            };
 9518
 9519            if let Some(last_row_range) = row_ranges.last_mut() {
 9520                if start <= last_row_range.end {
 9521                    last_row_range.end = end;
 9522                    continue;
 9523                }
 9524            }
 9525            row_ranges.push(start..end);
 9526        }
 9527
 9528        let snapshot = self.buffer.read(cx).snapshot(cx);
 9529        let mut cursor_positions = Vec::new();
 9530        for row_range in &row_ranges {
 9531            let anchor = snapshot.anchor_before(Point::new(
 9532                row_range.end.previous_row().0,
 9533                snapshot.line_len(row_range.end.previous_row()),
 9534            ));
 9535            cursor_positions.push(anchor..anchor);
 9536        }
 9537
 9538        self.transact(window, cx, |this, window, cx| {
 9539            for row_range in row_ranges.into_iter().rev() {
 9540                for row in row_range.iter_rows().rev() {
 9541                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9542                    let next_line_row = row.next_row();
 9543                    let indent = snapshot.indent_size_for_line(next_line_row);
 9544                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9545
 9546                    let replace =
 9547                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9548                            " "
 9549                        } else {
 9550                            ""
 9551                        };
 9552
 9553                    this.buffer.update(cx, |buffer, cx| {
 9554                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9555                    });
 9556                }
 9557            }
 9558
 9559            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9560                s.select_anchor_ranges(cursor_positions)
 9561            });
 9562        });
 9563    }
 9564
 9565    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9566        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9567        self.join_lines_impl(true, window, cx);
 9568    }
 9569
 9570    pub fn sort_lines_case_sensitive(
 9571        &mut self,
 9572        _: &SortLinesCaseSensitive,
 9573        window: &mut Window,
 9574        cx: &mut Context<Self>,
 9575    ) {
 9576        self.manipulate_lines(window, cx, |lines| lines.sort())
 9577    }
 9578
 9579    pub fn sort_lines_case_insensitive(
 9580        &mut self,
 9581        _: &SortLinesCaseInsensitive,
 9582        window: &mut Window,
 9583        cx: &mut Context<Self>,
 9584    ) {
 9585        self.manipulate_lines(window, cx, |lines| {
 9586            lines.sort_by_key(|line| line.to_lowercase())
 9587        })
 9588    }
 9589
 9590    pub fn unique_lines_case_insensitive(
 9591        &mut self,
 9592        _: &UniqueLinesCaseInsensitive,
 9593        window: &mut Window,
 9594        cx: &mut Context<Self>,
 9595    ) {
 9596        self.manipulate_lines(window, cx, |lines| {
 9597            let mut seen = HashSet::default();
 9598            lines.retain(|line| seen.insert(line.to_lowercase()));
 9599        })
 9600    }
 9601
 9602    pub fn unique_lines_case_sensitive(
 9603        &mut self,
 9604        _: &UniqueLinesCaseSensitive,
 9605        window: &mut Window,
 9606        cx: &mut Context<Self>,
 9607    ) {
 9608        self.manipulate_lines(window, cx, |lines| {
 9609            let mut seen = HashSet::default();
 9610            lines.retain(|line| seen.insert(*line));
 9611        })
 9612    }
 9613
 9614    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9615        let Some(project) = self.project.clone() else {
 9616            return;
 9617        };
 9618        self.reload(project, window, cx)
 9619            .detach_and_notify_err(window, cx);
 9620    }
 9621
 9622    pub fn restore_file(
 9623        &mut self,
 9624        _: &::git::RestoreFile,
 9625        window: &mut Window,
 9626        cx: &mut Context<Self>,
 9627    ) {
 9628        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9629        let mut buffer_ids = HashSet::default();
 9630        let snapshot = self.buffer().read(cx).snapshot(cx);
 9631        for selection in self.selections.all::<usize>(cx) {
 9632            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9633        }
 9634
 9635        let buffer = self.buffer().read(cx);
 9636        let ranges = buffer_ids
 9637            .into_iter()
 9638            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9639            .collect::<Vec<_>>();
 9640
 9641        self.restore_hunks_in_ranges(ranges, window, cx);
 9642    }
 9643
 9644    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9645        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9646        let selections = self
 9647            .selections
 9648            .all(cx)
 9649            .into_iter()
 9650            .map(|s| s.range())
 9651            .collect();
 9652        self.restore_hunks_in_ranges(selections, window, cx);
 9653    }
 9654
 9655    pub fn restore_hunks_in_ranges(
 9656        &mut self,
 9657        ranges: Vec<Range<Point>>,
 9658        window: &mut Window,
 9659        cx: &mut Context<Editor>,
 9660    ) {
 9661        let mut revert_changes = HashMap::default();
 9662        let chunk_by = self
 9663            .snapshot(window, cx)
 9664            .hunks_for_ranges(ranges)
 9665            .into_iter()
 9666            .chunk_by(|hunk| hunk.buffer_id);
 9667        for (buffer_id, hunks) in &chunk_by {
 9668            let hunks = hunks.collect::<Vec<_>>();
 9669            for hunk in &hunks {
 9670                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9671            }
 9672            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9673        }
 9674        drop(chunk_by);
 9675        if !revert_changes.is_empty() {
 9676            self.transact(window, cx, |editor, window, cx| {
 9677                editor.restore(revert_changes, window, cx);
 9678            });
 9679        }
 9680    }
 9681
 9682    pub fn open_active_item_in_terminal(
 9683        &mut self,
 9684        _: &OpenInTerminal,
 9685        window: &mut Window,
 9686        cx: &mut Context<Self>,
 9687    ) {
 9688        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9689            let project_path = buffer.read(cx).project_path(cx)?;
 9690            let project = self.project.as_ref()?.read(cx);
 9691            let entry = project.entry_for_path(&project_path, cx)?;
 9692            let parent = match &entry.canonical_path {
 9693                Some(canonical_path) => canonical_path.to_path_buf(),
 9694                None => project.absolute_path(&project_path, cx)?,
 9695            }
 9696            .parent()?
 9697            .to_path_buf();
 9698            Some(parent)
 9699        }) {
 9700            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9701        }
 9702    }
 9703
 9704    fn set_breakpoint_context_menu(
 9705        &mut self,
 9706        display_row: DisplayRow,
 9707        position: Option<Anchor>,
 9708        clicked_point: gpui::Point<Pixels>,
 9709        window: &mut Window,
 9710        cx: &mut Context<Self>,
 9711    ) {
 9712        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9713            return;
 9714        }
 9715        let source = self
 9716            .buffer
 9717            .read(cx)
 9718            .snapshot(cx)
 9719            .anchor_before(Point::new(display_row.0, 0u32));
 9720
 9721        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9722
 9723        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9724            self,
 9725            source,
 9726            clicked_point,
 9727            context_menu,
 9728            window,
 9729            cx,
 9730        );
 9731    }
 9732
 9733    fn add_edit_breakpoint_block(
 9734        &mut self,
 9735        anchor: Anchor,
 9736        breakpoint: &Breakpoint,
 9737        edit_action: BreakpointPromptEditAction,
 9738        window: &mut Window,
 9739        cx: &mut Context<Self>,
 9740    ) {
 9741        let weak_editor = cx.weak_entity();
 9742        let bp_prompt = cx.new(|cx| {
 9743            BreakpointPromptEditor::new(
 9744                weak_editor,
 9745                anchor,
 9746                breakpoint.clone(),
 9747                edit_action,
 9748                window,
 9749                cx,
 9750            )
 9751        });
 9752
 9753        let height = bp_prompt.update(cx, |this, cx| {
 9754            this.prompt
 9755                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9756        });
 9757        let cloned_prompt = bp_prompt.clone();
 9758        let blocks = vec![BlockProperties {
 9759            style: BlockStyle::Sticky,
 9760            placement: BlockPlacement::Above(anchor),
 9761            height: Some(height),
 9762            render: Arc::new(move |cx| {
 9763                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9764                cloned_prompt.clone().into_any_element()
 9765            }),
 9766            priority: 0,
 9767            render_in_minimap: true,
 9768        }];
 9769
 9770        let focus_handle = bp_prompt.focus_handle(cx);
 9771        window.focus(&focus_handle);
 9772
 9773        let block_ids = self.insert_blocks(blocks, None, cx);
 9774        bp_prompt.update(cx, |prompt, _| {
 9775            prompt.add_block_ids(block_ids);
 9776        });
 9777    }
 9778
 9779    pub(crate) fn breakpoint_at_row(
 9780        &self,
 9781        row: u32,
 9782        window: &mut Window,
 9783        cx: &mut Context<Self>,
 9784    ) -> Option<(Anchor, Breakpoint)> {
 9785        let snapshot = self.snapshot(window, cx);
 9786        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9787
 9788        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9789    }
 9790
 9791    pub(crate) fn breakpoint_at_anchor(
 9792        &self,
 9793        breakpoint_position: Anchor,
 9794        snapshot: &EditorSnapshot,
 9795        cx: &mut Context<Self>,
 9796    ) -> Option<(Anchor, Breakpoint)> {
 9797        let project = self.project.clone()?;
 9798
 9799        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9800            snapshot
 9801                .buffer_snapshot
 9802                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9803        })?;
 9804
 9805        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9806        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
 9807        let buffer_snapshot = buffer.read(cx).snapshot();
 9808
 9809        let row = buffer_snapshot
 9810            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9811            .row;
 9812
 9813        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9814        let anchor_end = snapshot
 9815            .buffer_snapshot
 9816            .anchor_after(Point::new(row, line_len));
 9817
 9818        let bp = self
 9819            .breakpoint_store
 9820            .as_ref()?
 9821            .read_with(cx, |breakpoint_store, cx| {
 9822                breakpoint_store
 9823                    .breakpoints(
 9824                        &buffer,
 9825                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
 9826                        &buffer_snapshot,
 9827                        cx,
 9828                    )
 9829                    .next()
 9830                    .and_then(|(bp, _)| {
 9831                        let breakpoint_row = buffer_snapshot
 9832                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
 9833                            .row;
 9834
 9835                        if breakpoint_row == row {
 9836                            snapshot
 9837                                .buffer_snapshot
 9838                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
 9839                                .map(|position| (position, bp.bp.clone()))
 9840                        } else {
 9841                            None
 9842                        }
 9843                    })
 9844            });
 9845        bp
 9846    }
 9847
 9848    pub fn edit_log_breakpoint(
 9849        &mut self,
 9850        _: &EditLogBreakpoint,
 9851        window: &mut Window,
 9852        cx: &mut Context<Self>,
 9853    ) {
 9854        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9855            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
 9856                message: None,
 9857                state: BreakpointState::Enabled,
 9858                condition: None,
 9859                hit_condition: None,
 9860            });
 9861
 9862            self.add_edit_breakpoint_block(
 9863                anchor,
 9864                &breakpoint,
 9865                BreakpointPromptEditAction::Log,
 9866                window,
 9867                cx,
 9868            );
 9869        }
 9870    }
 9871
 9872    fn breakpoints_at_cursors(
 9873        &self,
 9874        window: &mut Window,
 9875        cx: &mut Context<Self>,
 9876    ) -> Vec<(Anchor, Option<Breakpoint>)> {
 9877        let snapshot = self.snapshot(window, cx);
 9878        let cursors = self
 9879            .selections
 9880            .disjoint_anchors()
 9881            .into_iter()
 9882            .map(|selection| {
 9883                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
 9884
 9885                let breakpoint_position = self
 9886                    .breakpoint_at_row(cursor_position.row, window, cx)
 9887                    .map(|bp| bp.0)
 9888                    .unwrap_or_else(|| {
 9889                        snapshot
 9890                            .display_snapshot
 9891                            .buffer_snapshot
 9892                            .anchor_after(Point::new(cursor_position.row, 0))
 9893                    });
 9894
 9895                let breakpoint = self
 9896                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9897                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
 9898
 9899                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
 9900            })
 9901            // 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.
 9902            .collect::<HashMap<Anchor, _>>();
 9903
 9904        cursors.into_iter().collect()
 9905    }
 9906
 9907    pub fn enable_breakpoint(
 9908        &mut self,
 9909        _: &crate::actions::EnableBreakpoint,
 9910        window: &mut Window,
 9911        cx: &mut Context<Self>,
 9912    ) {
 9913        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9914            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
 9915                continue;
 9916            };
 9917            self.edit_breakpoint_at_anchor(
 9918                anchor,
 9919                breakpoint,
 9920                BreakpointEditAction::InvertState,
 9921                cx,
 9922            );
 9923        }
 9924    }
 9925
 9926    pub fn disable_breakpoint(
 9927        &mut self,
 9928        _: &crate::actions::DisableBreakpoint,
 9929        window: &mut Window,
 9930        cx: &mut Context<Self>,
 9931    ) {
 9932        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9933            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
 9934                continue;
 9935            };
 9936            self.edit_breakpoint_at_anchor(
 9937                anchor,
 9938                breakpoint,
 9939                BreakpointEditAction::InvertState,
 9940                cx,
 9941            );
 9942        }
 9943    }
 9944
 9945    pub fn toggle_breakpoint(
 9946        &mut self,
 9947        _: &crate::actions::ToggleBreakpoint,
 9948        window: &mut Window,
 9949        cx: &mut Context<Self>,
 9950    ) {
 9951        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
 9952            if let Some(breakpoint) = breakpoint {
 9953                self.edit_breakpoint_at_anchor(
 9954                    anchor,
 9955                    breakpoint,
 9956                    BreakpointEditAction::Toggle,
 9957                    cx,
 9958                );
 9959            } else {
 9960                self.edit_breakpoint_at_anchor(
 9961                    anchor,
 9962                    Breakpoint::new_standard(),
 9963                    BreakpointEditAction::Toggle,
 9964                    cx,
 9965                );
 9966            }
 9967        }
 9968    }
 9969
 9970    pub fn edit_breakpoint_at_anchor(
 9971        &mut self,
 9972        breakpoint_position: Anchor,
 9973        breakpoint: Breakpoint,
 9974        edit_action: BreakpointEditAction,
 9975        cx: &mut Context<Self>,
 9976    ) {
 9977        let Some(breakpoint_store) = &self.breakpoint_store else {
 9978            return;
 9979        };
 9980
 9981        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
 9982            if breakpoint_position == Anchor::min() {
 9983                self.buffer()
 9984                    .read(cx)
 9985                    .excerpt_buffer_ids()
 9986                    .into_iter()
 9987                    .next()
 9988            } else {
 9989                None
 9990            }
 9991        }) else {
 9992            return;
 9993        };
 9994
 9995        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
 9996            return;
 9997        };
 9998
 9999        breakpoint_store.update(cx, |breakpoint_store, cx| {
10000            breakpoint_store.toggle_breakpoint(
10001                buffer,
10002                BreakpointWithPosition {
10003                    position: breakpoint_position.text_anchor,
10004                    bp: breakpoint,
10005                },
10006                edit_action,
10007                cx,
10008            );
10009        });
10010
10011        cx.notify();
10012    }
10013
10014    #[cfg(any(test, feature = "test-support"))]
10015    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10016        self.breakpoint_store.clone()
10017    }
10018
10019    pub fn prepare_restore_change(
10020        &self,
10021        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10022        hunk: &MultiBufferDiffHunk,
10023        cx: &mut App,
10024    ) -> Option<()> {
10025        if hunk.is_created_file() {
10026            return None;
10027        }
10028        let buffer = self.buffer.read(cx);
10029        let diff = buffer.diff_for(hunk.buffer_id)?;
10030        let buffer = buffer.buffer(hunk.buffer_id)?;
10031        let buffer = buffer.read(cx);
10032        let original_text = diff
10033            .read(cx)
10034            .base_text()
10035            .as_rope()
10036            .slice(hunk.diff_base_byte_range.clone());
10037        let buffer_snapshot = buffer.snapshot();
10038        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10039        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10040            probe
10041                .0
10042                .start
10043                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10044                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10045        }) {
10046            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10047            Some(())
10048        } else {
10049            None
10050        }
10051    }
10052
10053    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10054        self.manipulate_lines(window, cx, |lines| lines.reverse())
10055    }
10056
10057    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10058        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10059    }
10060
10061    fn manipulate_lines<Fn>(
10062        &mut self,
10063        window: &mut Window,
10064        cx: &mut Context<Self>,
10065        mut callback: Fn,
10066    ) where
10067        Fn: FnMut(&mut Vec<&str>),
10068    {
10069        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10070
10071        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10072        let buffer = self.buffer.read(cx).snapshot(cx);
10073
10074        let mut edits = Vec::new();
10075
10076        let selections = self.selections.all::<Point>(cx);
10077        let mut selections = selections.iter().peekable();
10078        let mut contiguous_row_selections = Vec::new();
10079        let mut new_selections = Vec::new();
10080        let mut added_lines = 0;
10081        let mut removed_lines = 0;
10082
10083        while let Some(selection) = selections.next() {
10084            let (start_row, end_row) = consume_contiguous_rows(
10085                &mut contiguous_row_selections,
10086                selection,
10087                &display_map,
10088                &mut selections,
10089            );
10090
10091            let start_point = Point::new(start_row.0, 0);
10092            let end_point = Point::new(
10093                end_row.previous_row().0,
10094                buffer.line_len(end_row.previous_row()),
10095            );
10096            let text = buffer
10097                .text_for_range(start_point..end_point)
10098                .collect::<String>();
10099
10100            let mut lines = text.split('\n').collect_vec();
10101
10102            let lines_before = lines.len();
10103            callback(&mut lines);
10104            let lines_after = lines.len();
10105
10106            edits.push((start_point..end_point, lines.join("\n")));
10107
10108            // Selections must change based on added and removed line count
10109            let start_row =
10110                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10111            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10112            new_selections.push(Selection {
10113                id: selection.id,
10114                start: start_row,
10115                end: end_row,
10116                goal: SelectionGoal::None,
10117                reversed: selection.reversed,
10118            });
10119
10120            if lines_after > lines_before {
10121                added_lines += lines_after - lines_before;
10122            } else if lines_before > lines_after {
10123                removed_lines += lines_before - lines_after;
10124            }
10125        }
10126
10127        self.transact(window, cx, |this, window, cx| {
10128            let buffer = this.buffer.update(cx, |buffer, cx| {
10129                buffer.edit(edits, None, cx);
10130                buffer.snapshot(cx)
10131            });
10132
10133            // Recalculate offsets on newly edited buffer
10134            let new_selections = new_selections
10135                .iter()
10136                .map(|s| {
10137                    let start_point = Point::new(s.start.0, 0);
10138                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10139                    Selection {
10140                        id: s.id,
10141                        start: buffer.point_to_offset(start_point),
10142                        end: buffer.point_to_offset(end_point),
10143                        goal: s.goal,
10144                        reversed: s.reversed,
10145                    }
10146                })
10147                .collect();
10148
10149            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10150                s.select(new_selections);
10151            });
10152
10153            this.request_autoscroll(Autoscroll::fit(), cx);
10154        });
10155    }
10156
10157    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10158        self.manipulate_text(window, cx, |text| {
10159            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10160            if has_upper_case_characters {
10161                text.to_lowercase()
10162            } else {
10163                text.to_uppercase()
10164            }
10165        })
10166    }
10167
10168    pub fn convert_to_upper_case(
10169        &mut self,
10170        _: &ConvertToUpperCase,
10171        window: &mut Window,
10172        cx: &mut Context<Self>,
10173    ) {
10174        self.manipulate_text(window, cx, |text| text.to_uppercase())
10175    }
10176
10177    pub fn convert_to_lower_case(
10178        &mut self,
10179        _: &ConvertToLowerCase,
10180        window: &mut Window,
10181        cx: &mut Context<Self>,
10182    ) {
10183        self.manipulate_text(window, cx, |text| text.to_lowercase())
10184    }
10185
10186    pub fn convert_to_title_case(
10187        &mut self,
10188        _: &ConvertToTitleCase,
10189        window: &mut Window,
10190        cx: &mut Context<Self>,
10191    ) {
10192        self.manipulate_text(window, cx, |text| {
10193            text.split('\n')
10194                .map(|line| line.to_case(Case::Title))
10195                .join("\n")
10196        })
10197    }
10198
10199    pub fn convert_to_snake_case(
10200        &mut self,
10201        _: &ConvertToSnakeCase,
10202        window: &mut Window,
10203        cx: &mut Context<Self>,
10204    ) {
10205        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10206    }
10207
10208    pub fn convert_to_kebab_case(
10209        &mut self,
10210        _: &ConvertToKebabCase,
10211        window: &mut Window,
10212        cx: &mut Context<Self>,
10213    ) {
10214        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10215    }
10216
10217    pub fn convert_to_upper_camel_case(
10218        &mut self,
10219        _: &ConvertToUpperCamelCase,
10220        window: &mut Window,
10221        cx: &mut Context<Self>,
10222    ) {
10223        self.manipulate_text(window, cx, |text| {
10224            text.split('\n')
10225                .map(|line| line.to_case(Case::UpperCamel))
10226                .join("\n")
10227        })
10228    }
10229
10230    pub fn convert_to_lower_camel_case(
10231        &mut self,
10232        _: &ConvertToLowerCamelCase,
10233        window: &mut Window,
10234        cx: &mut Context<Self>,
10235    ) {
10236        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10237    }
10238
10239    pub fn convert_to_opposite_case(
10240        &mut self,
10241        _: &ConvertToOppositeCase,
10242        window: &mut Window,
10243        cx: &mut Context<Self>,
10244    ) {
10245        self.manipulate_text(window, cx, |text| {
10246            text.chars()
10247                .fold(String::with_capacity(text.len()), |mut t, c| {
10248                    if c.is_uppercase() {
10249                        t.extend(c.to_lowercase());
10250                    } else {
10251                        t.extend(c.to_uppercase());
10252                    }
10253                    t
10254                })
10255        })
10256    }
10257
10258    pub fn convert_to_rot13(
10259        &mut self,
10260        _: &ConvertToRot13,
10261        window: &mut Window,
10262        cx: &mut Context<Self>,
10263    ) {
10264        self.manipulate_text(window, cx, |text| {
10265            text.chars()
10266                .map(|c| match c {
10267                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10268                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10269                    _ => c,
10270                })
10271                .collect()
10272        })
10273    }
10274
10275    pub fn convert_to_rot47(
10276        &mut self,
10277        _: &ConvertToRot47,
10278        window: &mut Window,
10279        cx: &mut Context<Self>,
10280    ) {
10281        self.manipulate_text(window, cx, |text| {
10282            text.chars()
10283                .map(|c| {
10284                    let code_point = c as u32;
10285                    if code_point >= 33 && code_point <= 126 {
10286                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10287                    }
10288                    c
10289                })
10290                .collect()
10291        })
10292    }
10293
10294    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10295    where
10296        Fn: FnMut(&str) -> String,
10297    {
10298        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10299        let buffer = self.buffer.read(cx).snapshot(cx);
10300
10301        let mut new_selections = Vec::new();
10302        let mut edits = Vec::new();
10303        let mut selection_adjustment = 0i32;
10304
10305        for selection in self.selections.all::<usize>(cx) {
10306            let selection_is_empty = selection.is_empty();
10307
10308            let (start, end) = if selection_is_empty {
10309                let word_range = movement::surrounding_word(
10310                    &display_map,
10311                    selection.start.to_display_point(&display_map),
10312                );
10313                let start = word_range.start.to_offset(&display_map, Bias::Left);
10314                let end = word_range.end.to_offset(&display_map, Bias::Left);
10315                (start, end)
10316            } else {
10317                (selection.start, selection.end)
10318            };
10319
10320            let text = buffer.text_for_range(start..end).collect::<String>();
10321            let old_length = text.len() as i32;
10322            let text = callback(&text);
10323
10324            new_selections.push(Selection {
10325                start: (start as i32 - selection_adjustment) as usize,
10326                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10327                goal: SelectionGoal::None,
10328                ..selection
10329            });
10330
10331            selection_adjustment += old_length - text.len() as i32;
10332
10333            edits.push((start..end, text));
10334        }
10335
10336        self.transact(window, cx, |this, window, cx| {
10337            this.buffer.update(cx, |buffer, cx| {
10338                buffer.edit(edits, None, cx);
10339            });
10340
10341            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10342                s.select(new_selections);
10343            });
10344
10345            this.request_autoscroll(Autoscroll::fit(), cx);
10346        });
10347    }
10348
10349    pub fn duplicate(
10350        &mut self,
10351        upwards: bool,
10352        whole_lines: bool,
10353        window: &mut Window,
10354        cx: &mut Context<Self>,
10355    ) {
10356        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10357
10358        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10359        let buffer = &display_map.buffer_snapshot;
10360        let selections = self.selections.all::<Point>(cx);
10361
10362        let mut edits = Vec::new();
10363        let mut selections_iter = selections.iter().peekable();
10364        while let Some(selection) = selections_iter.next() {
10365            let mut rows = selection.spanned_rows(false, &display_map);
10366            // duplicate line-wise
10367            if whole_lines || selection.start == selection.end {
10368                // Avoid duplicating the same lines twice.
10369                while let Some(next_selection) = selections_iter.peek() {
10370                    let next_rows = next_selection.spanned_rows(false, &display_map);
10371                    if next_rows.start < rows.end {
10372                        rows.end = next_rows.end;
10373                        selections_iter.next().unwrap();
10374                    } else {
10375                        break;
10376                    }
10377                }
10378
10379                // Copy the text from the selected row region and splice it either at the start
10380                // or end of the region.
10381                let start = Point::new(rows.start.0, 0);
10382                let end = Point::new(
10383                    rows.end.previous_row().0,
10384                    buffer.line_len(rows.end.previous_row()),
10385                );
10386                let text = buffer
10387                    .text_for_range(start..end)
10388                    .chain(Some("\n"))
10389                    .collect::<String>();
10390                let insert_location = if upwards {
10391                    Point::new(rows.end.0, 0)
10392                } else {
10393                    start
10394                };
10395                edits.push((insert_location..insert_location, text));
10396            } else {
10397                // duplicate character-wise
10398                let start = selection.start;
10399                let end = selection.end;
10400                let text = buffer.text_for_range(start..end).collect::<String>();
10401                edits.push((selection.end..selection.end, text));
10402            }
10403        }
10404
10405        self.transact(window, cx, |this, _, cx| {
10406            this.buffer.update(cx, |buffer, cx| {
10407                buffer.edit(edits, None, cx);
10408            });
10409
10410            this.request_autoscroll(Autoscroll::fit(), cx);
10411        });
10412    }
10413
10414    pub fn duplicate_line_up(
10415        &mut self,
10416        _: &DuplicateLineUp,
10417        window: &mut Window,
10418        cx: &mut Context<Self>,
10419    ) {
10420        self.duplicate(true, true, window, cx);
10421    }
10422
10423    pub fn duplicate_line_down(
10424        &mut self,
10425        _: &DuplicateLineDown,
10426        window: &mut Window,
10427        cx: &mut Context<Self>,
10428    ) {
10429        self.duplicate(false, true, window, cx);
10430    }
10431
10432    pub fn duplicate_selection(
10433        &mut self,
10434        _: &DuplicateSelection,
10435        window: &mut Window,
10436        cx: &mut Context<Self>,
10437    ) {
10438        self.duplicate(false, false, window, cx);
10439    }
10440
10441    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10442        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10443
10444        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10445        let buffer = self.buffer.read(cx).snapshot(cx);
10446
10447        let mut edits = Vec::new();
10448        let mut unfold_ranges = Vec::new();
10449        let mut refold_creases = Vec::new();
10450
10451        let selections = self.selections.all::<Point>(cx);
10452        let mut selections = selections.iter().peekable();
10453        let mut contiguous_row_selections = Vec::new();
10454        let mut new_selections = Vec::new();
10455
10456        while let Some(selection) = selections.next() {
10457            // Find all the selections that span a contiguous row range
10458            let (start_row, end_row) = consume_contiguous_rows(
10459                &mut contiguous_row_selections,
10460                selection,
10461                &display_map,
10462                &mut selections,
10463            );
10464
10465            // Move the text spanned by the row range to be before the line preceding the row range
10466            if start_row.0 > 0 {
10467                let range_to_move = Point::new(
10468                    start_row.previous_row().0,
10469                    buffer.line_len(start_row.previous_row()),
10470                )
10471                    ..Point::new(
10472                        end_row.previous_row().0,
10473                        buffer.line_len(end_row.previous_row()),
10474                    );
10475                let insertion_point = display_map
10476                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10477                    .0;
10478
10479                // Don't move lines across excerpts
10480                if buffer
10481                    .excerpt_containing(insertion_point..range_to_move.end)
10482                    .is_some()
10483                {
10484                    let text = buffer
10485                        .text_for_range(range_to_move.clone())
10486                        .flat_map(|s| s.chars())
10487                        .skip(1)
10488                        .chain(['\n'])
10489                        .collect::<String>();
10490
10491                    edits.push((
10492                        buffer.anchor_after(range_to_move.start)
10493                            ..buffer.anchor_before(range_to_move.end),
10494                        String::new(),
10495                    ));
10496                    let insertion_anchor = buffer.anchor_after(insertion_point);
10497                    edits.push((insertion_anchor..insertion_anchor, text));
10498
10499                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10500
10501                    // Move selections up
10502                    new_selections.extend(contiguous_row_selections.drain(..).map(
10503                        |mut selection| {
10504                            selection.start.row -= row_delta;
10505                            selection.end.row -= row_delta;
10506                            selection
10507                        },
10508                    ));
10509
10510                    // Move folds up
10511                    unfold_ranges.push(range_to_move.clone());
10512                    for fold in display_map.folds_in_range(
10513                        buffer.anchor_before(range_to_move.start)
10514                            ..buffer.anchor_after(range_to_move.end),
10515                    ) {
10516                        let mut start = fold.range.start.to_point(&buffer);
10517                        let mut end = fold.range.end.to_point(&buffer);
10518                        start.row -= row_delta;
10519                        end.row -= row_delta;
10520                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10521                    }
10522                }
10523            }
10524
10525            // If we didn't move line(s), preserve the existing selections
10526            new_selections.append(&mut contiguous_row_selections);
10527        }
10528
10529        self.transact(window, cx, |this, window, cx| {
10530            this.unfold_ranges(&unfold_ranges, true, true, cx);
10531            this.buffer.update(cx, |buffer, cx| {
10532                for (range, text) in edits {
10533                    buffer.edit([(range, text)], None, cx);
10534                }
10535            });
10536            this.fold_creases(refold_creases, true, window, cx);
10537            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10538                s.select(new_selections);
10539            })
10540        });
10541    }
10542
10543    pub fn move_line_down(
10544        &mut self,
10545        _: &MoveLineDown,
10546        window: &mut Window,
10547        cx: &mut Context<Self>,
10548    ) {
10549        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10550
10551        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10552        let buffer = self.buffer.read(cx).snapshot(cx);
10553
10554        let mut edits = Vec::new();
10555        let mut unfold_ranges = Vec::new();
10556        let mut refold_creases = Vec::new();
10557
10558        let selections = self.selections.all::<Point>(cx);
10559        let mut selections = selections.iter().peekable();
10560        let mut contiguous_row_selections = Vec::new();
10561        let mut new_selections = Vec::new();
10562
10563        while let Some(selection) = selections.next() {
10564            // Find all the selections that span a contiguous row range
10565            let (start_row, end_row) = consume_contiguous_rows(
10566                &mut contiguous_row_selections,
10567                selection,
10568                &display_map,
10569                &mut selections,
10570            );
10571
10572            // Move the text spanned by the row range to be after the last line of the row range
10573            if end_row.0 <= buffer.max_point().row {
10574                let range_to_move =
10575                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10576                let insertion_point = display_map
10577                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10578                    .0;
10579
10580                // Don't move lines across excerpt boundaries
10581                if buffer
10582                    .excerpt_containing(range_to_move.start..insertion_point)
10583                    .is_some()
10584                {
10585                    let mut text = String::from("\n");
10586                    text.extend(buffer.text_for_range(range_to_move.clone()));
10587                    text.pop(); // Drop trailing newline
10588                    edits.push((
10589                        buffer.anchor_after(range_to_move.start)
10590                            ..buffer.anchor_before(range_to_move.end),
10591                        String::new(),
10592                    ));
10593                    let insertion_anchor = buffer.anchor_after(insertion_point);
10594                    edits.push((insertion_anchor..insertion_anchor, text));
10595
10596                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10597
10598                    // Move selections down
10599                    new_selections.extend(contiguous_row_selections.drain(..).map(
10600                        |mut selection| {
10601                            selection.start.row += row_delta;
10602                            selection.end.row += row_delta;
10603                            selection
10604                        },
10605                    ));
10606
10607                    // Move folds down
10608                    unfold_ranges.push(range_to_move.clone());
10609                    for fold in display_map.folds_in_range(
10610                        buffer.anchor_before(range_to_move.start)
10611                            ..buffer.anchor_after(range_to_move.end),
10612                    ) {
10613                        let mut start = fold.range.start.to_point(&buffer);
10614                        let mut end = fold.range.end.to_point(&buffer);
10615                        start.row += row_delta;
10616                        end.row += row_delta;
10617                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10618                    }
10619                }
10620            }
10621
10622            // If we didn't move line(s), preserve the existing selections
10623            new_selections.append(&mut contiguous_row_selections);
10624        }
10625
10626        self.transact(window, cx, |this, window, cx| {
10627            this.unfold_ranges(&unfold_ranges, true, true, cx);
10628            this.buffer.update(cx, |buffer, cx| {
10629                for (range, text) in edits {
10630                    buffer.edit([(range, text)], None, cx);
10631                }
10632            });
10633            this.fold_creases(refold_creases, true, window, cx);
10634            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10635                s.select(new_selections)
10636            });
10637        });
10638    }
10639
10640    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10641        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10642        let text_layout_details = &self.text_layout_details(window);
10643        self.transact(window, cx, |this, window, cx| {
10644            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10645                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10646                s.move_with(|display_map, selection| {
10647                    if !selection.is_empty() {
10648                        return;
10649                    }
10650
10651                    let mut head = selection.head();
10652                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10653                    if head.column() == display_map.line_len(head.row()) {
10654                        transpose_offset = display_map
10655                            .buffer_snapshot
10656                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10657                    }
10658
10659                    if transpose_offset == 0 {
10660                        return;
10661                    }
10662
10663                    *head.column_mut() += 1;
10664                    head = display_map.clip_point(head, Bias::Right);
10665                    let goal = SelectionGoal::HorizontalPosition(
10666                        display_map
10667                            .x_for_display_point(head, text_layout_details)
10668                            .into(),
10669                    );
10670                    selection.collapse_to(head, goal);
10671
10672                    let transpose_start = display_map
10673                        .buffer_snapshot
10674                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10675                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10676                        let transpose_end = display_map
10677                            .buffer_snapshot
10678                            .clip_offset(transpose_offset + 1, Bias::Right);
10679                        if let Some(ch) =
10680                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10681                        {
10682                            edits.push((transpose_start..transpose_offset, String::new()));
10683                            edits.push((transpose_end..transpose_end, ch.to_string()));
10684                        }
10685                    }
10686                });
10687                edits
10688            });
10689            this.buffer
10690                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10691            let selections = this.selections.all::<usize>(cx);
10692            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10693                s.select(selections);
10694            });
10695        });
10696    }
10697
10698    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10699        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10700        self.rewrap_impl(RewrapOptions::default(), cx)
10701    }
10702
10703    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10704        let buffer = self.buffer.read(cx).snapshot(cx);
10705        let selections = self.selections.all::<Point>(cx);
10706        let mut selections = selections.iter().peekable();
10707
10708        let mut edits = Vec::new();
10709        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10710
10711        while let Some(selection) = selections.next() {
10712            let mut start_row = selection.start.row;
10713            let mut end_row = selection.end.row;
10714
10715            // Skip selections that overlap with a range that has already been rewrapped.
10716            let selection_range = start_row..end_row;
10717            if rewrapped_row_ranges
10718                .iter()
10719                .any(|range| range.overlaps(&selection_range))
10720            {
10721                continue;
10722            }
10723
10724            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10725
10726            // Since not all lines in the selection may be at the same indent
10727            // level, choose the indent size that is the most common between all
10728            // of the lines.
10729            //
10730            // If there is a tie, we use the deepest indent.
10731            let (indent_size, indent_end) = {
10732                let mut indent_size_occurrences = HashMap::default();
10733                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10734
10735                for row in start_row..=end_row {
10736                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10737                    rows_by_indent_size.entry(indent).or_default().push(row);
10738                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10739                }
10740
10741                let indent_size = indent_size_occurrences
10742                    .into_iter()
10743                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10744                    .map(|(indent, _)| indent)
10745                    .unwrap_or_default();
10746                let row = rows_by_indent_size[&indent_size][0];
10747                let indent_end = Point::new(row, indent_size.len);
10748
10749                (indent_size, indent_end)
10750            };
10751
10752            let mut line_prefix = indent_size.chars().collect::<String>();
10753
10754            let mut inside_comment = false;
10755            if let Some(comment_prefix) =
10756                buffer
10757                    .language_scope_at(selection.head())
10758                    .and_then(|language| {
10759                        language
10760                            .line_comment_prefixes()
10761                            .iter()
10762                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10763                            .cloned()
10764                    })
10765            {
10766                line_prefix.push_str(&comment_prefix);
10767                inside_comment = true;
10768            }
10769
10770            let language_settings = buffer.language_settings_at(selection.head(), cx);
10771            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10772                RewrapBehavior::InComments => inside_comment,
10773                RewrapBehavior::InSelections => !selection.is_empty(),
10774                RewrapBehavior::Anywhere => true,
10775            };
10776
10777            let should_rewrap = options.override_language_settings
10778                || allow_rewrap_based_on_language
10779                || self.hard_wrap.is_some();
10780            if !should_rewrap {
10781                continue;
10782            }
10783
10784            if selection.is_empty() {
10785                'expand_upwards: while start_row > 0 {
10786                    let prev_row = start_row - 1;
10787                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10788                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10789                    {
10790                        start_row = prev_row;
10791                    } else {
10792                        break 'expand_upwards;
10793                    }
10794                }
10795
10796                'expand_downwards: while end_row < buffer.max_point().row {
10797                    let next_row = end_row + 1;
10798                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10799                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10800                    {
10801                        end_row = next_row;
10802                    } else {
10803                        break 'expand_downwards;
10804                    }
10805                }
10806            }
10807
10808            let start = Point::new(start_row, 0);
10809            let start_offset = start.to_offset(&buffer);
10810            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10811            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10812            let Some(lines_without_prefixes) = selection_text
10813                .lines()
10814                .map(|line| {
10815                    line.strip_prefix(&line_prefix)
10816                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10817                        .with_context(|| {
10818                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
10819                        })
10820                })
10821                .collect::<Result<Vec<_>, _>>()
10822                .log_err()
10823            else {
10824                continue;
10825            };
10826
10827            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
10828                buffer
10829                    .language_settings_at(Point::new(start_row, 0), cx)
10830                    .preferred_line_length as usize
10831            });
10832            let wrapped_text = wrap_with_prefix(
10833                line_prefix,
10834                lines_without_prefixes.join("\n"),
10835                wrap_column,
10836                tab_size,
10837                options.preserve_existing_whitespace,
10838            );
10839
10840            // TODO: should always use char-based diff while still supporting cursor behavior that
10841            // matches vim.
10842            let mut diff_options = DiffOptions::default();
10843            if options.override_language_settings {
10844                diff_options.max_word_diff_len = 0;
10845                diff_options.max_word_diff_line_count = 0;
10846            } else {
10847                diff_options.max_word_diff_len = usize::MAX;
10848                diff_options.max_word_diff_line_count = usize::MAX;
10849            }
10850
10851            for (old_range, new_text) in
10852                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
10853            {
10854                let edit_start = buffer.anchor_after(start_offset + old_range.start);
10855                let edit_end = buffer.anchor_after(start_offset + old_range.end);
10856                edits.push((edit_start..edit_end, new_text));
10857            }
10858
10859            rewrapped_row_ranges.push(start_row..=end_row);
10860        }
10861
10862        self.buffer
10863            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10864    }
10865
10866    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
10867        let mut text = String::new();
10868        let buffer = self.buffer.read(cx).snapshot(cx);
10869        let mut selections = self.selections.all::<Point>(cx);
10870        let mut clipboard_selections = Vec::with_capacity(selections.len());
10871        {
10872            let max_point = buffer.max_point();
10873            let mut is_first = true;
10874            for selection in &mut selections {
10875                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10876                if is_entire_line {
10877                    selection.start = Point::new(selection.start.row, 0);
10878                    if !selection.is_empty() && selection.end.column == 0 {
10879                        selection.end = cmp::min(max_point, selection.end);
10880                    } else {
10881                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
10882                    }
10883                    selection.goal = SelectionGoal::None;
10884                }
10885                if is_first {
10886                    is_first = false;
10887                } else {
10888                    text += "\n";
10889                }
10890                let mut len = 0;
10891                for chunk in buffer.text_for_range(selection.start..selection.end) {
10892                    text.push_str(chunk);
10893                    len += chunk.len();
10894                }
10895                clipboard_selections.push(ClipboardSelection {
10896                    len,
10897                    is_entire_line,
10898                    first_line_indent: buffer
10899                        .indent_size_for_line(MultiBufferRow(selection.start.row))
10900                        .len,
10901                });
10902            }
10903        }
10904
10905        self.transact(window, cx, |this, window, cx| {
10906            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10907                s.select(selections);
10908            });
10909            this.insert("", window, cx);
10910        });
10911        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
10912    }
10913
10914    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
10915        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10916        let item = self.cut_common(window, cx);
10917        cx.write_to_clipboard(item);
10918    }
10919
10920    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
10921        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10922        self.change_selections(None, window, cx, |s| {
10923            s.move_with(|snapshot, sel| {
10924                if sel.is_empty() {
10925                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
10926                }
10927            });
10928        });
10929        let item = self.cut_common(window, cx);
10930        cx.set_global(KillRing(item))
10931    }
10932
10933    pub fn kill_ring_yank(
10934        &mut self,
10935        _: &KillRingYank,
10936        window: &mut Window,
10937        cx: &mut Context<Self>,
10938    ) {
10939        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10940        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
10941            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
10942                (kill_ring.text().to_string(), kill_ring.metadata_json())
10943            } else {
10944                return;
10945            }
10946        } else {
10947            return;
10948        };
10949        self.do_paste(&text, metadata, false, window, cx);
10950    }
10951
10952    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
10953        self.do_copy(true, cx);
10954    }
10955
10956    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
10957        self.do_copy(false, cx);
10958    }
10959
10960    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
10961        let selections = self.selections.all::<Point>(cx);
10962        let buffer = self.buffer.read(cx).read(cx);
10963        let mut text = String::new();
10964
10965        let mut clipboard_selections = Vec::with_capacity(selections.len());
10966        {
10967            let max_point = buffer.max_point();
10968            let mut is_first = true;
10969            for selection in &selections {
10970                let mut start = selection.start;
10971                let mut end = selection.end;
10972                let is_entire_line = selection.is_empty() || self.selections.line_mode;
10973                if is_entire_line {
10974                    start = Point::new(start.row, 0);
10975                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
10976                }
10977
10978                let mut trimmed_selections = Vec::new();
10979                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
10980                    let row = MultiBufferRow(start.row);
10981                    let first_indent = buffer.indent_size_for_line(row);
10982                    if first_indent.len == 0 || start.column > first_indent.len {
10983                        trimmed_selections.push(start..end);
10984                    } else {
10985                        trimmed_selections.push(
10986                            Point::new(row.0, first_indent.len)
10987                                ..Point::new(row.0, buffer.line_len(row)),
10988                        );
10989                        for row in start.row + 1..=end.row {
10990                            let mut line_len = buffer.line_len(MultiBufferRow(row));
10991                            if row == end.row {
10992                                line_len = end.column;
10993                            }
10994                            if line_len == 0 {
10995                                trimmed_selections
10996                                    .push(Point::new(row, 0)..Point::new(row, line_len));
10997                                continue;
10998                            }
10999                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11000                            if row_indent_size.len >= first_indent.len {
11001                                trimmed_selections.push(
11002                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11003                                );
11004                            } else {
11005                                trimmed_selections.clear();
11006                                trimmed_selections.push(start..end);
11007                                break;
11008                            }
11009                        }
11010                    }
11011                } else {
11012                    trimmed_selections.push(start..end);
11013                }
11014
11015                for trimmed_range in trimmed_selections {
11016                    if is_first {
11017                        is_first = false;
11018                    } else {
11019                        text += "\n";
11020                    }
11021                    let mut len = 0;
11022                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11023                        text.push_str(chunk);
11024                        len += chunk.len();
11025                    }
11026                    clipboard_selections.push(ClipboardSelection {
11027                        len,
11028                        is_entire_line,
11029                        first_line_indent: buffer
11030                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11031                            .len,
11032                    });
11033                }
11034            }
11035        }
11036
11037        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11038            text,
11039            clipboard_selections,
11040        ));
11041    }
11042
11043    pub fn do_paste(
11044        &mut self,
11045        text: &String,
11046        clipboard_selections: Option<Vec<ClipboardSelection>>,
11047        handle_entire_lines: bool,
11048        window: &mut Window,
11049        cx: &mut Context<Self>,
11050    ) {
11051        if self.read_only(cx) {
11052            return;
11053        }
11054
11055        let clipboard_text = Cow::Borrowed(text);
11056
11057        self.transact(window, cx, |this, window, cx| {
11058            if let Some(mut clipboard_selections) = clipboard_selections {
11059                let old_selections = this.selections.all::<usize>(cx);
11060                let all_selections_were_entire_line =
11061                    clipboard_selections.iter().all(|s| s.is_entire_line);
11062                let first_selection_indent_column =
11063                    clipboard_selections.first().map(|s| s.first_line_indent);
11064                if clipboard_selections.len() != old_selections.len() {
11065                    clipboard_selections.drain(..);
11066                }
11067                let cursor_offset = this.selections.last::<usize>(cx).head();
11068                let mut auto_indent_on_paste = true;
11069
11070                this.buffer.update(cx, |buffer, cx| {
11071                    let snapshot = buffer.read(cx);
11072                    auto_indent_on_paste = snapshot
11073                        .language_settings_at(cursor_offset, cx)
11074                        .auto_indent_on_paste;
11075
11076                    let mut start_offset = 0;
11077                    let mut edits = Vec::new();
11078                    let mut original_indent_columns = Vec::new();
11079                    for (ix, selection) in old_selections.iter().enumerate() {
11080                        let to_insert;
11081                        let entire_line;
11082                        let original_indent_column;
11083                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11084                            let end_offset = start_offset + clipboard_selection.len;
11085                            to_insert = &clipboard_text[start_offset..end_offset];
11086                            entire_line = clipboard_selection.is_entire_line;
11087                            start_offset = end_offset + 1;
11088                            original_indent_column = Some(clipboard_selection.first_line_indent);
11089                        } else {
11090                            to_insert = clipboard_text.as_str();
11091                            entire_line = all_selections_were_entire_line;
11092                            original_indent_column = first_selection_indent_column
11093                        }
11094
11095                        // If the corresponding selection was empty when this slice of the
11096                        // clipboard text was written, then the entire line containing the
11097                        // selection was copied. If this selection is also currently empty,
11098                        // then paste the line before the current line of the buffer.
11099                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11100                            let column = selection.start.to_point(&snapshot).column as usize;
11101                            let line_start = selection.start - column;
11102                            line_start..line_start
11103                        } else {
11104                            selection.range()
11105                        };
11106
11107                        edits.push((range, to_insert));
11108                        original_indent_columns.push(original_indent_column);
11109                    }
11110                    drop(snapshot);
11111
11112                    buffer.edit(
11113                        edits,
11114                        if auto_indent_on_paste {
11115                            Some(AutoindentMode::Block {
11116                                original_indent_columns,
11117                            })
11118                        } else {
11119                            None
11120                        },
11121                        cx,
11122                    );
11123                });
11124
11125                let selections = this.selections.all::<usize>(cx);
11126                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11127                    s.select(selections)
11128                });
11129            } else {
11130                this.insert(&clipboard_text, window, cx);
11131            }
11132        });
11133    }
11134
11135    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11136        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11137        if let Some(item) = cx.read_from_clipboard() {
11138            let entries = item.entries();
11139
11140            match entries.first() {
11141                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11142                // of all the pasted entries.
11143                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11144                    .do_paste(
11145                        clipboard_string.text(),
11146                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11147                        true,
11148                        window,
11149                        cx,
11150                    ),
11151                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11152            }
11153        }
11154    }
11155
11156    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11157        if self.read_only(cx) {
11158            return;
11159        }
11160
11161        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11162
11163        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11164            if let Some((selections, _)) =
11165                self.selection_history.transaction(transaction_id).cloned()
11166            {
11167                self.change_selections(None, window, cx, |s| {
11168                    s.select_anchors(selections.to_vec());
11169                });
11170            } else {
11171                log::error!(
11172                    "No entry in selection_history found for undo. \
11173                     This may correspond to a bug where undo does not update the selection. \
11174                     If this is occurring, please add details to \
11175                     https://github.com/zed-industries/zed/issues/22692"
11176                );
11177            }
11178            self.request_autoscroll(Autoscroll::fit(), cx);
11179            self.unmark_text(window, cx);
11180            self.refresh_inline_completion(true, false, window, cx);
11181            cx.emit(EditorEvent::Edited { transaction_id });
11182            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11183        }
11184    }
11185
11186    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11187        if self.read_only(cx) {
11188            return;
11189        }
11190
11191        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11192
11193        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11194            if let Some((_, Some(selections))) =
11195                self.selection_history.transaction(transaction_id).cloned()
11196            {
11197                self.change_selections(None, window, cx, |s| {
11198                    s.select_anchors(selections.to_vec());
11199                });
11200            } else {
11201                log::error!(
11202                    "No entry in selection_history found for redo. \
11203                     This may correspond to a bug where undo does not update the selection. \
11204                     If this is occurring, please add details to \
11205                     https://github.com/zed-industries/zed/issues/22692"
11206                );
11207            }
11208            self.request_autoscroll(Autoscroll::fit(), cx);
11209            self.unmark_text(window, cx);
11210            self.refresh_inline_completion(true, false, window, cx);
11211            cx.emit(EditorEvent::Edited { transaction_id });
11212        }
11213    }
11214
11215    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11216        self.buffer
11217            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11218    }
11219
11220    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11221        self.buffer
11222            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11223    }
11224
11225    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11226        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11227        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11228            s.move_with(|map, selection| {
11229                let cursor = if selection.is_empty() {
11230                    movement::left(map, selection.start)
11231                } else {
11232                    selection.start
11233                };
11234                selection.collapse_to(cursor, SelectionGoal::None);
11235            });
11236        })
11237    }
11238
11239    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11240        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11241        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11242            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11243        })
11244    }
11245
11246    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11247        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11248        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11249            s.move_with(|map, selection| {
11250                let cursor = if selection.is_empty() {
11251                    movement::right(map, selection.end)
11252                } else {
11253                    selection.end
11254                };
11255                selection.collapse_to(cursor, SelectionGoal::None)
11256            });
11257        })
11258    }
11259
11260    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11261        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11262        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11263            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11264        })
11265    }
11266
11267    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11268        if self.take_rename(true, window, cx).is_some() {
11269            return;
11270        }
11271
11272        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11273            cx.propagate();
11274            return;
11275        }
11276
11277        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11278
11279        let text_layout_details = &self.text_layout_details(window);
11280        let selection_count = self.selections.count();
11281        let first_selection = self.selections.first_anchor();
11282
11283        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11284            s.move_with(|map, selection| {
11285                if !selection.is_empty() {
11286                    selection.goal = SelectionGoal::None;
11287                }
11288                let (cursor, goal) = movement::up(
11289                    map,
11290                    selection.start,
11291                    selection.goal,
11292                    false,
11293                    text_layout_details,
11294                );
11295                selection.collapse_to(cursor, goal);
11296            });
11297        });
11298
11299        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11300        {
11301            cx.propagate();
11302        }
11303    }
11304
11305    pub fn move_up_by_lines(
11306        &mut self,
11307        action: &MoveUpByLines,
11308        window: &mut Window,
11309        cx: &mut Context<Self>,
11310    ) {
11311        if self.take_rename(true, window, cx).is_some() {
11312            return;
11313        }
11314
11315        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11316            cx.propagate();
11317            return;
11318        }
11319
11320        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11321
11322        let text_layout_details = &self.text_layout_details(window);
11323
11324        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11325            s.move_with(|map, selection| {
11326                if !selection.is_empty() {
11327                    selection.goal = SelectionGoal::None;
11328                }
11329                let (cursor, goal) = movement::up_by_rows(
11330                    map,
11331                    selection.start,
11332                    action.lines,
11333                    selection.goal,
11334                    false,
11335                    text_layout_details,
11336                );
11337                selection.collapse_to(cursor, goal);
11338            });
11339        })
11340    }
11341
11342    pub fn move_down_by_lines(
11343        &mut self,
11344        action: &MoveDownByLines,
11345        window: &mut Window,
11346        cx: &mut Context<Self>,
11347    ) {
11348        if self.take_rename(true, window, cx).is_some() {
11349            return;
11350        }
11351
11352        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11353            cx.propagate();
11354            return;
11355        }
11356
11357        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11358
11359        let text_layout_details = &self.text_layout_details(window);
11360
11361        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11362            s.move_with(|map, selection| {
11363                if !selection.is_empty() {
11364                    selection.goal = SelectionGoal::None;
11365                }
11366                let (cursor, goal) = movement::down_by_rows(
11367                    map,
11368                    selection.start,
11369                    action.lines,
11370                    selection.goal,
11371                    false,
11372                    text_layout_details,
11373                );
11374                selection.collapse_to(cursor, goal);
11375            });
11376        })
11377    }
11378
11379    pub fn select_down_by_lines(
11380        &mut self,
11381        action: &SelectDownByLines,
11382        window: &mut Window,
11383        cx: &mut Context<Self>,
11384    ) {
11385        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11386        let text_layout_details = &self.text_layout_details(window);
11387        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11388            s.move_heads_with(|map, head, goal| {
11389                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11390            })
11391        })
11392    }
11393
11394    pub fn select_up_by_lines(
11395        &mut self,
11396        action: &SelectUpByLines,
11397        window: &mut Window,
11398        cx: &mut Context<Self>,
11399    ) {
11400        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11401        let text_layout_details = &self.text_layout_details(window);
11402        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11403            s.move_heads_with(|map, head, goal| {
11404                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11405            })
11406        })
11407    }
11408
11409    pub fn select_page_up(
11410        &mut self,
11411        _: &SelectPageUp,
11412        window: &mut Window,
11413        cx: &mut Context<Self>,
11414    ) {
11415        let Some(row_count) = self.visible_row_count() else {
11416            return;
11417        };
11418
11419        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11420
11421        let text_layout_details = &self.text_layout_details(window);
11422
11423        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11424            s.move_heads_with(|map, head, goal| {
11425                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11426            })
11427        })
11428    }
11429
11430    pub fn move_page_up(
11431        &mut self,
11432        action: &MovePageUp,
11433        window: &mut Window,
11434        cx: &mut Context<Self>,
11435    ) {
11436        if self.take_rename(true, window, cx).is_some() {
11437            return;
11438        }
11439
11440        if self
11441            .context_menu
11442            .borrow_mut()
11443            .as_mut()
11444            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11445            .unwrap_or(false)
11446        {
11447            return;
11448        }
11449
11450        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11451            cx.propagate();
11452            return;
11453        }
11454
11455        let Some(row_count) = self.visible_row_count() else {
11456            return;
11457        };
11458
11459        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11460
11461        let autoscroll = if action.center_cursor {
11462            Autoscroll::center()
11463        } else {
11464            Autoscroll::fit()
11465        };
11466
11467        let text_layout_details = &self.text_layout_details(window);
11468
11469        self.change_selections(Some(autoscroll), window, cx, |s| {
11470            s.move_with(|map, selection| {
11471                if !selection.is_empty() {
11472                    selection.goal = SelectionGoal::None;
11473                }
11474                let (cursor, goal) = movement::up_by_rows(
11475                    map,
11476                    selection.end,
11477                    row_count,
11478                    selection.goal,
11479                    false,
11480                    text_layout_details,
11481                );
11482                selection.collapse_to(cursor, goal);
11483            });
11484        });
11485    }
11486
11487    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11488        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11489        let text_layout_details = &self.text_layout_details(window);
11490        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11491            s.move_heads_with(|map, head, goal| {
11492                movement::up(map, head, goal, false, text_layout_details)
11493            })
11494        })
11495    }
11496
11497    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11498        self.take_rename(true, window, cx);
11499
11500        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11501            cx.propagate();
11502            return;
11503        }
11504
11505        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11506
11507        let text_layout_details = &self.text_layout_details(window);
11508        let selection_count = self.selections.count();
11509        let first_selection = self.selections.first_anchor();
11510
11511        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11512            s.move_with(|map, selection| {
11513                if !selection.is_empty() {
11514                    selection.goal = SelectionGoal::None;
11515                }
11516                let (cursor, goal) = movement::down(
11517                    map,
11518                    selection.end,
11519                    selection.goal,
11520                    false,
11521                    text_layout_details,
11522                );
11523                selection.collapse_to(cursor, goal);
11524            });
11525        });
11526
11527        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11528        {
11529            cx.propagate();
11530        }
11531    }
11532
11533    pub fn select_page_down(
11534        &mut self,
11535        _: &SelectPageDown,
11536        window: &mut Window,
11537        cx: &mut Context<Self>,
11538    ) {
11539        let Some(row_count) = self.visible_row_count() else {
11540            return;
11541        };
11542
11543        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11544
11545        let text_layout_details = &self.text_layout_details(window);
11546
11547        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11548            s.move_heads_with(|map, head, goal| {
11549                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11550            })
11551        })
11552    }
11553
11554    pub fn move_page_down(
11555        &mut self,
11556        action: &MovePageDown,
11557        window: &mut Window,
11558        cx: &mut Context<Self>,
11559    ) {
11560        if self.take_rename(true, window, cx).is_some() {
11561            return;
11562        }
11563
11564        if self
11565            .context_menu
11566            .borrow_mut()
11567            .as_mut()
11568            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
11569            .unwrap_or(false)
11570        {
11571            return;
11572        }
11573
11574        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11575            cx.propagate();
11576            return;
11577        }
11578
11579        let Some(row_count) = self.visible_row_count() else {
11580            return;
11581        };
11582
11583        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11584
11585        let autoscroll = if action.center_cursor {
11586            Autoscroll::center()
11587        } else {
11588            Autoscroll::fit()
11589        };
11590
11591        let text_layout_details = &self.text_layout_details(window);
11592        self.change_selections(Some(autoscroll), window, cx, |s| {
11593            s.move_with(|map, selection| {
11594                if !selection.is_empty() {
11595                    selection.goal = SelectionGoal::None;
11596                }
11597                let (cursor, goal) = movement::down_by_rows(
11598                    map,
11599                    selection.end,
11600                    row_count,
11601                    selection.goal,
11602                    false,
11603                    text_layout_details,
11604                );
11605                selection.collapse_to(cursor, goal);
11606            });
11607        });
11608    }
11609
11610    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11611        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11612        let text_layout_details = &self.text_layout_details(window);
11613        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11614            s.move_heads_with(|map, head, goal| {
11615                movement::down(map, head, goal, false, text_layout_details)
11616            })
11617        });
11618    }
11619
11620    pub fn context_menu_first(
11621        &mut self,
11622        _: &ContextMenuFirst,
11623        window: &mut Window,
11624        cx: &mut Context<Self>,
11625    ) {
11626        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11627            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
11628        }
11629    }
11630
11631    pub fn context_menu_prev(
11632        &mut self,
11633        _: &ContextMenuPrevious,
11634        window: &mut Window,
11635        cx: &mut Context<Self>,
11636    ) {
11637        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11638            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
11639        }
11640    }
11641
11642    pub fn context_menu_next(
11643        &mut self,
11644        _: &ContextMenuNext,
11645        window: &mut Window,
11646        cx: &mut Context<Self>,
11647    ) {
11648        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11649            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
11650        }
11651    }
11652
11653    pub fn context_menu_last(
11654        &mut self,
11655        _: &ContextMenuLast,
11656        window: &mut Window,
11657        cx: &mut Context<Self>,
11658    ) {
11659        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11660            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
11661        }
11662    }
11663
11664    pub fn move_to_previous_word_start(
11665        &mut self,
11666        _: &MoveToPreviousWordStart,
11667        window: &mut Window,
11668        cx: &mut Context<Self>,
11669    ) {
11670        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11671        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11672            s.move_cursors_with(|map, head, _| {
11673                (
11674                    movement::previous_word_start(map, head),
11675                    SelectionGoal::None,
11676                )
11677            });
11678        })
11679    }
11680
11681    pub fn move_to_previous_subword_start(
11682        &mut self,
11683        _: &MoveToPreviousSubwordStart,
11684        window: &mut Window,
11685        cx: &mut Context<Self>,
11686    ) {
11687        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11688        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11689            s.move_cursors_with(|map, head, _| {
11690                (
11691                    movement::previous_subword_start(map, head),
11692                    SelectionGoal::None,
11693                )
11694            });
11695        })
11696    }
11697
11698    pub fn select_to_previous_word_start(
11699        &mut self,
11700        _: &SelectToPreviousWordStart,
11701        window: &mut Window,
11702        cx: &mut Context<Self>,
11703    ) {
11704        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11705        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11706            s.move_heads_with(|map, head, _| {
11707                (
11708                    movement::previous_word_start(map, head),
11709                    SelectionGoal::None,
11710                )
11711            });
11712        })
11713    }
11714
11715    pub fn select_to_previous_subword_start(
11716        &mut self,
11717        _: &SelectToPreviousSubwordStart,
11718        window: &mut Window,
11719        cx: &mut Context<Self>,
11720    ) {
11721        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11722        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11723            s.move_heads_with(|map, head, _| {
11724                (
11725                    movement::previous_subword_start(map, head),
11726                    SelectionGoal::None,
11727                )
11728            });
11729        })
11730    }
11731
11732    pub fn delete_to_previous_word_start(
11733        &mut self,
11734        action: &DeleteToPreviousWordStart,
11735        window: &mut Window,
11736        cx: &mut Context<Self>,
11737    ) {
11738        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11739        self.transact(window, cx, |this, window, cx| {
11740            this.select_autoclose_pair(window, cx);
11741            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11742                s.move_with(|map, selection| {
11743                    if selection.is_empty() {
11744                        let cursor = if action.ignore_newlines {
11745                            movement::previous_word_start(map, selection.head())
11746                        } else {
11747                            movement::previous_word_start_or_newline(map, selection.head())
11748                        };
11749                        selection.set_head(cursor, SelectionGoal::None);
11750                    }
11751                });
11752            });
11753            this.insert("", window, cx);
11754        });
11755    }
11756
11757    pub fn delete_to_previous_subword_start(
11758        &mut self,
11759        _: &DeleteToPreviousSubwordStart,
11760        window: &mut Window,
11761        cx: &mut Context<Self>,
11762    ) {
11763        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11764        self.transact(window, cx, |this, window, cx| {
11765            this.select_autoclose_pair(window, cx);
11766            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11767                s.move_with(|map, selection| {
11768                    if selection.is_empty() {
11769                        let cursor = movement::previous_subword_start(map, selection.head());
11770                        selection.set_head(cursor, SelectionGoal::None);
11771                    }
11772                });
11773            });
11774            this.insert("", window, cx);
11775        });
11776    }
11777
11778    pub fn move_to_next_word_end(
11779        &mut self,
11780        _: &MoveToNextWordEnd,
11781        window: &mut Window,
11782        cx: &mut Context<Self>,
11783    ) {
11784        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11785        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11786            s.move_cursors_with(|map, head, _| {
11787                (movement::next_word_end(map, head), SelectionGoal::None)
11788            });
11789        })
11790    }
11791
11792    pub fn move_to_next_subword_end(
11793        &mut self,
11794        _: &MoveToNextSubwordEnd,
11795        window: &mut Window,
11796        cx: &mut Context<Self>,
11797    ) {
11798        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11799        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11800            s.move_cursors_with(|map, head, _| {
11801                (movement::next_subword_end(map, head), SelectionGoal::None)
11802            });
11803        })
11804    }
11805
11806    pub fn select_to_next_word_end(
11807        &mut self,
11808        _: &SelectToNextWordEnd,
11809        window: &mut Window,
11810        cx: &mut Context<Self>,
11811    ) {
11812        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11813        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11814            s.move_heads_with(|map, head, _| {
11815                (movement::next_word_end(map, head), SelectionGoal::None)
11816            });
11817        })
11818    }
11819
11820    pub fn select_to_next_subword_end(
11821        &mut self,
11822        _: &SelectToNextSubwordEnd,
11823        window: &mut Window,
11824        cx: &mut Context<Self>,
11825    ) {
11826        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11827        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11828            s.move_heads_with(|map, head, _| {
11829                (movement::next_subword_end(map, head), SelectionGoal::None)
11830            });
11831        })
11832    }
11833
11834    pub fn delete_to_next_word_end(
11835        &mut self,
11836        action: &DeleteToNextWordEnd,
11837        window: &mut Window,
11838        cx: &mut Context<Self>,
11839    ) {
11840        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11841        self.transact(window, cx, |this, window, cx| {
11842            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11843                s.move_with(|map, selection| {
11844                    if selection.is_empty() {
11845                        let cursor = if action.ignore_newlines {
11846                            movement::next_word_end(map, selection.head())
11847                        } else {
11848                            movement::next_word_end_or_newline(map, selection.head())
11849                        };
11850                        selection.set_head(cursor, SelectionGoal::None);
11851                    }
11852                });
11853            });
11854            this.insert("", window, cx);
11855        });
11856    }
11857
11858    pub fn delete_to_next_subword_end(
11859        &mut self,
11860        _: &DeleteToNextSubwordEnd,
11861        window: &mut Window,
11862        cx: &mut Context<Self>,
11863    ) {
11864        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11865        self.transact(window, cx, |this, window, cx| {
11866            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11867                s.move_with(|map, selection| {
11868                    if selection.is_empty() {
11869                        let cursor = movement::next_subword_end(map, selection.head());
11870                        selection.set_head(cursor, SelectionGoal::None);
11871                    }
11872                });
11873            });
11874            this.insert("", window, cx);
11875        });
11876    }
11877
11878    pub fn move_to_beginning_of_line(
11879        &mut self,
11880        action: &MoveToBeginningOfLine,
11881        window: &mut Window,
11882        cx: &mut Context<Self>,
11883    ) {
11884        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11885        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11886            s.move_cursors_with(|map, head, _| {
11887                (
11888                    movement::indented_line_beginning(
11889                        map,
11890                        head,
11891                        action.stop_at_soft_wraps,
11892                        action.stop_at_indent,
11893                    ),
11894                    SelectionGoal::None,
11895                )
11896            });
11897        })
11898    }
11899
11900    pub fn select_to_beginning_of_line(
11901        &mut self,
11902        action: &SelectToBeginningOfLine,
11903        window: &mut Window,
11904        cx: &mut Context<Self>,
11905    ) {
11906        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11907        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11908            s.move_heads_with(|map, head, _| {
11909                (
11910                    movement::indented_line_beginning(
11911                        map,
11912                        head,
11913                        action.stop_at_soft_wraps,
11914                        action.stop_at_indent,
11915                    ),
11916                    SelectionGoal::None,
11917                )
11918            });
11919        });
11920    }
11921
11922    pub fn delete_to_beginning_of_line(
11923        &mut self,
11924        action: &DeleteToBeginningOfLine,
11925        window: &mut Window,
11926        cx: &mut Context<Self>,
11927    ) {
11928        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11929        self.transact(window, cx, |this, window, cx| {
11930            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11931                s.move_with(|_, selection| {
11932                    selection.reversed = true;
11933                });
11934            });
11935
11936            this.select_to_beginning_of_line(
11937                &SelectToBeginningOfLine {
11938                    stop_at_soft_wraps: false,
11939                    stop_at_indent: action.stop_at_indent,
11940                },
11941                window,
11942                cx,
11943            );
11944            this.backspace(&Backspace, window, cx);
11945        });
11946    }
11947
11948    pub fn move_to_end_of_line(
11949        &mut self,
11950        action: &MoveToEndOfLine,
11951        window: &mut Window,
11952        cx: &mut Context<Self>,
11953    ) {
11954        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11955        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11956            s.move_cursors_with(|map, head, _| {
11957                (
11958                    movement::line_end(map, head, action.stop_at_soft_wraps),
11959                    SelectionGoal::None,
11960                )
11961            });
11962        })
11963    }
11964
11965    pub fn select_to_end_of_line(
11966        &mut self,
11967        action: &SelectToEndOfLine,
11968        window: &mut Window,
11969        cx: &mut Context<Self>,
11970    ) {
11971        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11972        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11973            s.move_heads_with(|map, head, _| {
11974                (
11975                    movement::line_end(map, head, action.stop_at_soft_wraps),
11976                    SelectionGoal::None,
11977                )
11978            });
11979        })
11980    }
11981
11982    pub fn delete_to_end_of_line(
11983        &mut self,
11984        _: &DeleteToEndOfLine,
11985        window: &mut Window,
11986        cx: &mut Context<Self>,
11987    ) {
11988        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11989        self.transact(window, cx, |this, window, cx| {
11990            this.select_to_end_of_line(
11991                &SelectToEndOfLine {
11992                    stop_at_soft_wraps: false,
11993                },
11994                window,
11995                cx,
11996            );
11997            this.delete(&Delete, window, cx);
11998        });
11999    }
12000
12001    pub fn cut_to_end_of_line(
12002        &mut self,
12003        _: &CutToEndOfLine,
12004        window: &mut Window,
12005        cx: &mut Context<Self>,
12006    ) {
12007        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12008        self.transact(window, cx, |this, window, cx| {
12009            this.select_to_end_of_line(
12010                &SelectToEndOfLine {
12011                    stop_at_soft_wraps: false,
12012                },
12013                window,
12014                cx,
12015            );
12016            this.cut(&Cut, window, cx);
12017        });
12018    }
12019
12020    pub fn move_to_start_of_paragraph(
12021        &mut self,
12022        _: &MoveToStartOfParagraph,
12023        window: &mut Window,
12024        cx: &mut Context<Self>,
12025    ) {
12026        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12027            cx.propagate();
12028            return;
12029        }
12030        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12031        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12032            s.move_with(|map, selection| {
12033                selection.collapse_to(
12034                    movement::start_of_paragraph(map, selection.head(), 1),
12035                    SelectionGoal::None,
12036                )
12037            });
12038        })
12039    }
12040
12041    pub fn move_to_end_of_paragraph(
12042        &mut self,
12043        _: &MoveToEndOfParagraph,
12044        window: &mut Window,
12045        cx: &mut Context<Self>,
12046    ) {
12047        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12048            cx.propagate();
12049            return;
12050        }
12051        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12052        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12053            s.move_with(|map, selection| {
12054                selection.collapse_to(
12055                    movement::end_of_paragraph(map, selection.head(), 1),
12056                    SelectionGoal::None,
12057                )
12058            });
12059        })
12060    }
12061
12062    pub fn select_to_start_of_paragraph(
12063        &mut self,
12064        _: &SelectToStartOfParagraph,
12065        window: &mut Window,
12066        cx: &mut Context<Self>,
12067    ) {
12068        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12069            cx.propagate();
12070            return;
12071        }
12072        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12073        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12074            s.move_heads_with(|map, head, _| {
12075                (
12076                    movement::start_of_paragraph(map, head, 1),
12077                    SelectionGoal::None,
12078                )
12079            });
12080        })
12081    }
12082
12083    pub fn select_to_end_of_paragraph(
12084        &mut self,
12085        _: &SelectToEndOfParagraph,
12086        window: &mut Window,
12087        cx: &mut Context<Self>,
12088    ) {
12089        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12090            cx.propagate();
12091            return;
12092        }
12093        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12094        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12095            s.move_heads_with(|map, head, _| {
12096                (
12097                    movement::end_of_paragraph(map, head, 1),
12098                    SelectionGoal::None,
12099                )
12100            });
12101        })
12102    }
12103
12104    pub fn move_to_start_of_excerpt(
12105        &mut self,
12106        _: &MoveToStartOfExcerpt,
12107        window: &mut Window,
12108        cx: &mut Context<Self>,
12109    ) {
12110        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12111            cx.propagate();
12112            return;
12113        }
12114        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12115        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12116            s.move_with(|map, selection| {
12117                selection.collapse_to(
12118                    movement::start_of_excerpt(
12119                        map,
12120                        selection.head(),
12121                        workspace::searchable::Direction::Prev,
12122                    ),
12123                    SelectionGoal::None,
12124                )
12125            });
12126        })
12127    }
12128
12129    pub fn move_to_start_of_next_excerpt(
12130        &mut self,
12131        _: &MoveToStartOfNextExcerpt,
12132        window: &mut Window,
12133        cx: &mut Context<Self>,
12134    ) {
12135        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12136            cx.propagate();
12137            return;
12138        }
12139
12140        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12141            s.move_with(|map, selection| {
12142                selection.collapse_to(
12143                    movement::start_of_excerpt(
12144                        map,
12145                        selection.head(),
12146                        workspace::searchable::Direction::Next,
12147                    ),
12148                    SelectionGoal::None,
12149                )
12150            });
12151        })
12152    }
12153
12154    pub fn move_to_end_of_excerpt(
12155        &mut self,
12156        _: &MoveToEndOfExcerpt,
12157        window: &mut Window,
12158        cx: &mut Context<Self>,
12159    ) {
12160        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12161            cx.propagate();
12162            return;
12163        }
12164        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12165        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12166            s.move_with(|map, selection| {
12167                selection.collapse_to(
12168                    movement::end_of_excerpt(
12169                        map,
12170                        selection.head(),
12171                        workspace::searchable::Direction::Next,
12172                    ),
12173                    SelectionGoal::None,
12174                )
12175            });
12176        })
12177    }
12178
12179    pub fn move_to_end_of_previous_excerpt(
12180        &mut self,
12181        _: &MoveToEndOfPreviousExcerpt,
12182        window: &mut Window,
12183        cx: &mut Context<Self>,
12184    ) {
12185        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12186            cx.propagate();
12187            return;
12188        }
12189        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12190        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12191            s.move_with(|map, selection| {
12192                selection.collapse_to(
12193                    movement::end_of_excerpt(
12194                        map,
12195                        selection.head(),
12196                        workspace::searchable::Direction::Prev,
12197                    ),
12198                    SelectionGoal::None,
12199                )
12200            });
12201        })
12202    }
12203
12204    pub fn select_to_start_of_excerpt(
12205        &mut self,
12206        _: &SelectToStartOfExcerpt,
12207        window: &mut Window,
12208        cx: &mut Context<Self>,
12209    ) {
12210        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12211            cx.propagate();
12212            return;
12213        }
12214        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12215        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12216            s.move_heads_with(|map, head, _| {
12217                (
12218                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12219                    SelectionGoal::None,
12220                )
12221            });
12222        })
12223    }
12224
12225    pub fn select_to_start_of_next_excerpt(
12226        &mut self,
12227        _: &SelectToStartOfNextExcerpt,
12228        window: &mut Window,
12229        cx: &mut Context<Self>,
12230    ) {
12231        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12232            cx.propagate();
12233            return;
12234        }
12235        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12236        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12237            s.move_heads_with(|map, head, _| {
12238                (
12239                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12240                    SelectionGoal::None,
12241                )
12242            });
12243        })
12244    }
12245
12246    pub fn select_to_end_of_excerpt(
12247        &mut self,
12248        _: &SelectToEndOfExcerpt,
12249        window: &mut Window,
12250        cx: &mut Context<Self>,
12251    ) {
12252        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12253            cx.propagate();
12254            return;
12255        }
12256        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12257        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12258            s.move_heads_with(|map, head, _| {
12259                (
12260                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12261                    SelectionGoal::None,
12262                )
12263            });
12264        })
12265    }
12266
12267    pub fn select_to_end_of_previous_excerpt(
12268        &mut self,
12269        _: &SelectToEndOfPreviousExcerpt,
12270        window: &mut Window,
12271        cx: &mut Context<Self>,
12272    ) {
12273        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12274            cx.propagate();
12275            return;
12276        }
12277        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12278        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12279            s.move_heads_with(|map, head, _| {
12280                (
12281                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12282                    SelectionGoal::None,
12283                )
12284            });
12285        })
12286    }
12287
12288    pub fn move_to_beginning(
12289        &mut self,
12290        _: &MoveToBeginning,
12291        window: &mut Window,
12292        cx: &mut Context<Self>,
12293    ) {
12294        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12295            cx.propagate();
12296            return;
12297        }
12298        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12299        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12300            s.select_ranges(vec![0..0]);
12301        });
12302    }
12303
12304    pub fn select_to_beginning(
12305        &mut self,
12306        _: &SelectToBeginning,
12307        window: &mut Window,
12308        cx: &mut Context<Self>,
12309    ) {
12310        let mut selection = self.selections.last::<Point>(cx);
12311        selection.set_head(Point::zero(), SelectionGoal::None);
12312        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12313        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12314            s.select(vec![selection]);
12315        });
12316    }
12317
12318    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12319        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12320            cx.propagate();
12321            return;
12322        }
12323        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12324        let cursor = self.buffer.read(cx).read(cx).len();
12325        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12326            s.select_ranges(vec![cursor..cursor])
12327        });
12328    }
12329
12330    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12331        self.nav_history = nav_history;
12332    }
12333
12334    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12335        self.nav_history.as_ref()
12336    }
12337
12338    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12339        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12340    }
12341
12342    fn push_to_nav_history(
12343        &mut self,
12344        cursor_anchor: Anchor,
12345        new_position: Option<Point>,
12346        is_deactivate: bool,
12347        cx: &mut Context<Self>,
12348    ) {
12349        if let Some(nav_history) = self.nav_history.as_mut() {
12350            let buffer = self.buffer.read(cx).read(cx);
12351            let cursor_position = cursor_anchor.to_point(&buffer);
12352            let scroll_state = self.scroll_manager.anchor();
12353            let scroll_top_row = scroll_state.top_row(&buffer);
12354            drop(buffer);
12355
12356            if let Some(new_position) = new_position {
12357                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12358                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12359                    return;
12360                }
12361            }
12362
12363            nav_history.push(
12364                Some(NavigationData {
12365                    cursor_anchor,
12366                    cursor_position,
12367                    scroll_anchor: scroll_state,
12368                    scroll_top_row,
12369                }),
12370                cx,
12371            );
12372            cx.emit(EditorEvent::PushedToNavHistory {
12373                anchor: cursor_anchor,
12374                is_deactivate,
12375            })
12376        }
12377    }
12378
12379    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12380        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12381        let buffer = self.buffer.read(cx).snapshot(cx);
12382        let mut selection = self.selections.first::<usize>(cx);
12383        selection.set_head(buffer.len(), SelectionGoal::None);
12384        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12385            s.select(vec![selection]);
12386        });
12387    }
12388
12389    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12390        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12391        let end = self.buffer.read(cx).read(cx).len();
12392        self.change_selections(None, window, cx, |s| {
12393            s.select_ranges(vec![0..end]);
12394        });
12395    }
12396
12397    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12398        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12399        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12400        let mut selections = self.selections.all::<Point>(cx);
12401        let max_point = display_map.buffer_snapshot.max_point();
12402        for selection in &mut selections {
12403            let rows = selection.spanned_rows(true, &display_map);
12404            selection.start = Point::new(rows.start.0, 0);
12405            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12406            selection.reversed = false;
12407        }
12408        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12409            s.select(selections);
12410        });
12411    }
12412
12413    pub fn split_selection_into_lines(
12414        &mut self,
12415        _: &SplitSelectionIntoLines,
12416        window: &mut Window,
12417        cx: &mut Context<Self>,
12418    ) {
12419        let selections = self
12420            .selections
12421            .all::<Point>(cx)
12422            .into_iter()
12423            .map(|selection| selection.start..selection.end)
12424            .collect::<Vec<_>>();
12425        self.unfold_ranges(&selections, true, true, cx);
12426
12427        let mut new_selection_ranges = Vec::new();
12428        {
12429            let buffer = self.buffer.read(cx).read(cx);
12430            for selection in selections {
12431                for row in selection.start.row..selection.end.row {
12432                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12433                    new_selection_ranges.push(cursor..cursor);
12434                }
12435
12436                let is_multiline_selection = selection.start.row != selection.end.row;
12437                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12438                // so this action feels more ergonomic when paired with other selection operations
12439                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12440                if !should_skip_last {
12441                    new_selection_ranges.push(selection.end..selection.end);
12442                }
12443            }
12444        }
12445        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12446            s.select_ranges(new_selection_ranges);
12447        });
12448    }
12449
12450    pub fn add_selection_above(
12451        &mut self,
12452        _: &AddSelectionAbove,
12453        window: &mut Window,
12454        cx: &mut Context<Self>,
12455    ) {
12456        self.add_selection(true, window, cx);
12457    }
12458
12459    pub fn add_selection_below(
12460        &mut self,
12461        _: &AddSelectionBelow,
12462        window: &mut Window,
12463        cx: &mut Context<Self>,
12464    ) {
12465        self.add_selection(false, window, cx);
12466    }
12467
12468    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12469        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12470
12471        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12472        let mut selections = self.selections.all::<Point>(cx);
12473        let text_layout_details = self.text_layout_details(window);
12474        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12475            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12476            let range = oldest_selection.display_range(&display_map).sorted();
12477
12478            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12479            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12480            let positions = start_x.min(end_x)..start_x.max(end_x);
12481
12482            selections.clear();
12483            let mut stack = Vec::new();
12484            for row in range.start.row().0..=range.end.row().0 {
12485                if let Some(selection) = self.selections.build_columnar_selection(
12486                    &display_map,
12487                    DisplayRow(row),
12488                    &positions,
12489                    oldest_selection.reversed,
12490                    &text_layout_details,
12491                ) {
12492                    stack.push(selection.id);
12493                    selections.push(selection);
12494                }
12495            }
12496
12497            if above {
12498                stack.reverse();
12499            }
12500
12501            AddSelectionsState { above, stack }
12502        });
12503
12504        let last_added_selection = *state.stack.last().unwrap();
12505        let mut new_selections = Vec::new();
12506        if above == state.above {
12507            let end_row = if above {
12508                DisplayRow(0)
12509            } else {
12510                display_map.max_point().row()
12511            };
12512
12513            'outer: for selection in selections {
12514                if selection.id == last_added_selection {
12515                    let range = selection.display_range(&display_map).sorted();
12516                    debug_assert_eq!(range.start.row(), range.end.row());
12517                    let mut row = range.start.row();
12518                    let positions =
12519                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12520                            px(start)..px(end)
12521                        } else {
12522                            let start_x =
12523                                display_map.x_for_display_point(range.start, &text_layout_details);
12524                            let end_x =
12525                                display_map.x_for_display_point(range.end, &text_layout_details);
12526                            start_x.min(end_x)..start_x.max(end_x)
12527                        };
12528
12529                    while row != end_row {
12530                        if above {
12531                            row.0 -= 1;
12532                        } else {
12533                            row.0 += 1;
12534                        }
12535
12536                        if let Some(new_selection) = self.selections.build_columnar_selection(
12537                            &display_map,
12538                            row,
12539                            &positions,
12540                            selection.reversed,
12541                            &text_layout_details,
12542                        ) {
12543                            state.stack.push(new_selection.id);
12544                            if above {
12545                                new_selections.push(new_selection);
12546                                new_selections.push(selection);
12547                            } else {
12548                                new_selections.push(selection);
12549                                new_selections.push(new_selection);
12550                            }
12551
12552                            continue 'outer;
12553                        }
12554                    }
12555                }
12556
12557                new_selections.push(selection);
12558            }
12559        } else {
12560            new_selections = selections;
12561            new_selections.retain(|s| s.id != last_added_selection);
12562            state.stack.pop();
12563        }
12564
12565        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12566            s.select(new_selections);
12567        });
12568        if state.stack.len() > 1 {
12569            self.add_selections_state = Some(state);
12570        }
12571    }
12572
12573    fn select_match_ranges(
12574        &mut self,
12575        range: Range<usize>,
12576        reversed: bool,
12577        replace_newest: bool,
12578        auto_scroll: Option<Autoscroll>,
12579        window: &mut Window,
12580        cx: &mut Context<Editor>,
12581    ) {
12582        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12583        self.change_selections(auto_scroll, window, cx, |s| {
12584            if replace_newest {
12585                s.delete(s.newest_anchor().id);
12586            }
12587            if reversed {
12588                s.insert_range(range.end..range.start);
12589            } else {
12590                s.insert_range(range);
12591            }
12592        });
12593    }
12594
12595    pub fn select_next_match_internal(
12596        &mut self,
12597        display_map: &DisplaySnapshot,
12598        replace_newest: bool,
12599        autoscroll: Option<Autoscroll>,
12600        window: &mut Window,
12601        cx: &mut Context<Self>,
12602    ) -> Result<()> {
12603        let buffer = &display_map.buffer_snapshot;
12604        let mut selections = self.selections.all::<usize>(cx);
12605        if let Some(mut select_next_state) = self.select_next_state.take() {
12606            let query = &select_next_state.query;
12607            if !select_next_state.done {
12608                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12609                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12610                let mut next_selected_range = None;
12611
12612                let bytes_after_last_selection =
12613                    buffer.bytes_in_range(last_selection.end..buffer.len());
12614                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12615                let query_matches = query
12616                    .stream_find_iter(bytes_after_last_selection)
12617                    .map(|result| (last_selection.end, result))
12618                    .chain(
12619                        query
12620                            .stream_find_iter(bytes_before_first_selection)
12621                            .map(|result| (0, result)),
12622                    );
12623
12624                for (start_offset, query_match) in query_matches {
12625                    let query_match = query_match.unwrap(); // can only fail due to I/O
12626                    let offset_range =
12627                        start_offset + query_match.start()..start_offset + query_match.end();
12628                    let display_range = offset_range.start.to_display_point(display_map)
12629                        ..offset_range.end.to_display_point(display_map);
12630
12631                    if !select_next_state.wordwise
12632                        || (!movement::is_inside_word(display_map, display_range.start)
12633                            && !movement::is_inside_word(display_map, display_range.end))
12634                    {
12635                        // TODO: This is n^2, because we might check all the selections
12636                        if !selections
12637                            .iter()
12638                            .any(|selection| selection.range().overlaps(&offset_range))
12639                        {
12640                            next_selected_range = Some(offset_range);
12641                            break;
12642                        }
12643                    }
12644                }
12645
12646                if let Some(next_selected_range) = next_selected_range {
12647                    self.select_match_ranges(
12648                        next_selected_range,
12649                        last_selection.reversed,
12650                        replace_newest,
12651                        autoscroll,
12652                        window,
12653                        cx,
12654                    );
12655                } else {
12656                    select_next_state.done = true;
12657                }
12658            }
12659
12660            self.select_next_state = Some(select_next_state);
12661        } else {
12662            let mut only_carets = true;
12663            let mut same_text_selected = true;
12664            let mut selected_text = None;
12665
12666            let mut selections_iter = selections.iter().peekable();
12667            while let Some(selection) = selections_iter.next() {
12668                if selection.start != selection.end {
12669                    only_carets = false;
12670                }
12671
12672                if same_text_selected {
12673                    if selected_text.is_none() {
12674                        selected_text =
12675                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12676                    }
12677
12678                    if let Some(next_selection) = selections_iter.peek() {
12679                        if next_selection.range().len() == selection.range().len() {
12680                            let next_selected_text = buffer
12681                                .text_for_range(next_selection.range())
12682                                .collect::<String>();
12683                            if Some(next_selected_text) != selected_text {
12684                                same_text_selected = false;
12685                                selected_text = None;
12686                            }
12687                        } else {
12688                            same_text_selected = false;
12689                            selected_text = None;
12690                        }
12691                    }
12692                }
12693            }
12694
12695            if only_carets {
12696                for selection in &mut selections {
12697                    let word_range = movement::surrounding_word(
12698                        display_map,
12699                        selection.start.to_display_point(display_map),
12700                    );
12701                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12702                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12703                    selection.goal = SelectionGoal::None;
12704                    selection.reversed = false;
12705                    self.select_match_ranges(
12706                        selection.start..selection.end,
12707                        selection.reversed,
12708                        replace_newest,
12709                        autoscroll,
12710                        window,
12711                        cx,
12712                    );
12713                }
12714
12715                if selections.len() == 1 {
12716                    let selection = selections
12717                        .last()
12718                        .expect("ensured that there's only one selection");
12719                    let query = buffer
12720                        .text_for_range(selection.start..selection.end)
12721                        .collect::<String>();
12722                    let is_empty = query.is_empty();
12723                    let select_state = SelectNextState {
12724                        query: AhoCorasick::new(&[query])?,
12725                        wordwise: true,
12726                        done: is_empty,
12727                    };
12728                    self.select_next_state = Some(select_state);
12729                } else {
12730                    self.select_next_state = None;
12731                }
12732            } else if let Some(selected_text) = selected_text {
12733                self.select_next_state = Some(SelectNextState {
12734                    query: AhoCorasick::new(&[selected_text])?,
12735                    wordwise: false,
12736                    done: false,
12737                });
12738                self.select_next_match_internal(
12739                    display_map,
12740                    replace_newest,
12741                    autoscroll,
12742                    window,
12743                    cx,
12744                )?;
12745            }
12746        }
12747        Ok(())
12748    }
12749
12750    pub fn select_all_matches(
12751        &mut self,
12752        _action: &SelectAllMatches,
12753        window: &mut Window,
12754        cx: &mut Context<Self>,
12755    ) -> Result<()> {
12756        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12757
12758        self.push_to_selection_history();
12759        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12760
12761        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12762        let Some(select_next_state) = self.select_next_state.as_mut() else {
12763            return Ok(());
12764        };
12765        if select_next_state.done {
12766            return Ok(());
12767        }
12768
12769        let mut new_selections = Vec::new();
12770
12771        let reversed = self.selections.oldest::<usize>(cx).reversed;
12772        let buffer = &display_map.buffer_snapshot;
12773        let query_matches = select_next_state
12774            .query
12775            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12776
12777        for query_match in query_matches.into_iter() {
12778            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12779            let offset_range = if reversed {
12780                query_match.end()..query_match.start()
12781            } else {
12782                query_match.start()..query_match.end()
12783            };
12784            let display_range = offset_range.start.to_display_point(&display_map)
12785                ..offset_range.end.to_display_point(&display_map);
12786
12787            if !select_next_state.wordwise
12788                || (!movement::is_inside_word(&display_map, display_range.start)
12789                    && !movement::is_inside_word(&display_map, display_range.end))
12790            {
12791                new_selections.push(offset_range.start..offset_range.end);
12792            }
12793        }
12794
12795        select_next_state.done = true;
12796        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12797        self.change_selections(None, window, cx, |selections| {
12798            selections.select_ranges(new_selections)
12799        });
12800
12801        Ok(())
12802    }
12803
12804    pub fn select_next(
12805        &mut self,
12806        action: &SelectNext,
12807        window: &mut Window,
12808        cx: &mut Context<Self>,
12809    ) -> Result<()> {
12810        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12811        self.push_to_selection_history();
12812        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12813        self.select_next_match_internal(
12814            &display_map,
12815            action.replace_newest,
12816            Some(Autoscroll::newest()),
12817            window,
12818            cx,
12819        )?;
12820        Ok(())
12821    }
12822
12823    pub fn select_previous(
12824        &mut self,
12825        action: &SelectPrevious,
12826        window: &mut Window,
12827        cx: &mut Context<Self>,
12828    ) -> Result<()> {
12829        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12830        self.push_to_selection_history();
12831        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12832        let buffer = &display_map.buffer_snapshot;
12833        let mut selections = self.selections.all::<usize>(cx);
12834        if let Some(mut select_prev_state) = self.select_prev_state.take() {
12835            let query = &select_prev_state.query;
12836            if !select_prev_state.done {
12837                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12838                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12839                let mut next_selected_range = None;
12840                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
12841                let bytes_before_last_selection =
12842                    buffer.reversed_bytes_in_range(0..last_selection.start);
12843                let bytes_after_first_selection =
12844                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
12845                let query_matches = query
12846                    .stream_find_iter(bytes_before_last_selection)
12847                    .map(|result| (last_selection.start, result))
12848                    .chain(
12849                        query
12850                            .stream_find_iter(bytes_after_first_selection)
12851                            .map(|result| (buffer.len(), result)),
12852                    );
12853                for (end_offset, query_match) in query_matches {
12854                    let query_match = query_match.unwrap(); // can only fail due to I/O
12855                    let offset_range =
12856                        end_offset - query_match.end()..end_offset - query_match.start();
12857                    let display_range = offset_range.start.to_display_point(&display_map)
12858                        ..offset_range.end.to_display_point(&display_map);
12859
12860                    if !select_prev_state.wordwise
12861                        || (!movement::is_inside_word(&display_map, display_range.start)
12862                            && !movement::is_inside_word(&display_map, display_range.end))
12863                    {
12864                        next_selected_range = Some(offset_range);
12865                        break;
12866                    }
12867                }
12868
12869                if let Some(next_selected_range) = next_selected_range {
12870                    self.select_match_ranges(
12871                        next_selected_range,
12872                        last_selection.reversed,
12873                        action.replace_newest,
12874                        Some(Autoscroll::newest()),
12875                        window,
12876                        cx,
12877                    );
12878                } else {
12879                    select_prev_state.done = true;
12880                }
12881            }
12882
12883            self.select_prev_state = Some(select_prev_state);
12884        } else {
12885            let mut only_carets = true;
12886            let mut same_text_selected = true;
12887            let mut selected_text = None;
12888
12889            let mut selections_iter = selections.iter().peekable();
12890            while let Some(selection) = selections_iter.next() {
12891                if selection.start != selection.end {
12892                    only_carets = false;
12893                }
12894
12895                if same_text_selected {
12896                    if selected_text.is_none() {
12897                        selected_text =
12898                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12899                    }
12900
12901                    if let Some(next_selection) = selections_iter.peek() {
12902                        if next_selection.range().len() == selection.range().len() {
12903                            let next_selected_text = buffer
12904                                .text_for_range(next_selection.range())
12905                                .collect::<String>();
12906                            if Some(next_selected_text) != selected_text {
12907                                same_text_selected = false;
12908                                selected_text = None;
12909                            }
12910                        } else {
12911                            same_text_selected = false;
12912                            selected_text = None;
12913                        }
12914                    }
12915                }
12916            }
12917
12918            if only_carets {
12919                for selection in &mut selections {
12920                    let word_range = movement::surrounding_word(
12921                        &display_map,
12922                        selection.start.to_display_point(&display_map),
12923                    );
12924                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
12925                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
12926                    selection.goal = SelectionGoal::None;
12927                    selection.reversed = false;
12928                    self.select_match_ranges(
12929                        selection.start..selection.end,
12930                        selection.reversed,
12931                        action.replace_newest,
12932                        Some(Autoscroll::newest()),
12933                        window,
12934                        cx,
12935                    );
12936                }
12937                if selections.len() == 1 {
12938                    let selection = selections
12939                        .last()
12940                        .expect("ensured that there's only one selection");
12941                    let query = buffer
12942                        .text_for_range(selection.start..selection.end)
12943                        .collect::<String>();
12944                    let is_empty = query.is_empty();
12945                    let select_state = SelectNextState {
12946                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
12947                        wordwise: true,
12948                        done: is_empty,
12949                    };
12950                    self.select_prev_state = Some(select_state);
12951                } else {
12952                    self.select_prev_state = None;
12953                }
12954            } else if let Some(selected_text) = selected_text {
12955                self.select_prev_state = Some(SelectNextState {
12956                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
12957                    wordwise: false,
12958                    done: false,
12959                });
12960                self.select_previous(action, window, cx)?;
12961            }
12962        }
12963        Ok(())
12964    }
12965
12966    pub fn find_next_match(
12967        &mut self,
12968        _: &FindNextMatch,
12969        window: &mut Window,
12970        cx: &mut Context<Self>,
12971    ) -> Result<()> {
12972        let selections = self.selections.disjoint_anchors();
12973        match selections.first() {
12974            Some(first) if selections.len() >= 2 => {
12975                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12976                    s.select_ranges([first.range()]);
12977                });
12978            }
12979            _ => self.select_next(
12980                &SelectNext {
12981                    replace_newest: true,
12982                },
12983                window,
12984                cx,
12985            )?,
12986        }
12987        Ok(())
12988    }
12989
12990    pub fn find_previous_match(
12991        &mut self,
12992        _: &FindPreviousMatch,
12993        window: &mut Window,
12994        cx: &mut Context<Self>,
12995    ) -> Result<()> {
12996        let selections = self.selections.disjoint_anchors();
12997        match selections.last() {
12998            Some(last) if selections.len() >= 2 => {
12999                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13000                    s.select_ranges([last.range()]);
13001                });
13002            }
13003            _ => self.select_previous(
13004                &SelectPrevious {
13005                    replace_newest: true,
13006                },
13007                window,
13008                cx,
13009            )?,
13010        }
13011        Ok(())
13012    }
13013
13014    pub fn toggle_comments(
13015        &mut self,
13016        action: &ToggleComments,
13017        window: &mut Window,
13018        cx: &mut Context<Self>,
13019    ) {
13020        if self.read_only(cx) {
13021            return;
13022        }
13023        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
13024        let text_layout_details = &self.text_layout_details(window);
13025        self.transact(window, cx, |this, window, cx| {
13026            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13027            let mut edits = Vec::new();
13028            let mut selection_edit_ranges = Vec::new();
13029            let mut last_toggled_row = None;
13030            let snapshot = this.buffer.read(cx).read(cx);
13031            let empty_str: Arc<str> = Arc::default();
13032            let mut suffixes_inserted = Vec::new();
13033            let ignore_indent = action.ignore_indent;
13034
13035            fn comment_prefix_range(
13036                snapshot: &MultiBufferSnapshot,
13037                row: MultiBufferRow,
13038                comment_prefix: &str,
13039                comment_prefix_whitespace: &str,
13040                ignore_indent: bool,
13041            ) -> Range<Point> {
13042                let indent_size = if ignore_indent {
13043                    0
13044                } else {
13045                    snapshot.indent_size_for_line(row).len
13046                };
13047
13048                let start = Point::new(row.0, indent_size);
13049
13050                let mut line_bytes = snapshot
13051                    .bytes_in_range(start..snapshot.max_point())
13052                    .flatten()
13053                    .copied();
13054
13055                // If this line currently begins with the line comment prefix, then record
13056                // the range containing the prefix.
13057                if line_bytes
13058                    .by_ref()
13059                    .take(comment_prefix.len())
13060                    .eq(comment_prefix.bytes())
13061                {
13062                    // Include any whitespace that matches the comment prefix.
13063                    let matching_whitespace_len = line_bytes
13064                        .zip(comment_prefix_whitespace.bytes())
13065                        .take_while(|(a, b)| a == b)
13066                        .count() as u32;
13067                    let end = Point::new(
13068                        start.row,
13069                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13070                    );
13071                    start..end
13072                } else {
13073                    start..start
13074                }
13075            }
13076
13077            fn comment_suffix_range(
13078                snapshot: &MultiBufferSnapshot,
13079                row: MultiBufferRow,
13080                comment_suffix: &str,
13081                comment_suffix_has_leading_space: bool,
13082            ) -> Range<Point> {
13083                let end = Point::new(row.0, snapshot.line_len(row));
13084                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13085
13086                let mut line_end_bytes = snapshot
13087                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13088                    .flatten()
13089                    .copied();
13090
13091                let leading_space_len = if suffix_start_column > 0
13092                    && line_end_bytes.next() == Some(b' ')
13093                    && comment_suffix_has_leading_space
13094                {
13095                    1
13096                } else {
13097                    0
13098                };
13099
13100                // If this line currently begins with the line comment prefix, then record
13101                // the range containing the prefix.
13102                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13103                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13104                    start..end
13105                } else {
13106                    end..end
13107                }
13108            }
13109
13110            // TODO: Handle selections that cross excerpts
13111            for selection in &mut selections {
13112                let start_column = snapshot
13113                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13114                    .len;
13115                let language = if let Some(language) =
13116                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13117                {
13118                    language
13119                } else {
13120                    continue;
13121                };
13122
13123                selection_edit_ranges.clear();
13124
13125                // If multiple selections contain a given row, avoid processing that
13126                // row more than once.
13127                let mut start_row = MultiBufferRow(selection.start.row);
13128                if last_toggled_row == Some(start_row) {
13129                    start_row = start_row.next_row();
13130                }
13131                let end_row =
13132                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13133                        MultiBufferRow(selection.end.row - 1)
13134                    } else {
13135                        MultiBufferRow(selection.end.row)
13136                    };
13137                last_toggled_row = Some(end_row);
13138
13139                if start_row > end_row {
13140                    continue;
13141                }
13142
13143                // If the language has line comments, toggle those.
13144                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13145
13146                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13147                if ignore_indent {
13148                    full_comment_prefixes = full_comment_prefixes
13149                        .into_iter()
13150                        .map(|s| Arc::from(s.trim_end()))
13151                        .collect();
13152                }
13153
13154                if !full_comment_prefixes.is_empty() {
13155                    let first_prefix = full_comment_prefixes
13156                        .first()
13157                        .expect("prefixes is non-empty");
13158                    let prefix_trimmed_lengths = full_comment_prefixes
13159                        .iter()
13160                        .map(|p| p.trim_end_matches(' ').len())
13161                        .collect::<SmallVec<[usize; 4]>>();
13162
13163                    let mut all_selection_lines_are_comments = true;
13164
13165                    for row in start_row.0..=end_row.0 {
13166                        let row = MultiBufferRow(row);
13167                        if start_row < end_row && snapshot.is_line_blank(row) {
13168                            continue;
13169                        }
13170
13171                        let prefix_range = full_comment_prefixes
13172                            .iter()
13173                            .zip(prefix_trimmed_lengths.iter().copied())
13174                            .map(|(prefix, trimmed_prefix_len)| {
13175                                comment_prefix_range(
13176                                    snapshot.deref(),
13177                                    row,
13178                                    &prefix[..trimmed_prefix_len],
13179                                    &prefix[trimmed_prefix_len..],
13180                                    ignore_indent,
13181                                )
13182                            })
13183                            .max_by_key(|range| range.end.column - range.start.column)
13184                            .expect("prefixes is non-empty");
13185
13186                        if prefix_range.is_empty() {
13187                            all_selection_lines_are_comments = false;
13188                        }
13189
13190                        selection_edit_ranges.push(prefix_range);
13191                    }
13192
13193                    if all_selection_lines_are_comments {
13194                        edits.extend(
13195                            selection_edit_ranges
13196                                .iter()
13197                                .cloned()
13198                                .map(|range| (range, empty_str.clone())),
13199                        );
13200                    } else {
13201                        let min_column = selection_edit_ranges
13202                            .iter()
13203                            .map(|range| range.start.column)
13204                            .min()
13205                            .unwrap_or(0);
13206                        edits.extend(selection_edit_ranges.iter().map(|range| {
13207                            let position = Point::new(range.start.row, min_column);
13208                            (position..position, first_prefix.clone())
13209                        }));
13210                    }
13211                } else if let Some((full_comment_prefix, comment_suffix)) =
13212                    language.block_comment_delimiters()
13213                {
13214                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13215                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13216                    let prefix_range = comment_prefix_range(
13217                        snapshot.deref(),
13218                        start_row,
13219                        comment_prefix,
13220                        comment_prefix_whitespace,
13221                        ignore_indent,
13222                    );
13223                    let suffix_range = comment_suffix_range(
13224                        snapshot.deref(),
13225                        end_row,
13226                        comment_suffix.trim_start_matches(' '),
13227                        comment_suffix.starts_with(' '),
13228                    );
13229
13230                    if prefix_range.is_empty() || suffix_range.is_empty() {
13231                        edits.push((
13232                            prefix_range.start..prefix_range.start,
13233                            full_comment_prefix.clone(),
13234                        ));
13235                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13236                        suffixes_inserted.push((end_row, comment_suffix.len()));
13237                    } else {
13238                        edits.push((prefix_range, empty_str.clone()));
13239                        edits.push((suffix_range, empty_str.clone()));
13240                    }
13241                } else {
13242                    continue;
13243                }
13244            }
13245
13246            drop(snapshot);
13247            this.buffer.update(cx, |buffer, cx| {
13248                buffer.edit(edits, None, cx);
13249            });
13250
13251            // Adjust selections so that they end before any comment suffixes that
13252            // were inserted.
13253            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13254            let mut selections = this.selections.all::<Point>(cx);
13255            let snapshot = this.buffer.read(cx).read(cx);
13256            for selection in &mut selections {
13257                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13258                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13259                        Ordering::Less => {
13260                            suffixes_inserted.next();
13261                            continue;
13262                        }
13263                        Ordering::Greater => break,
13264                        Ordering::Equal => {
13265                            if selection.end.column == snapshot.line_len(row) {
13266                                if selection.is_empty() {
13267                                    selection.start.column -= suffix_len as u32;
13268                                }
13269                                selection.end.column -= suffix_len as u32;
13270                            }
13271                            break;
13272                        }
13273                    }
13274                }
13275            }
13276
13277            drop(snapshot);
13278            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13279                s.select(selections)
13280            });
13281
13282            let selections = this.selections.all::<Point>(cx);
13283            let selections_on_single_row = selections.windows(2).all(|selections| {
13284                selections[0].start.row == selections[1].start.row
13285                    && selections[0].end.row == selections[1].end.row
13286                    && selections[0].start.row == selections[0].end.row
13287            });
13288            let selections_selecting = selections
13289                .iter()
13290                .any(|selection| selection.start != selection.end);
13291            let advance_downwards = action.advance_downwards
13292                && selections_on_single_row
13293                && !selections_selecting
13294                && !matches!(this.mode, EditorMode::SingleLine { .. });
13295
13296            if advance_downwards {
13297                let snapshot = this.buffer.read(cx).snapshot(cx);
13298
13299                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13300                    s.move_cursors_with(|display_snapshot, display_point, _| {
13301                        let mut point = display_point.to_point(display_snapshot);
13302                        point.row += 1;
13303                        point = snapshot.clip_point(point, Bias::Left);
13304                        let display_point = point.to_display_point(display_snapshot);
13305                        let goal = SelectionGoal::HorizontalPosition(
13306                            display_snapshot
13307                                .x_for_display_point(display_point, text_layout_details)
13308                                .into(),
13309                        );
13310                        (display_point, goal)
13311                    })
13312                });
13313            }
13314        });
13315    }
13316
13317    pub fn select_enclosing_symbol(
13318        &mut self,
13319        _: &SelectEnclosingSymbol,
13320        window: &mut Window,
13321        cx: &mut Context<Self>,
13322    ) {
13323        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13324
13325        let buffer = self.buffer.read(cx).snapshot(cx);
13326        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13327
13328        fn update_selection(
13329            selection: &Selection<usize>,
13330            buffer_snap: &MultiBufferSnapshot,
13331        ) -> Option<Selection<usize>> {
13332            let cursor = selection.head();
13333            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13334            for symbol in symbols.iter().rev() {
13335                let start = symbol.range.start.to_offset(buffer_snap);
13336                let end = symbol.range.end.to_offset(buffer_snap);
13337                let new_range = start..end;
13338                if start < selection.start || end > selection.end {
13339                    return Some(Selection {
13340                        id: selection.id,
13341                        start: new_range.start,
13342                        end: new_range.end,
13343                        goal: SelectionGoal::None,
13344                        reversed: selection.reversed,
13345                    });
13346                }
13347            }
13348            None
13349        }
13350
13351        let mut selected_larger_symbol = false;
13352        let new_selections = old_selections
13353            .iter()
13354            .map(|selection| match update_selection(selection, &buffer) {
13355                Some(new_selection) => {
13356                    if new_selection.range() != selection.range() {
13357                        selected_larger_symbol = true;
13358                    }
13359                    new_selection
13360                }
13361                None => selection.clone(),
13362            })
13363            .collect::<Vec<_>>();
13364
13365        if selected_larger_symbol {
13366            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13367                s.select(new_selections);
13368            });
13369        }
13370    }
13371
13372    pub fn select_larger_syntax_node(
13373        &mut self,
13374        _: &SelectLargerSyntaxNode,
13375        window: &mut Window,
13376        cx: &mut Context<Self>,
13377    ) {
13378        let Some(visible_row_count) = self.visible_row_count() else {
13379            return;
13380        };
13381        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13382        if old_selections.is_empty() {
13383            return;
13384        }
13385
13386        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13387
13388        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13389        let buffer = self.buffer.read(cx).snapshot(cx);
13390
13391        let mut selected_larger_node = false;
13392        let mut new_selections = old_selections
13393            .iter()
13394            .map(|selection| {
13395                let old_range = selection.start..selection.end;
13396
13397                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13398                    // manually select word at selection
13399                    if ["string_content", "inline"].contains(&node.kind()) {
13400                        let word_range = {
13401                            let display_point = buffer
13402                                .offset_to_point(old_range.start)
13403                                .to_display_point(&display_map);
13404                            let Range { start, end } =
13405                                movement::surrounding_word(&display_map, display_point);
13406                            start.to_point(&display_map).to_offset(&buffer)
13407                                ..end.to_point(&display_map).to_offset(&buffer)
13408                        };
13409                        // ignore if word is already selected
13410                        if !word_range.is_empty() && old_range != word_range {
13411                            let last_word_range = {
13412                                let display_point = buffer
13413                                    .offset_to_point(old_range.end)
13414                                    .to_display_point(&display_map);
13415                                let Range { start, end } =
13416                                    movement::surrounding_word(&display_map, display_point);
13417                                start.to_point(&display_map).to_offset(&buffer)
13418                                    ..end.to_point(&display_map).to_offset(&buffer)
13419                            };
13420                            // only select word if start and end point belongs to same word
13421                            if word_range == last_word_range {
13422                                selected_larger_node = true;
13423                                return Selection {
13424                                    id: selection.id,
13425                                    start: word_range.start,
13426                                    end: word_range.end,
13427                                    goal: SelectionGoal::None,
13428                                    reversed: selection.reversed,
13429                                };
13430                            }
13431                        }
13432                    }
13433                }
13434
13435                let mut new_range = old_range.clone();
13436                while let Some((_node, containing_range)) =
13437                    buffer.syntax_ancestor(new_range.clone())
13438                {
13439                    new_range = match containing_range {
13440                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13441                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13442                    };
13443                    if !display_map.intersects_fold(new_range.start)
13444                        && !display_map.intersects_fold(new_range.end)
13445                    {
13446                        break;
13447                    }
13448                }
13449
13450                selected_larger_node |= new_range != old_range;
13451                Selection {
13452                    id: selection.id,
13453                    start: new_range.start,
13454                    end: new_range.end,
13455                    goal: SelectionGoal::None,
13456                    reversed: selection.reversed,
13457                }
13458            })
13459            .collect::<Vec<_>>();
13460
13461        if !selected_larger_node {
13462            return; // don't put this call in the history
13463        }
13464
13465        // scroll based on transformation done to the last selection created by the user
13466        let (last_old, last_new) = old_selections
13467            .last()
13468            .zip(new_selections.last().cloned())
13469            .expect("old_selections isn't empty");
13470
13471        // revert selection
13472        let is_selection_reversed = {
13473            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13474            new_selections.last_mut().expect("checked above").reversed =
13475                should_newest_selection_be_reversed;
13476            should_newest_selection_be_reversed
13477        };
13478
13479        if selected_larger_node {
13480            self.select_syntax_node_history.disable_clearing = true;
13481            self.change_selections(None, window, cx, |s| {
13482                s.select(new_selections.clone());
13483            });
13484            self.select_syntax_node_history.disable_clearing = false;
13485        }
13486
13487        let start_row = last_new.start.to_display_point(&display_map).row().0;
13488        let end_row = last_new.end.to_display_point(&display_map).row().0;
13489        let selection_height = end_row - start_row + 1;
13490        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13491
13492        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13493        let scroll_behavior = if fits_on_the_screen {
13494            self.request_autoscroll(Autoscroll::fit(), cx);
13495            SelectSyntaxNodeScrollBehavior::FitSelection
13496        } else if is_selection_reversed {
13497            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13498            SelectSyntaxNodeScrollBehavior::CursorTop
13499        } else {
13500            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13501            SelectSyntaxNodeScrollBehavior::CursorBottom
13502        };
13503
13504        self.select_syntax_node_history.push((
13505            old_selections,
13506            scroll_behavior,
13507            is_selection_reversed,
13508        ));
13509    }
13510
13511    pub fn select_smaller_syntax_node(
13512        &mut self,
13513        _: &SelectSmallerSyntaxNode,
13514        window: &mut Window,
13515        cx: &mut Context<Self>,
13516    ) {
13517        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13518
13519        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13520            self.select_syntax_node_history.pop()
13521        {
13522            if let Some(selection) = selections.last_mut() {
13523                selection.reversed = is_selection_reversed;
13524            }
13525
13526            self.select_syntax_node_history.disable_clearing = true;
13527            self.change_selections(None, window, cx, |s| {
13528                s.select(selections.to_vec());
13529            });
13530            self.select_syntax_node_history.disable_clearing = false;
13531
13532            match scroll_behavior {
13533                SelectSyntaxNodeScrollBehavior::CursorTop => {
13534                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13535                }
13536                SelectSyntaxNodeScrollBehavior::FitSelection => {
13537                    self.request_autoscroll(Autoscroll::fit(), cx);
13538                }
13539                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13540                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13541                }
13542            }
13543        }
13544    }
13545
13546    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13547        if !EditorSettings::get_global(cx).gutter.runnables {
13548            self.clear_tasks();
13549            return Task::ready(());
13550        }
13551        let project = self.project.as_ref().map(Entity::downgrade);
13552        let task_sources = self.lsp_task_sources(cx);
13553        let multi_buffer = self.buffer.downgrade();
13554        cx.spawn_in(window, async move |editor, cx| {
13555            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13556            let Some(project) = project.and_then(|p| p.upgrade()) else {
13557                return;
13558            };
13559            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13560                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13561            }) else {
13562                return;
13563            };
13564
13565            let hide_runnables = project
13566                .update(cx, |project, cx| {
13567                    // Do not display any test indicators in non-dev server remote projects.
13568                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13569                })
13570                .unwrap_or(true);
13571            if hide_runnables {
13572                return;
13573            }
13574            let new_rows =
13575                cx.background_spawn({
13576                    let snapshot = display_snapshot.clone();
13577                    async move {
13578                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13579                    }
13580                })
13581                    .await;
13582            let Ok(lsp_tasks) =
13583                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13584            else {
13585                return;
13586            };
13587            let lsp_tasks = lsp_tasks.await;
13588
13589            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13590                lsp_tasks
13591                    .into_iter()
13592                    .flat_map(|(kind, tasks)| {
13593                        tasks.into_iter().filter_map(move |(location, task)| {
13594                            Some((kind.clone(), location?, task))
13595                        })
13596                    })
13597                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13598                        let buffer = location.target.buffer;
13599                        let buffer_snapshot = buffer.read(cx).snapshot();
13600                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13601                            |(excerpt_id, snapshot, _)| {
13602                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13603                                    display_snapshot
13604                                        .buffer_snapshot
13605                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13606                                } else {
13607                                    None
13608                                }
13609                            },
13610                        );
13611                        if let Some(offset) = offset {
13612                            let task_buffer_range =
13613                                location.target.range.to_point(&buffer_snapshot);
13614                            let context_buffer_range =
13615                                task_buffer_range.to_offset(&buffer_snapshot);
13616                            let context_range = BufferOffset(context_buffer_range.start)
13617                                ..BufferOffset(context_buffer_range.end);
13618
13619                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13620                                .or_insert_with(|| RunnableTasks {
13621                                    templates: Vec::new(),
13622                                    offset,
13623                                    column: task_buffer_range.start.column,
13624                                    extra_variables: HashMap::default(),
13625                                    context_range,
13626                                })
13627                                .templates
13628                                .push((kind, task.original_task().clone()));
13629                        }
13630
13631                        acc
13632                    })
13633            }) else {
13634                return;
13635            };
13636
13637            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
13638                buffer.language_settings(cx).tasks.prefer_lsp
13639            }) else {
13640                return;
13641            };
13642
13643            let rows = Self::runnable_rows(
13644                project,
13645                display_snapshot,
13646                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
13647                new_rows,
13648                cx.clone(),
13649            );
13650            editor
13651                .update(cx, |editor, _| {
13652                    editor.clear_tasks();
13653                    for (key, mut value) in rows {
13654                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13655                            value.templates.extend(lsp_tasks.templates);
13656                        }
13657
13658                        editor.insert_tasks(key, value);
13659                    }
13660                    for (key, value) in lsp_tasks_by_rows {
13661                        editor.insert_tasks(key, value);
13662                    }
13663                })
13664                .ok();
13665        })
13666    }
13667    fn fetch_runnable_ranges(
13668        snapshot: &DisplaySnapshot,
13669        range: Range<Anchor>,
13670    ) -> Vec<language::RunnableRange> {
13671        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13672    }
13673
13674    fn runnable_rows(
13675        project: Entity<Project>,
13676        snapshot: DisplaySnapshot,
13677        prefer_lsp: bool,
13678        runnable_ranges: Vec<RunnableRange>,
13679        mut cx: AsyncWindowContext,
13680    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13681        runnable_ranges
13682            .into_iter()
13683            .filter_map(|mut runnable| {
13684                let mut tasks = cx
13685                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13686                    .ok()?;
13687                if prefer_lsp {
13688                    tasks.retain(|(task_kind, _)| {
13689                        !matches!(task_kind, TaskSourceKind::Language { .. })
13690                    });
13691                }
13692                if tasks.is_empty() {
13693                    return None;
13694                }
13695
13696                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13697
13698                let row = snapshot
13699                    .buffer_snapshot
13700                    .buffer_line_for_row(MultiBufferRow(point.row))?
13701                    .1
13702                    .start
13703                    .row;
13704
13705                let context_range =
13706                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13707                Some((
13708                    (runnable.buffer_id, row),
13709                    RunnableTasks {
13710                        templates: tasks,
13711                        offset: snapshot
13712                            .buffer_snapshot
13713                            .anchor_before(runnable.run_range.start),
13714                        context_range,
13715                        column: point.column,
13716                        extra_variables: runnable.extra_captures,
13717                    },
13718                ))
13719            })
13720            .collect()
13721    }
13722
13723    fn templates_with_tags(
13724        project: &Entity<Project>,
13725        runnable: &mut Runnable,
13726        cx: &mut App,
13727    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13728        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13729            let (worktree_id, file) = project
13730                .buffer_for_id(runnable.buffer, cx)
13731                .and_then(|buffer| buffer.read(cx).file())
13732                .map(|file| (file.worktree_id(cx), file.clone()))
13733                .unzip();
13734
13735            (
13736                project.task_store().read(cx).task_inventory().cloned(),
13737                worktree_id,
13738                file,
13739            )
13740        });
13741
13742        let mut templates_with_tags = mem::take(&mut runnable.tags)
13743            .into_iter()
13744            .flat_map(|RunnableTag(tag)| {
13745                inventory
13746                    .as_ref()
13747                    .into_iter()
13748                    .flat_map(|inventory| {
13749                        inventory.read(cx).list_tasks(
13750                            file.clone(),
13751                            Some(runnable.language.clone()),
13752                            worktree_id,
13753                            cx,
13754                        )
13755                    })
13756                    .filter(move |(_, template)| {
13757                        template.tags.iter().any(|source_tag| source_tag == &tag)
13758                    })
13759            })
13760            .sorted_by_key(|(kind, _)| kind.to_owned())
13761            .collect::<Vec<_>>();
13762        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13763            // Strongest source wins; if we have worktree tag binding, prefer that to
13764            // global and language bindings;
13765            // if we have a global binding, prefer that to language binding.
13766            let first_mismatch = templates_with_tags
13767                .iter()
13768                .position(|(tag_source, _)| tag_source != leading_tag_source);
13769            if let Some(index) = first_mismatch {
13770                templates_with_tags.truncate(index);
13771            }
13772        }
13773
13774        templates_with_tags
13775    }
13776
13777    pub fn move_to_enclosing_bracket(
13778        &mut self,
13779        _: &MoveToEnclosingBracket,
13780        window: &mut Window,
13781        cx: &mut Context<Self>,
13782    ) {
13783        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13784        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13785            s.move_offsets_with(|snapshot, selection| {
13786                let Some(enclosing_bracket_ranges) =
13787                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13788                else {
13789                    return;
13790                };
13791
13792                let mut best_length = usize::MAX;
13793                let mut best_inside = false;
13794                let mut best_in_bracket_range = false;
13795                let mut best_destination = None;
13796                for (open, close) in enclosing_bracket_ranges {
13797                    let close = close.to_inclusive();
13798                    let length = close.end() - open.start;
13799                    let inside = selection.start >= open.end && selection.end <= *close.start();
13800                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13801                        || close.contains(&selection.head());
13802
13803                    // If best is next to a bracket and current isn't, skip
13804                    if !in_bracket_range && best_in_bracket_range {
13805                        continue;
13806                    }
13807
13808                    // Prefer smaller lengths unless best is inside and current isn't
13809                    if length > best_length && (best_inside || !inside) {
13810                        continue;
13811                    }
13812
13813                    best_length = length;
13814                    best_inside = inside;
13815                    best_in_bracket_range = in_bracket_range;
13816                    best_destination = Some(
13817                        if close.contains(&selection.start) && close.contains(&selection.end) {
13818                            if inside { open.end } else { open.start }
13819                        } else if inside {
13820                            *close.start()
13821                        } else {
13822                            *close.end()
13823                        },
13824                    );
13825                }
13826
13827                if let Some(destination) = best_destination {
13828                    selection.collapse_to(destination, SelectionGoal::None);
13829                }
13830            })
13831        });
13832    }
13833
13834    pub fn undo_selection(
13835        &mut self,
13836        _: &UndoSelection,
13837        window: &mut Window,
13838        cx: &mut Context<Self>,
13839    ) {
13840        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13841        self.end_selection(window, cx);
13842        self.selection_history.mode = SelectionHistoryMode::Undoing;
13843        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
13844            self.change_selections(None, window, cx, |s| {
13845                s.select_anchors(entry.selections.to_vec())
13846            });
13847            self.select_next_state = entry.select_next_state;
13848            self.select_prev_state = entry.select_prev_state;
13849            self.add_selections_state = entry.add_selections_state;
13850            self.request_autoscroll(Autoscroll::newest(), cx);
13851        }
13852        self.selection_history.mode = SelectionHistoryMode::Normal;
13853    }
13854
13855    pub fn redo_selection(
13856        &mut self,
13857        _: &RedoSelection,
13858        window: &mut Window,
13859        cx: &mut Context<Self>,
13860    ) {
13861        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13862        self.end_selection(window, cx);
13863        self.selection_history.mode = SelectionHistoryMode::Redoing;
13864        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
13865            self.change_selections(None, window, cx, |s| {
13866                s.select_anchors(entry.selections.to_vec())
13867            });
13868            self.select_next_state = entry.select_next_state;
13869            self.select_prev_state = entry.select_prev_state;
13870            self.add_selections_state = entry.add_selections_state;
13871            self.request_autoscroll(Autoscroll::newest(), cx);
13872        }
13873        self.selection_history.mode = SelectionHistoryMode::Normal;
13874    }
13875
13876    pub fn expand_excerpts(
13877        &mut self,
13878        action: &ExpandExcerpts,
13879        _: &mut Window,
13880        cx: &mut Context<Self>,
13881    ) {
13882        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
13883    }
13884
13885    pub fn expand_excerpts_down(
13886        &mut self,
13887        action: &ExpandExcerptsDown,
13888        _: &mut Window,
13889        cx: &mut Context<Self>,
13890    ) {
13891        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
13892    }
13893
13894    pub fn expand_excerpts_up(
13895        &mut self,
13896        action: &ExpandExcerptsUp,
13897        _: &mut Window,
13898        cx: &mut Context<Self>,
13899    ) {
13900        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
13901    }
13902
13903    pub fn expand_excerpts_for_direction(
13904        &mut self,
13905        lines: u32,
13906        direction: ExpandExcerptDirection,
13907
13908        cx: &mut Context<Self>,
13909    ) {
13910        let selections = self.selections.disjoint_anchors();
13911
13912        let lines = if lines == 0 {
13913            EditorSettings::get_global(cx).expand_excerpt_lines
13914        } else {
13915            lines
13916        };
13917
13918        self.buffer.update(cx, |buffer, cx| {
13919            let snapshot = buffer.snapshot(cx);
13920            let mut excerpt_ids = selections
13921                .iter()
13922                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
13923                .collect::<Vec<_>>();
13924            excerpt_ids.sort();
13925            excerpt_ids.dedup();
13926            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
13927        })
13928    }
13929
13930    pub fn expand_excerpt(
13931        &mut self,
13932        excerpt: ExcerptId,
13933        direction: ExpandExcerptDirection,
13934        window: &mut Window,
13935        cx: &mut Context<Self>,
13936    ) {
13937        let current_scroll_position = self.scroll_position(cx);
13938        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
13939        let mut should_scroll_up = false;
13940
13941        if direction == ExpandExcerptDirection::Down {
13942            let multi_buffer = self.buffer.read(cx);
13943            let snapshot = multi_buffer.snapshot(cx);
13944            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
13945                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
13946                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
13947                        let buffer_snapshot = buffer.read(cx).snapshot();
13948                        let excerpt_end_row =
13949                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
13950                        let last_row = buffer_snapshot.max_point().row;
13951                        let lines_below = last_row.saturating_sub(excerpt_end_row);
13952                        should_scroll_up = lines_below >= lines_to_expand;
13953                    }
13954                }
13955            }
13956        }
13957
13958        self.buffer.update(cx, |buffer, cx| {
13959            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
13960        });
13961
13962        if should_scroll_up {
13963            let new_scroll_position =
13964                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
13965            self.set_scroll_position(new_scroll_position, window, cx);
13966        }
13967    }
13968
13969    pub fn go_to_singleton_buffer_point(
13970        &mut self,
13971        point: Point,
13972        window: &mut Window,
13973        cx: &mut Context<Self>,
13974    ) {
13975        self.go_to_singleton_buffer_range(point..point, window, cx);
13976    }
13977
13978    pub fn go_to_singleton_buffer_range(
13979        &mut self,
13980        range: Range<Point>,
13981        window: &mut Window,
13982        cx: &mut Context<Self>,
13983    ) {
13984        let multibuffer = self.buffer().read(cx);
13985        let Some(buffer) = multibuffer.as_singleton() else {
13986            return;
13987        };
13988        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
13989            return;
13990        };
13991        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
13992            return;
13993        };
13994        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
13995            s.select_anchor_ranges([start..end])
13996        });
13997    }
13998
13999    pub fn go_to_diagnostic(
14000        &mut self,
14001        _: &GoToDiagnostic,
14002        window: &mut Window,
14003        cx: &mut Context<Self>,
14004    ) {
14005        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14006        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14007    }
14008
14009    pub fn go_to_prev_diagnostic(
14010        &mut self,
14011        _: &GoToPreviousDiagnostic,
14012        window: &mut Window,
14013        cx: &mut Context<Self>,
14014    ) {
14015        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14016        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14017    }
14018
14019    pub fn go_to_diagnostic_impl(
14020        &mut self,
14021        direction: Direction,
14022        window: &mut Window,
14023        cx: &mut Context<Self>,
14024    ) {
14025        let buffer = self.buffer.read(cx).snapshot(cx);
14026        let selection = self.selections.newest::<usize>(cx);
14027
14028        let mut active_group_id = None;
14029        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14030            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14031                active_group_id = Some(active_group.group_id);
14032            }
14033        }
14034
14035        fn filtered(
14036            snapshot: EditorSnapshot,
14037            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14038        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14039            diagnostics
14040                .filter(|entry| entry.range.start != entry.range.end)
14041                .filter(|entry| !entry.diagnostic.is_unnecessary)
14042                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14043        }
14044
14045        let snapshot = self.snapshot(window, cx);
14046        let before = filtered(
14047            snapshot.clone(),
14048            buffer
14049                .diagnostics_in_range(0..selection.start)
14050                .filter(|entry| entry.range.start <= selection.start),
14051        );
14052        let after = filtered(
14053            snapshot,
14054            buffer
14055                .diagnostics_in_range(selection.start..buffer.len())
14056                .filter(|entry| entry.range.start >= selection.start),
14057        );
14058
14059        let mut found: Option<DiagnosticEntry<usize>> = None;
14060        if direction == Direction::Prev {
14061            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14062            {
14063                for diagnostic in prev_diagnostics.into_iter().rev() {
14064                    if diagnostic.range.start != selection.start
14065                        || active_group_id
14066                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14067                    {
14068                        found = Some(diagnostic);
14069                        break 'outer;
14070                    }
14071                }
14072            }
14073        } else {
14074            for diagnostic in after.chain(before) {
14075                if diagnostic.range.start != selection.start
14076                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14077                {
14078                    found = Some(diagnostic);
14079                    break;
14080                }
14081            }
14082        }
14083        let Some(next_diagnostic) = found else {
14084            return;
14085        };
14086
14087        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14088            return;
14089        };
14090        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14091            s.select_ranges(vec![
14092                next_diagnostic.range.start..next_diagnostic.range.start,
14093            ])
14094        });
14095        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14096        self.refresh_inline_completion(false, true, window, cx);
14097    }
14098
14099    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14100        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14101        let snapshot = self.snapshot(window, cx);
14102        let selection = self.selections.newest::<Point>(cx);
14103        self.go_to_hunk_before_or_after_position(
14104            &snapshot,
14105            selection.head(),
14106            Direction::Next,
14107            window,
14108            cx,
14109        );
14110    }
14111
14112    pub fn go_to_hunk_before_or_after_position(
14113        &mut self,
14114        snapshot: &EditorSnapshot,
14115        position: Point,
14116        direction: Direction,
14117        window: &mut Window,
14118        cx: &mut Context<Editor>,
14119    ) {
14120        let row = if direction == Direction::Next {
14121            self.hunk_after_position(snapshot, position)
14122                .map(|hunk| hunk.row_range.start)
14123        } else {
14124            self.hunk_before_position(snapshot, position)
14125        };
14126
14127        if let Some(row) = row {
14128            let destination = Point::new(row.0, 0);
14129            let autoscroll = Autoscroll::center();
14130
14131            self.unfold_ranges(&[destination..destination], false, false, cx);
14132            self.change_selections(Some(autoscroll), window, cx, |s| {
14133                s.select_ranges([destination..destination]);
14134            });
14135        }
14136    }
14137
14138    fn hunk_after_position(
14139        &mut self,
14140        snapshot: &EditorSnapshot,
14141        position: Point,
14142    ) -> Option<MultiBufferDiffHunk> {
14143        snapshot
14144            .buffer_snapshot
14145            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14146            .find(|hunk| hunk.row_range.start.0 > position.row)
14147            .or_else(|| {
14148                snapshot
14149                    .buffer_snapshot
14150                    .diff_hunks_in_range(Point::zero()..position)
14151                    .find(|hunk| hunk.row_range.end.0 < position.row)
14152            })
14153    }
14154
14155    fn go_to_prev_hunk(
14156        &mut self,
14157        _: &GoToPreviousHunk,
14158        window: &mut Window,
14159        cx: &mut Context<Self>,
14160    ) {
14161        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14162        let snapshot = self.snapshot(window, cx);
14163        let selection = self.selections.newest::<Point>(cx);
14164        self.go_to_hunk_before_or_after_position(
14165            &snapshot,
14166            selection.head(),
14167            Direction::Prev,
14168            window,
14169            cx,
14170        );
14171    }
14172
14173    fn hunk_before_position(
14174        &mut self,
14175        snapshot: &EditorSnapshot,
14176        position: Point,
14177    ) -> Option<MultiBufferRow> {
14178        snapshot
14179            .buffer_snapshot
14180            .diff_hunk_before(position)
14181            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14182    }
14183
14184    fn go_to_next_change(
14185        &mut self,
14186        _: &GoToNextChange,
14187        window: &mut Window,
14188        cx: &mut Context<Self>,
14189    ) {
14190        if let Some(selections) = self
14191            .change_list
14192            .next_change(1, Direction::Next)
14193            .map(|s| s.to_vec())
14194        {
14195            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14196                let map = s.display_map();
14197                s.select_display_ranges(selections.iter().map(|a| {
14198                    let point = a.to_display_point(&map);
14199                    point..point
14200                }))
14201            })
14202        }
14203    }
14204
14205    fn go_to_previous_change(
14206        &mut self,
14207        _: &GoToPreviousChange,
14208        window: &mut Window,
14209        cx: &mut Context<Self>,
14210    ) {
14211        if let Some(selections) = self
14212            .change_list
14213            .next_change(1, Direction::Prev)
14214            .map(|s| s.to_vec())
14215        {
14216            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14217                let map = s.display_map();
14218                s.select_display_ranges(selections.iter().map(|a| {
14219                    let point = a.to_display_point(&map);
14220                    point..point
14221                }))
14222            })
14223        }
14224    }
14225
14226    fn go_to_line<T: 'static>(
14227        &mut self,
14228        position: Anchor,
14229        highlight_color: Option<Hsla>,
14230        window: &mut Window,
14231        cx: &mut Context<Self>,
14232    ) {
14233        let snapshot = self.snapshot(window, cx).display_snapshot;
14234        let position = position.to_point(&snapshot.buffer_snapshot);
14235        let start = snapshot
14236            .buffer_snapshot
14237            .clip_point(Point::new(position.row, 0), Bias::Left);
14238        let end = start + Point::new(1, 0);
14239        let start = snapshot.buffer_snapshot.anchor_before(start);
14240        let end = snapshot.buffer_snapshot.anchor_before(end);
14241
14242        self.highlight_rows::<T>(
14243            start..end,
14244            highlight_color
14245                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14246            Default::default(),
14247            cx,
14248        );
14249
14250        if self.buffer.read(cx).is_singleton() {
14251            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14252        }
14253    }
14254
14255    pub fn go_to_definition(
14256        &mut self,
14257        _: &GoToDefinition,
14258        window: &mut Window,
14259        cx: &mut Context<Self>,
14260    ) -> Task<Result<Navigated>> {
14261        let definition =
14262            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14263        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14264        cx.spawn_in(window, async move |editor, cx| {
14265            if definition.await? == Navigated::Yes {
14266                return Ok(Navigated::Yes);
14267            }
14268            match fallback_strategy {
14269                GoToDefinitionFallback::None => Ok(Navigated::No),
14270                GoToDefinitionFallback::FindAllReferences => {
14271                    match editor.update_in(cx, |editor, window, cx| {
14272                        editor.find_all_references(&FindAllReferences, window, cx)
14273                    })? {
14274                        Some(references) => references.await,
14275                        None => Ok(Navigated::No),
14276                    }
14277                }
14278            }
14279        })
14280    }
14281
14282    pub fn go_to_declaration(
14283        &mut self,
14284        _: &GoToDeclaration,
14285        window: &mut Window,
14286        cx: &mut Context<Self>,
14287    ) -> Task<Result<Navigated>> {
14288        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14289    }
14290
14291    pub fn go_to_declaration_split(
14292        &mut self,
14293        _: &GoToDeclaration,
14294        window: &mut Window,
14295        cx: &mut Context<Self>,
14296    ) -> Task<Result<Navigated>> {
14297        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14298    }
14299
14300    pub fn go_to_implementation(
14301        &mut self,
14302        _: &GoToImplementation,
14303        window: &mut Window,
14304        cx: &mut Context<Self>,
14305    ) -> Task<Result<Navigated>> {
14306        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14307    }
14308
14309    pub fn go_to_implementation_split(
14310        &mut self,
14311        _: &GoToImplementationSplit,
14312        window: &mut Window,
14313        cx: &mut Context<Self>,
14314    ) -> Task<Result<Navigated>> {
14315        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14316    }
14317
14318    pub fn go_to_type_definition(
14319        &mut self,
14320        _: &GoToTypeDefinition,
14321        window: &mut Window,
14322        cx: &mut Context<Self>,
14323    ) -> Task<Result<Navigated>> {
14324        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14325    }
14326
14327    pub fn go_to_definition_split(
14328        &mut self,
14329        _: &GoToDefinitionSplit,
14330        window: &mut Window,
14331        cx: &mut Context<Self>,
14332    ) -> Task<Result<Navigated>> {
14333        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14334    }
14335
14336    pub fn go_to_type_definition_split(
14337        &mut self,
14338        _: &GoToTypeDefinitionSplit,
14339        window: &mut Window,
14340        cx: &mut Context<Self>,
14341    ) -> Task<Result<Navigated>> {
14342        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14343    }
14344
14345    fn go_to_definition_of_kind(
14346        &mut self,
14347        kind: GotoDefinitionKind,
14348        split: bool,
14349        window: &mut Window,
14350        cx: &mut Context<Self>,
14351    ) -> Task<Result<Navigated>> {
14352        let Some(provider) = self.semantics_provider.clone() else {
14353            return Task::ready(Ok(Navigated::No));
14354        };
14355        let head = self.selections.newest::<usize>(cx).head();
14356        let buffer = self.buffer.read(cx);
14357        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14358            text_anchor
14359        } else {
14360            return Task::ready(Ok(Navigated::No));
14361        };
14362
14363        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14364            return Task::ready(Ok(Navigated::No));
14365        };
14366
14367        cx.spawn_in(window, async move |editor, cx| {
14368            let definitions = definitions.await?;
14369            let navigated = editor
14370                .update_in(cx, |editor, window, cx| {
14371                    editor.navigate_to_hover_links(
14372                        Some(kind),
14373                        definitions
14374                            .into_iter()
14375                            .filter(|location| {
14376                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14377                            })
14378                            .map(HoverLink::Text)
14379                            .collect::<Vec<_>>(),
14380                        split,
14381                        window,
14382                        cx,
14383                    )
14384                })?
14385                .await?;
14386            anyhow::Ok(navigated)
14387        })
14388    }
14389
14390    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14391        let selection = self.selections.newest_anchor();
14392        let head = selection.head();
14393        let tail = selection.tail();
14394
14395        let Some((buffer, start_position)) =
14396            self.buffer.read(cx).text_anchor_for_position(head, cx)
14397        else {
14398            return;
14399        };
14400
14401        let end_position = if head != tail {
14402            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14403                return;
14404            };
14405            Some(pos)
14406        } else {
14407            None
14408        };
14409
14410        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14411            let url = if let Some(end_pos) = end_position {
14412                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14413            } else {
14414                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14415            };
14416
14417            if let Some(url) = url {
14418                editor.update(cx, |_, cx| {
14419                    cx.open_url(&url);
14420                })
14421            } else {
14422                Ok(())
14423            }
14424        });
14425
14426        url_finder.detach();
14427    }
14428
14429    pub fn open_selected_filename(
14430        &mut self,
14431        _: &OpenSelectedFilename,
14432        window: &mut Window,
14433        cx: &mut Context<Self>,
14434    ) {
14435        let Some(workspace) = self.workspace() else {
14436            return;
14437        };
14438
14439        let position = self.selections.newest_anchor().head();
14440
14441        let Some((buffer, buffer_position)) =
14442            self.buffer.read(cx).text_anchor_for_position(position, cx)
14443        else {
14444            return;
14445        };
14446
14447        let project = self.project.clone();
14448
14449        cx.spawn_in(window, async move |_, cx| {
14450            let result = find_file(&buffer, project, buffer_position, cx).await;
14451
14452            if let Some((_, path)) = result {
14453                workspace
14454                    .update_in(cx, |workspace, window, cx| {
14455                        workspace.open_resolved_path(path, window, cx)
14456                    })?
14457                    .await?;
14458            }
14459            anyhow::Ok(())
14460        })
14461        .detach();
14462    }
14463
14464    pub(crate) fn navigate_to_hover_links(
14465        &mut self,
14466        kind: Option<GotoDefinitionKind>,
14467        mut definitions: Vec<HoverLink>,
14468        split: bool,
14469        window: &mut Window,
14470        cx: &mut Context<Editor>,
14471    ) -> Task<Result<Navigated>> {
14472        // If there is one definition, just open it directly
14473        if definitions.len() == 1 {
14474            let definition = definitions.pop().unwrap();
14475
14476            enum TargetTaskResult {
14477                Location(Option<Location>),
14478                AlreadyNavigated,
14479            }
14480
14481            let target_task = match definition {
14482                HoverLink::Text(link) => {
14483                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14484                }
14485                HoverLink::InlayHint(lsp_location, server_id) => {
14486                    let computation =
14487                        self.compute_target_location(lsp_location, server_id, window, cx);
14488                    cx.background_spawn(async move {
14489                        let location = computation.await?;
14490                        Ok(TargetTaskResult::Location(location))
14491                    })
14492                }
14493                HoverLink::Url(url) => {
14494                    cx.open_url(&url);
14495                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14496                }
14497                HoverLink::File(path) => {
14498                    if let Some(workspace) = self.workspace() {
14499                        cx.spawn_in(window, async move |_, cx| {
14500                            workspace
14501                                .update_in(cx, |workspace, window, cx| {
14502                                    workspace.open_resolved_path(path, window, cx)
14503                                })?
14504                                .await
14505                                .map(|_| TargetTaskResult::AlreadyNavigated)
14506                        })
14507                    } else {
14508                        Task::ready(Ok(TargetTaskResult::Location(None)))
14509                    }
14510                }
14511            };
14512            cx.spawn_in(window, async move |editor, cx| {
14513                let target = match target_task.await.context("target resolution task")? {
14514                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14515                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14516                    TargetTaskResult::Location(Some(target)) => target,
14517                };
14518
14519                editor.update_in(cx, |editor, window, cx| {
14520                    let Some(workspace) = editor.workspace() else {
14521                        return Navigated::No;
14522                    };
14523                    let pane = workspace.read(cx).active_pane().clone();
14524
14525                    let range = target.range.to_point(target.buffer.read(cx));
14526                    let range = editor.range_for_match(&range);
14527                    let range = collapse_multiline_range(range);
14528
14529                    if !split
14530                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14531                    {
14532                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14533                    } else {
14534                        window.defer(cx, move |window, cx| {
14535                            let target_editor: Entity<Self> =
14536                                workspace.update(cx, |workspace, cx| {
14537                                    let pane = if split {
14538                                        workspace.adjacent_pane(window, cx)
14539                                    } else {
14540                                        workspace.active_pane().clone()
14541                                    };
14542
14543                                    workspace.open_project_item(
14544                                        pane,
14545                                        target.buffer.clone(),
14546                                        true,
14547                                        true,
14548                                        window,
14549                                        cx,
14550                                    )
14551                                });
14552                            target_editor.update(cx, |target_editor, cx| {
14553                                // When selecting a definition in a different buffer, disable the nav history
14554                                // to avoid creating a history entry at the previous cursor location.
14555                                pane.update(cx, |pane, _| pane.disable_history());
14556                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14557                                pane.update(cx, |pane, _| pane.enable_history());
14558                            });
14559                        });
14560                    }
14561                    Navigated::Yes
14562                })
14563            })
14564        } else if !definitions.is_empty() {
14565            cx.spawn_in(window, async move |editor, cx| {
14566                let (title, location_tasks, workspace) = editor
14567                    .update_in(cx, |editor, window, cx| {
14568                        let tab_kind = match kind {
14569                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14570                            _ => "Definitions",
14571                        };
14572                        let title = definitions
14573                            .iter()
14574                            .find_map(|definition| match definition {
14575                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14576                                    let buffer = origin.buffer.read(cx);
14577                                    format!(
14578                                        "{} for {}",
14579                                        tab_kind,
14580                                        buffer
14581                                            .text_for_range(origin.range.clone())
14582                                            .collect::<String>()
14583                                    )
14584                                }),
14585                                HoverLink::InlayHint(_, _) => None,
14586                                HoverLink::Url(_) => None,
14587                                HoverLink::File(_) => None,
14588                            })
14589                            .unwrap_or(tab_kind.to_string());
14590                        let location_tasks = definitions
14591                            .into_iter()
14592                            .map(|definition| match definition {
14593                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14594                                HoverLink::InlayHint(lsp_location, server_id) => editor
14595                                    .compute_target_location(lsp_location, server_id, window, cx),
14596                                HoverLink::Url(_) => Task::ready(Ok(None)),
14597                                HoverLink::File(_) => Task::ready(Ok(None)),
14598                            })
14599                            .collect::<Vec<_>>();
14600                        (title, location_tasks, editor.workspace().clone())
14601                    })
14602                    .context("location tasks preparation")?;
14603
14604                let locations = future::join_all(location_tasks)
14605                    .await
14606                    .into_iter()
14607                    .filter_map(|location| location.transpose())
14608                    .collect::<Result<_>>()
14609                    .context("location tasks")?;
14610
14611                let Some(workspace) = workspace else {
14612                    return Ok(Navigated::No);
14613                };
14614                let opened = workspace
14615                    .update_in(cx, |workspace, window, cx| {
14616                        Self::open_locations_in_multibuffer(
14617                            workspace,
14618                            locations,
14619                            title,
14620                            split,
14621                            MultibufferSelectionMode::First,
14622                            window,
14623                            cx,
14624                        )
14625                    })
14626                    .ok();
14627
14628                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14629            })
14630        } else {
14631            Task::ready(Ok(Navigated::No))
14632        }
14633    }
14634
14635    fn compute_target_location(
14636        &self,
14637        lsp_location: lsp::Location,
14638        server_id: LanguageServerId,
14639        window: &mut Window,
14640        cx: &mut Context<Self>,
14641    ) -> Task<anyhow::Result<Option<Location>>> {
14642        let Some(project) = self.project.clone() else {
14643            return Task::ready(Ok(None));
14644        };
14645
14646        cx.spawn_in(window, async move |editor, cx| {
14647            let location_task = editor.update(cx, |_, cx| {
14648                project.update(cx, |project, cx| {
14649                    let language_server_name = project
14650                        .language_server_statuses(cx)
14651                        .find(|(id, _)| server_id == *id)
14652                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14653                    language_server_name.map(|language_server_name| {
14654                        project.open_local_buffer_via_lsp(
14655                            lsp_location.uri.clone(),
14656                            server_id,
14657                            language_server_name,
14658                            cx,
14659                        )
14660                    })
14661                })
14662            })?;
14663            let location = match location_task {
14664                Some(task) => Some({
14665                    let target_buffer_handle = task.await.context("open local buffer")?;
14666                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
14667                        let target_start = target_buffer
14668                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14669                        let target_end = target_buffer
14670                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14671                        target_buffer.anchor_after(target_start)
14672                            ..target_buffer.anchor_before(target_end)
14673                    })?;
14674                    Location {
14675                        buffer: target_buffer_handle,
14676                        range,
14677                    }
14678                }),
14679                None => None,
14680            };
14681            Ok(location)
14682        })
14683    }
14684
14685    pub fn find_all_references(
14686        &mut self,
14687        _: &FindAllReferences,
14688        window: &mut Window,
14689        cx: &mut Context<Self>,
14690    ) -> Option<Task<Result<Navigated>>> {
14691        let selection = self.selections.newest::<usize>(cx);
14692        let multi_buffer = self.buffer.read(cx);
14693        let head = selection.head();
14694
14695        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14696        let head_anchor = multi_buffer_snapshot.anchor_at(
14697            head,
14698            if head < selection.tail() {
14699                Bias::Right
14700            } else {
14701                Bias::Left
14702            },
14703        );
14704
14705        match self
14706            .find_all_references_task_sources
14707            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14708        {
14709            Ok(_) => {
14710                log::info!(
14711                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14712                );
14713                return None;
14714            }
14715            Err(i) => {
14716                self.find_all_references_task_sources.insert(i, head_anchor);
14717            }
14718        }
14719
14720        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14721        let workspace = self.workspace()?;
14722        let project = workspace.read(cx).project().clone();
14723        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14724        Some(cx.spawn_in(window, async move |editor, cx| {
14725            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14726                if let Ok(i) = editor
14727                    .find_all_references_task_sources
14728                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14729                {
14730                    editor.find_all_references_task_sources.remove(i);
14731                }
14732            });
14733
14734            let locations = references.await?;
14735            if locations.is_empty() {
14736                return anyhow::Ok(Navigated::No);
14737            }
14738
14739            workspace.update_in(cx, |workspace, window, cx| {
14740                let title = locations
14741                    .first()
14742                    .as_ref()
14743                    .map(|location| {
14744                        let buffer = location.buffer.read(cx);
14745                        format!(
14746                            "References to `{}`",
14747                            buffer
14748                                .text_for_range(location.range.clone())
14749                                .collect::<String>()
14750                        )
14751                    })
14752                    .unwrap();
14753                Self::open_locations_in_multibuffer(
14754                    workspace,
14755                    locations,
14756                    title,
14757                    false,
14758                    MultibufferSelectionMode::First,
14759                    window,
14760                    cx,
14761                );
14762                Navigated::Yes
14763            })
14764        }))
14765    }
14766
14767    /// Opens a multibuffer with the given project locations in it
14768    pub fn open_locations_in_multibuffer(
14769        workspace: &mut Workspace,
14770        mut locations: Vec<Location>,
14771        title: String,
14772        split: bool,
14773        multibuffer_selection_mode: MultibufferSelectionMode,
14774        window: &mut Window,
14775        cx: &mut Context<Workspace>,
14776    ) {
14777        // If there are multiple definitions, open them in a multibuffer
14778        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14779        let mut locations = locations.into_iter().peekable();
14780        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14781        let capability = workspace.project().read(cx).capability();
14782
14783        let excerpt_buffer = cx.new(|cx| {
14784            let mut multibuffer = MultiBuffer::new(capability);
14785            while let Some(location) = locations.next() {
14786                let buffer = location.buffer.read(cx);
14787                let mut ranges_for_buffer = Vec::new();
14788                let range = location.range.to_point(buffer);
14789                ranges_for_buffer.push(range.clone());
14790
14791                while let Some(next_location) = locations.peek() {
14792                    if next_location.buffer == location.buffer {
14793                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14794                        locations.next();
14795                    } else {
14796                        break;
14797                    }
14798                }
14799
14800                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14801                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14802                    PathKey::for_buffer(&location.buffer, cx),
14803                    location.buffer.clone(),
14804                    ranges_for_buffer,
14805                    DEFAULT_MULTIBUFFER_CONTEXT,
14806                    cx,
14807                );
14808                ranges.extend(new_ranges)
14809            }
14810
14811            multibuffer.with_title(title)
14812        });
14813
14814        let editor = cx.new(|cx| {
14815            Editor::for_multibuffer(
14816                excerpt_buffer,
14817                Some(workspace.project().clone()),
14818                window,
14819                cx,
14820            )
14821        });
14822        editor.update(cx, |editor, cx| {
14823            match multibuffer_selection_mode {
14824                MultibufferSelectionMode::First => {
14825                    if let Some(first_range) = ranges.first() {
14826                        editor.change_selections(None, window, cx, |selections| {
14827                            selections.clear_disjoint();
14828                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
14829                        });
14830                    }
14831                    editor.highlight_background::<Self>(
14832                        &ranges,
14833                        |theme| theme.editor_highlighted_line_background,
14834                        cx,
14835                    );
14836                }
14837                MultibufferSelectionMode::All => {
14838                    editor.change_selections(None, window, cx, |selections| {
14839                        selections.clear_disjoint();
14840                        selections.select_anchor_ranges(ranges);
14841                    });
14842                }
14843            }
14844            editor.register_buffers_with_language_servers(cx);
14845        });
14846
14847        let item = Box::new(editor);
14848        let item_id = item.item_id();
14849
14850        if split {
14851            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
14852        } else {
14853            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
14854                let (preview_item_id, preview_item_idx) =
14855                    workspace.active_pane().read_with(cx, |pane, _| {
14856                        (pane.preview_item_id(), pane.preview_item_idx())
14857                    });
14858
14859                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
14860
14861                if let Some(preview_item_id) = preview_item_id {
14862                    workspace.active_pane().update(cx, |pane, cx| {
14863                        pane.remove_item(preview_item_id, false, false, window, cx);
14864                    });
14865                }
14866            } else {
14867                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
14868            }
14869        }
14870        workspace.active_pane().update(cx, |pane, cx| {
14871            pane.set_preview_item_id(Some(item_id), cx);
14872        });
14873    }
14874
14875    pub fn rename(
14876        &mut self,
14877        _: &Rename,
14878        window: &mut Window,
14879        cx: &mut Context<Self>,
14880    ) -> Option<Task<Result<()>>> {
14881        use language::ToOffset as _;
14882
14883        let provider = self.semantics_provider.clone()?;
14884        let selection = self.selections.newest_anchor().clone();
14885        let (cursor_buffer, cursor_buffer_position) = self
14886            .buffer
14887            .read(cx)
14888            .text_anchor_for_position(selection.head(), cx)?;
14889        let (tail_buffer, cursor_buffer_position_end) = self
14890            .buffer
14891            .read(cx)
14892            .text_anchor_for_position(selection.tail(), cx)?;
14893        if tail_buffer != cursor_buffer {
14894            return None;
14895        }
14896
14897        let snapshot = cursor_buffer.read(cx).snapshot();
14898        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
14899        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
14900        let prepare_rename = provider
14901            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
14902            .unwrap_or_else(|| Task::ready(Ok(None)));
14903        drop(snapshot);
14904
14905        Some(cx.spawn_in(window, async move |this, cx| {
14906            let rename_range = if let Some(range) = prepare_rename.await? {
14907                Some(range)
14908            } else {
14909                this.update(cx, |this, cx| {
14910                    let buffer = this.buffer.read(cx).snapshot(cx);
14911                    let mut buffer_highlights = this
14912                        .document_highlights_for_position(selection.head(), &buffer)
14913                        .filter(|highlight| {
14914                            highlight.start.excerpt_id == selection.head().excerpt_id
14915                                && highlight.end.excerpt_id == selection.head().excerpt_id
14916                        });
14917                    buffer_highlights
14918                        .next()
14919                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
14920                })?
14921            };
14922            if let Some(rename_range) = rename_range {
14923                this.update_in(cx, |this, window, cx| {
14924                    let snapshot = cursor_buffer.read(cx).snapshot();
14925                    let rename_buffer_range = rename_range.to_offset(&snapshot);
14926                    let cursor_offset_in_rename_range =
14927                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
14928                    let cursor_offset_in_rename_range_end =
14929                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
14930
14931                    this.take_rename(false, window, cx);
14932                    let buffer = this.buffer.read(cx).read(cx);
14933                    let cursor_offset = selection.head().to_offset(&buffer);
14934                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
14935                    let rename_end = rename_start + rename_buffer_range.len();
14936                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
14937                    let mut old_highlight_id = None;
14938                    let old_name: Arc<str> = buffer
14939                        .chunks(rename_start..rename_end, true)
14940                        .map(|chunk| {
14941                            if old_highlight_id.is_none() {
14942                                old_highlight_id = chunk.syntax_highlight_id;
14943                            }
14944                            chunk.text
14945                        })
14946                        .collect::<String>()
14947                        .into();
14948
14949                    drop(buffer);
14950
14951                    // Position the selection in the rename editor so that it matches the current selection.
14952                    this.show_local_selections = false;
14953                    let rename_editor = cx.new(|cx| {
14954                        let mut editor = Editor::single_line(window, cx);
14955                        editor.buffer.update(cx, |buffer, cx| {
14956                            buffer.edit([(0..0, old_name.clone())], None, cx)
14957                        });
14958                        let rename_selection_range = match cursor_offset_in_rename_range
14959                            .cmp(&cursor_offset_in_rename_range_end)
14960                        {
14961                            Ordering::Equal => {
14962                                editor.select_all(&SelectAll, window, cx);
14963                                return editor;
14964                            }
14965                            Ordering::Less => {
14966                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
14967                            }
14968                            Ordering::Greater => {
14969                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
14970                            }
14971                        };
14972                        if rename_selection_range.end > old_name.len() {
14973                            editor.select_all(&SelectAll, window, cx);
14974                        } else {
14975                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14976                                s.select_ranges([rename_selection_range]);
14977                            });
14978                        }
14979                        editor
14980                    });
14981                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
14982                        if e == &EditorEvent::Focused {
14983                            cx.emit(EditorEvent::FocusedIn)
14984                        }
14985                    })
14986                    .detach();
14987
14988                    let write_highlights =
14989                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
14990                    let read_highlights =
14991                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
14992                    let ranges = write_highlights
14993                        .iter()
14994                        .flat_map(|(_, ranges)| ranges.iter())
14995                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
14996                        .cloned()
14997                        .collect();
14998
14999                    this.highlight_text::<Rename>(
15000                        ranges,
15001                        HighlightStyle {
15002                            fade_out: Some(0.6),
15003                            ..Default::default()
15004                        },
15005                        cx,
15006                    );
15007                    let rename_focus_handle = rename_editor.focus_handle(cx);
15008                    window.focus(&rename_focus_handle);
15009                    let block_id = this.insert_blocks(
15010                        [BlockProperties {
15011                            style: BlockStyle::Flex,
15012                            placement: BlockPlacement::Below(range.start),
15013                            height: Some(1),
15014                            render: Arc::new({
15015                                let rename_editor = rename_editor.clone();
15016                                move |cx: &mut BlockContext| {
15017                                    let mut text_style = cx.editor_style.text.clone();
15018                                    if let Some(highlight_style) = old_highlight_id
15019                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15020                                    {
15021                                        text_style = text_style.highlight(highlight_style);
15022                                    }
15023                                    div()
15024                                        .block_mouse_except_scroll()
15025                                        .pl(cx.anchor_x)
15026                                        .child(EditorElement::new(
15027                                            &rename_editor,
15028                                            EditorStyle {
15029                                                background: cx.theme().system().transparent,
15030                                                local_player: cx.editor_style.local_player,
15031                                                text: text_style,
15032                                                scrollbar_width: cx.editor_style.scrollbar_width,
15033                                                syntax: cx.editor_style.syntax.clone(),
15034                                                status: cx.editor_style.status.clone(),
15035                                                inlay_hints_style: HighlightStyle {
15036                                                    font_weight: Some(FontWeight::BOLD),
15037                                                    ..make_inlay_hints_style(cx.app)
15038                                                },
15039                                                inline_completion_styles: make_suggestion_styles(
15040                                                    cx.app,
15041                                                ),
15042                                                ..EditorStyle::default()
15043                                            },
15044                                        ))
15045                                        .into_any_element()
15046                                }
15047                            }),
15048                            priority: 0,
15049                            render_in_minimap: true,
15050                        }],
15051                        Some(Autoscroll::fit()),
15052                        cx,
15053                    )[0];
15054                    this.pending_rename = Some(RenameState {
15055                        range,
15056                        old_name,
15057                        editor: rename_editor,
15058                        block_id,
15059                    });
15060                })?;
15061            }
15062
15063            Ok(())
15064        }))
15065    }
15066
15067    pub fn confirm_rename(
15068        &mut self,
15069        _: &ConfirmRename,
15070        window: &mut Window,
15071        cx: &mut Context<Self>,
15072    ) -> Option<Task<Result<()>>> {
15073        let rename = self.take_rename(false, window, cx)?;
15074        let workspace = self.workspace()?.downgrade();
15075        let (buffer, start) = self
15076            .buffer
15077            .read(cx)
15078            .text_anchor_for_position(rename.range.start, cx)?;
15079        let (end_buffer, _) = self
15080            .buffer
15081            .read(cx)
15082            .text_anchor_for_position(rename.range.end, cx)?;
15083        if buffer != end_buffer {
15084            return None;
15085        }
15086
15087        let old_name = rename.old_name;
15088        let new_name = rename.editor.read(cx).text(cx);
15089
15090        let rename = self.semantics_provider.as_ref()?.perform_rename(
15091            &buffer,
15092            start,
15093            new_name.clone(),
15094            cx,
15095        )?;
15096
15097        Some(cx.spawn_in(window, async move |editor, cx| {
15098            let project_transaction = rename.await?;
15099            Self::open_project_transaction(
15100                &editor,
15101                workspace,
15102                project_transaction,
15103                format!("Rename: {}{}", old_name, new_name),
15104                cx,
15105            )
15106            .await?;
15107
15108            editor.update(cx, |editor, cx| {
15109                editor.refresh_document_highlights(cx);
15110            })?;
15111            Ok(())
15112        }))
15113    }
15114
15115    fn take_rename(
15116        &mut self,
15117        moving_cursor: bool,
15118        window: &mut Window,
15119        cx: &mut Context<Self>,
15120    ) -> Option<RenameState> {
15121        let rename = self.pending_rename.take()?;
15122        if rename.editor.focus_handle(cx).is_focused(window) {
15123            window.focus(&self.focus_handle);
15124        }
15125
15126        self.remove_blocks(
15127            [rename.block_id].into_iter().collect(),
15128            Some(Autoscroll::fit()),
15129            cx,
15130        );
15131        self.clear_highlights::<Rename>(cx);
15132        self.show_local_selections = true;
15133
15134        if moving_cursor {
15135            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15136                editor.selections.newest::<usize>(cx).head()
15137            });
15138
15139            // Update the selection to match the position of the selection inside
15140            // the rename editor.
15141            let snapshot = self.buffer.read(cx).read(cx);
15142            let rename_range = rename.range.to_offset(&snapshot);
15143            let cursor_in_editor = snapshot
15144                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15145                .min(rename_range.end);
15146            drop(snapshot);
15147
15148            self.change_selections(None, window, cx, |s| {
15149                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15150            });
15151        } else {
15152            self.refresh_document_highlights(cx);
15153        }
15154
15155        Some(rename)
15156    }
15157
15158    pub fn pending_rename(&self) -> Option<&RenameState> {
15159        self.pending_rename.as_ref()
15160    }
15161
15162    fn format(
15163        &mut self,
15164        _: &Format,
15165        window: &mut Window,
15166        cx: &mut Context<Self>,
15167    ) -> Option<Task<Result<()>>> {
15168        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15169
15170        let project = match &self.project {
15171            Some(project) => project.clone(),
15172            None => return None,
15173        };
15174
15175        Some(self.perform_format(
15176            project,
15177            FormatTrigger::Manual,
15178            FormatTarget::Buffers,
15179            window,
15180            cx,
15181        ))
15182    }
15183
15184    fn format_selections(
15185        &mut self,
15186        _: &FormatSelections,
15187        window: &mut Window,
15188        cx: &mut Context<Self>,
15189    ) -> Option<Task<Result<()>>> {
15190        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15191
15192        let project = match &self.project {
15193            Some(project) => project.clone(),
15194            None => return None,
15195        };
15196
15197        let ranges = self
15198            .selections
15199            .all_adjusted(cx)
15200            .into_iter()
15201            .map(|selection| selection.range())
15202            .collect_vec();
15203
15204        Some(self.perform_format(
15205            project,
15206            FormatTrigger::Manual,
15207            FormatTarget::Ranges(ranges),
15208            window,
15209            cx,
15210        ))
15211    }
15212
15213    fn perform_format(
15214        &mut self,
15215        project: Entity<Project>,
15216        trigger: FormatTrigger,
15217        target: FormatTarget,
15218        window: &mut Window,
15219        cx: &mut Context<Self>,
15220    ) -> Task<Result<()>> {
15221        let buffer = self.buffer.clone();
15222        let (buffers, target) = match target {
15223            FormatTarget::Buffers => {
15224                let mut buffers = buffer.read(cx).all_buffers();
15225                if trigger == FormatTrigger::Save {
15226                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15227                }
15228                (buffers, LspFormatTarget::Buffers)
15229            }
15230            FormatTarget::Ranges(selection_ranges) => {
15231                let multi_buffer = buffer.read(cx);
15232                let snapshot = multi_buffer.read(cx);
15233                let mut buffers = HashSet::default();
15234                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15235                    BTreeMap::new();
15236                for selection_range in selection_ranges {
15237                    for (buffer, buffer_range, _) in
15238                        snapshot.range_to_buffer_ranges(selection_range)
15239                    {
15240                        let buffer_id = buffer.remote_id();
15241                        let start = buffer.anchor_before(buffer_range.start);
15242                        let end = buffer.anchor_after(buffer_range.end);
15243                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15244                        buffer_id_to_ranges
15245                            .entry(buffer_id)
15246                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15247                            .or_insert_with(|| vec![start..end]);
15248                    }
15249                }
15250                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15251            }
15252        };
15253
15254        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15255        let selections_prev = transaction_id_prev
15256            .and_then(|transaction_id_prev| {
15257                // default to selections as they were after the last edit, if we have them,
15258                // instead of how they are now.
15259                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15260                // will take you back to where you made the last edit, instead of staying where you scrolled
15261                self.selection_history
15262                    .transaction(transaction_id_prev)
15263                    .map(|t| t.0.clone())
15264            })
15265            .unwrap_or_else(|| {
15266                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15267                self.selections.disjoint_anchors()
15268            });
15269
15270        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15271        let format = project.update(cx, |project, cx| {
15272            project.format(buffers, target, true, trigger, cx)
15273        });
15274
15275        cx.spawn_in(window, async move |editor, cx| {
15276            let transaction = futures::select_biased! {
15277                transaction = format.log_err().fuse() => transaction,
15278                () = timeout => {
15279                    log::warn!("timed out waiting for formatting");
15280                    None
15281                }
15282            };
15283
15284            buffer
15285                .update(cx, |buffer, cx| {
15286                    if let Some(transaction) = transaction {
15287                        if !buffer.is_singleton() {
15288                            buffer.push_transaction(&transaction.0, cx);
15289                        }
15290                    }
15291                    cx.notify();
15292                })
15293                .ok();
15294
15295            if let Some(transaction_id_now) =
15296                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15297            {
15298                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15299                if has_new_transaction {
15300                    _ = editor.update(cx, |editor, _| {
15301                        editor
15302                            .selection_history
15303                            .insert_transaction(transaction_id_now, selections_prev);
15304                    });
15305                }
15306            }
15307
15308            Ok(())
15309        })
15310    }
15311
15312    fn organize_imports(
15313        &mut self,
15314        _: &OrganizeImports,
15315        window: &mut Window,
15316        cx: &mut Context<Self>,
15317    ) -> Option<Task<Result<()>>> {
15318        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15319        let project = match &self.project {
15320            Some(project) => project.clone(),
15321            None => return None,
15322        };
15323        Some(self.perform_code_action_kind(
15324            project,
15325            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15326            window,
15327            cx,
15328        ))
15329    }
15330
15331    fn perform_code_action_kind(
15332        &mut self,
15333        project: Entity<Project>,
15334        kind: CodeActionKind,
15335        window: &mut Window,
15336        cx: &mut Context<Self>,
15337    ) -> Task<Result<()>> {
15338        let buffer = self.buffer.clone();
15339        let buffers = buffer.read(cx).all_buffers();
15340        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15341        let apply_action = project.update(cx, |project, cx| {
15342            project.apply_code_action_kind(buffers, kind, true, cx)
15343        });
15344        cx.spawn_in(window, async move |_, cx| {
15345            let transaction = futures::select_biased! {
15346                () = timeout => {
15347                    log::warn!("timed out waiting for executing code action");
15348                    None
15349                }
15350                transaction = apply_action.log_err().fuse() => transaction,
15351            };
15352            buffer
15353                .update(cx, |buffer, cx| {
15354                    // check if we need this
15355                    if let Some(transaction) = transaction {
15356                        if !buffer.is_singleton() {
15357                            buffer.push_transaction(&transaction.0, cx);
15358                        }
15359                    }
15360                    cx.notify();
15361                })
15362                .ok();
15363            Ok(())
15364        })
15365    }
15366
15367    fn restart_language_server(
15368        &mut self,
15369        _: &RestartLanguageServer,
15370        _: &mut Window,
15371        cx: &mut Context<Self>,
15372    ) {
15373        if let Some(project) = self.project.clone() {
15374            self.buffer.update(cx, |multi_buffer, cx| {
15375                project.update(cx, |project, cx| {
15376                    project.restart_language_servers_for_buffers(
15377                        multi_buffer.all_buffers().into_iter().collect(),
15378                        cx,
15379                    );
15380                });
15381            })
15382        }
15383    }
15384
15385    fn stop_language_server(
15386        &mut self,
15387        _: &StopLanguageServer,
15388        _: &mut Window,
15389        cx: &mut Context<Self>,
15390    ) {
15391        if let Some(project) = self.project.clone() {
15392            self.buffer.update(cx, |multi_buffer, cx| {
15393                project.update(cx, |project, cx| {
15394                    project.stop_language_servers_for_buffers(
15395                        multi_buffer.all_buffers().into_iter().collect(),
15396                        cx,
15397                    );
15398                    cx.emit(project::Event::RefreshInlayHints);
15399                });
15400            });
15401        }
15402    }
15403
15404    fn cancel_language_server_work(
15405        workspace: &mut Workspace,
15406        _: &actions::CancelLanguageServerWork,
15407        _: &mut Window,
15408        cx: &mut Context<Workspace>,
15409    ) {
15410        let project = workspace.project();
15411        let buffers = workspace
15412            .active_item(cx)
15413            .and_then(|item| item.act_as::<Editor>(cx))
15414            .map_or(HashSet::default(), |editor| {
15415                editor.read(cx).buffer.read(cx).all_buffers()
15416            });
15417        project.update(cx, |project, cx| {
15418            project.cancel_language_server_work_for_buffers(buffers, cx);
15419        });
15420    }
15421
15422    fn show_character_palette(
15423        &mut self,
15424        _: &ShowCharacterPalette,
15425        window: &mut Window,
15426        _: &mut Context<Self>,
15427    ) {
15428        window.show_character_palette();
15429    }
15430
15431    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15432        if self.mode.is_minimap() {
15433            return;
15434        }
15435
15436        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15437            let buffer = self.buffer.read(cx).snapshot(cx);
15438            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15439            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15440            let is_valid = buffer
15441                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15442                .any(|entry| {
15443                    entry.diagnostic.is_primary
15444                        && !entry.range.is_empty()
15445                        && entry.range.start == primary_range_start
15446                        && entry.diagnostic.message == active_diagnostics.active_message
15447                });
15448
15449            if !is_valid {
15450                self.dismiss_diagnostics(cx);
15451            }
15452        }
15453    }
15454
15455    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15456        match &self.active_diagnostics {
15457            ActiveDiagnostic::Group(group) => Some(group),
15458            _ => None,
15459        }
15460    }
15461
15462    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15463        self.dismiss_diagnostics(cx);
15464        self.active_diagnostics = ActiveDiagnostic::All;
15465    }
15466
15467    fn activate_diagnostics(
15468        &mut self,
15469        buffer_id: BufferId,
15470        diagnostic: DiagnosticEntry<usize>,
15471        window: &mut Window,
15472        cx: &mut Context<Self>,
15473    ) {
15474        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15475            return;
15476        }
15477        self.dismiss_diagnostics(cx);
15478        let snapshot = self.snapshot(window, cx);
15479        let buffer = self.buffer.read(cx).snapshot(cx);
15480        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15481            return;
15482        };
15483
15484        let diagnostic_group = buffer
15485            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15486            .collect::<Vec<_>>();
15487
15488        let blocks =
15489            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15490
15491        let blocks = self.display_map.update(cx, |display_map, cx| {
15492            display_map.insert_blocks(blocks, cx).into_iter().collect()
15493        });
15494        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15495            active_range: buffer.anchor_before(diagnostic.range.start)
15496                ..buffer.anchor_after(diagnostic.range.end),
15497            active_message: diagnostic.diagnostic.message.clone(),
15498            group_id: diagnostic.diagnostic.group_id,
15499            blocks,
15500        });
15501        cx.notify();
15502    }
15503
15504    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15505        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15506            return;
15507        };
15508
15509        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15510        if let ActiveDiagnostic::Group(group) = prev {
15511            self.display_map.update(cx, |display_map, cx| {
15512                display_map.remove_blocks(group.blocks, cx);
15513            });
15514            cx.notify();
15515        }
15516    }
15517
15518    /// Disable inline diagnostics rendering for this editor.
15519    pub fn disable_inline_diagnostics(&mut self) {
15520        self.inline_diagnostics_enabled = false;
15521        self.inline_diagnostics_update = Task::ready(());
15522        self.inline_diagnostics.clear();
15523    }
15524
15525    pub fn diagnostics_enabled(&self) -> bool {
15526        self.mode.is_full()
15527    }
15528
15529    pub fn inline_diagnostics_enabled(&self) -> bool {
15530        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15531    }
15532
15533    pub fn show_inline_diagnostics(&self) -> bool {
15534        self.show_inline_diagnostics
15535    }
15536
15537    pub fn toggle_inline_diagnostics(
15538        &mut self,
15539        _: &ToggleInlineDiagnostics,
15540        window: &mut Window,
15541        cx: &mut Context<Editor>,
15542    ) {
15543        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15544        self.refresh_inline_diagnostics(false, window, cx);
15545    }
15546
15547    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15548        self.diagnostics_max_severity = severity;
15549        self.display_map.update(cx, |display_map, _| {
15550            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15551        });
15552    }
15553
15554    pub fn toggle_diagnostics(
15555        &mut self,
15556        _: &ToggleDiagnostics,
15557        window: &mut Window,
15558        cx: &mut Context<Editor>,
15559    ) {
15560        if !self.diagnostics_enabled() {
15561            return;
15562        }
15563
15564        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15565            EditorSettings::get_global(cx)
15566                .diagnostics_max_severity
15567                .filter(|severity| severity != &DiagnosticSeverity::Off)
15568                .unwrap_or(DiagnosticSeverity::Hint)
15569        } else {
15570            DiagnosticSeverity::Off
15571        };
15572        self.set_max_diagnostics_severity(new_severity, cx);
15573        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15574            self.active_diagnostics = ActiveDiagnostic::None;
15575            self.inline_diagnostics_update = Task::ready(());
15576            self.inline_diagnostics.clear();
15577        } else {
15578            self.refresh_inline_diagnostics(false, window, cx);
15579        }
15580
15581        cx.notify();
15582    }
15583
15584    pub fn toggle_minimap(
15585        &mut self,
15586        _: &ToggleMinimap,
15587        window: &mut Window,
15588        cx: &mut Context<Editor>,
15589    ) {
15590        if self.supports_minimap(cx) {
15591            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15592        }
15593    }
15594
15595    fn refresh_inline_diagnostics(
15596        &mut self,
15597        debounce: bool,
15598        window: &mut Window,
15599        cx: &mut Context<Self>,
15600    ) {
15601        let max_severity = ProjectSettings::get_global(cx)
15602            .diagnostics
15603            .inline
15604            .max_severity
15605            .unwrap_or(self.diagnostics_max_severity);
15606
15607        if !self.inline_diagnostics_enabled()
15608            || !self.show_inline_diagnostics
15609            || max_severity == DiagnosticSeverity::Off
15610        {
15611            self.inline_diagnostics_update = Task::ready(());
15612            self.inline_diagnostics.clear();
15613            return;
15614        }
15615
15616        let debounce_ms = ProjectSettings::get_global(cx)
15617            .diagnostics
15618            .inline
15619            .update_debounce_ms;
15620        let debounce = if debounce && debounce_ms > 0 {
15621            Some(Duration::from_millis(debounce_ms))
15622        } else {
15623            None
15624        };
15625        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15626            let editor = editor.upgrade().unwrap();
15627
15628            if let Some(debounce) = debounce {
15629                cx.background_executor().timer(debounce).await;
15630            }
15631            let Some(snapshot) = editor
15632                .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15633                .ok()
15634            else {
15635                return;
15636            };
15637
15638            let new_inline_diagnostics = cx
15639                .background_spawn(async move {
15640                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15641                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15642                        let message = diagnostic_entry
15643                            .diagnostic
15644                            .message
15645                            .split_once('\n')
15646                            .map(|(line, _)| line)
15647                            .map(SharedString::new)
15648                            .unwrap_or_else(|| {
15649                                SharedString::from(diagnostic_entry.diagnostic.message)
15650                            });
15651                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15652                        let (Ok(i) | Err(i)) = inline_diagnostics
15653                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15654                        inline_diagnostics.insert(
15655                            i,
15656                            (
15657                                start_anchor,
15658                                InlineDiagnostic {
15659                                    message,
15660                                    group_id: diagnostic_entry.diagnostic.group_id,
15661                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15662                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15663                                    severity: diagnostic_entry.diagnostic.severity,
15664                                },
15665                            ),
15666                        );
15667                    }
15668                    inline_diagnostics
15669                })
15670                .await;
15671
15672            editor
15673                .update(cx, |editor, cx| {
15674                    editor.inline_diagnostics = new_inline_diagnostics;
15675                    cx.notify();
15676                })
15677                .ok();
15678        });
15679    }
15680
15681    pub fn set_selections_from_remote(
15682        &mut self,
15683        selections: Vec<Selection<Anchor>>,
15684        pending_selection: Option<Selection<Anchor>>,
15685        window: &mut Window,
15686        cx: &mut Context<Self>,
15687    ) {
15688        let old_cursor_position = self.selections.newest_anchor().head();
15689        self.selections.change_with(cx, |s| {
15690            s.select_anchors(selections);
15691            if let Some(pending_selection) = pending_selection {
15692                s.set_pending(pending_selection, SelectMode::Character);
15693            } else {
15694                s.clear_pending();
15695            }
15696        });
15697        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15698    }
15699
15700    fn push_to_selection_history(&mut self) {
15701        self.selection_history.push(SelectionHistoryEntry {
15702            selections: self.selections.disjoint_anchors(),
15703            select_next_state: self.select_next_state.clone(),
15704            select_prev_state: self.select_prev_state.clone(),
15705            add_selections_state: self.add_selections_state.clone(),
15706        });
15707    }
15708
15709    pub fn transact(
15710        &mut self,
15711        window: &mut Window,
15712        cx: &mut Context<Self>,
15713        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15714    ) -> Option<TransactionId> {
15715        self.start_transaction_at(Instant::now(), window, cx);
15716        update(self, window, cx);
15717        self.end_transaction_at(Instant::now(), cx)
15718    }
15719
15720    pub fn start_transaction_at(
15721        &mut self,
15722        now: Instant,
15723        window: &mut Window,
15724        cx: &mut Context<Self>,
15725    ) {
15726        self.end_selection(window, cx);
15727        if let Some(tx_id) = self
15728            .buffer
15729            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15730        {
15731            self.selection_history
15732                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15733            cx.emit(EditorEvent::TransactionBegun {
15734                transaction_id: tx_id,
15735            })
15736        }
15737    }
15738
15739    pub fn end_transaction_at(
15740        &mut self,
15741        now: Instant,
15742        cx: &mut Context<Self>,
15743    ) -> Option<TransactionId> {
15744        if let Some(transaction_id) = self
15745            .buffer
15746            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15747        {
15748            if let Some((_, end_selections)) =
15749                self.selection_history.transaction_mut(transaction_id)
15750            {
15751                *end_selections = Some(self.selections.disjoint_anchors());
15752            } else {
15753                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15754            }
15755
15756            cx.emit(EditorEvent::Edited { transaction_id });
15757            Some(transaction_id)
15758        } else {
15759            None
15760        }
15761    }
15762
15763    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15764        if self.selection_mark_mode {
15765            self.change_selections(None, window, cx, |s| {
15766                s.move_with(|_, sel| {
15767                    sel.collapse_to(sel.head(), SelectionGoal::None);
15768                });
15769            })
15770        }
15771        self.selection_mark_mode = true;
15772        cx.notify();
15773    }
15774
15775    pub fn swap_selection_ends(
15776        &mut self,
15777        _: &actions::SwapSelectionEnds,
15778        window: &mut Window,
15779        cx: &mut Context<Self>,
15780    ) {
15781        self.change_selections(None, window, cx, |s| {
15782            s.move_with(|_, sel| {
15783                if sel.start != sel.end {
15784                    sel.reversed = !sel.reversed
15785                }
15786            });
15787        });
15788        self.request_autoscroll(Autoscroll::newest(), cx);
15789        cx.notify();
15790    }
15791
15792    pub fn toggle_fold(
15793        &mut self,
15794        _: &actions::ToggleFold,
15795        window: &mut Window,
15796        cx: &mut Context<Self>,
15797    ) {
15798        if self.is_singleton(cx) {
15799            let selection = self.selections.newest::<Point>(cx);
15800
15801            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15802            let range = if selection.is_empty() {
15803                let point = selection.head().to_display_point(&display_map);
15804                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15805                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15806                    .to_point(&display_map);
15807                start..end
15808            } else {
15809                selection.range()
15810            };
15811            if display_map.folds_in_range(range).next().is_some() {
15812                self.unfold_lines(&Default::default(), window, cx)
15813            } else {
15814                self.fold(&Default::default(), window, cx)
15815            }
15816        } else {
15817            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15818            let buffer_ids: HashSet<_> = self
15819                .selections
15820                .disjoint_anchor_ranges()
15821                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15822                .collect();
15823
15824            let should_unfold = buffer_ids
15825                .iter()
15826                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15827
15828            for buffer_id in buffer_ids {
15829                if should_unfold {
15830                    self.unfold_buffer(buffer_id, cx);
15831                } else {
15832                    self.fold_buffer(buffer_id, cx);
15833                }
15834            }
15835        }
15836    }
15837
15838    pub fn toggle_fold_recursive(
15839        &mut self,
15840        _: &actions::ToggleFoldRecursive,
15841        window: &mut Window,
15842        cx: &mut Context<Self>,
15843    ) {
15844        let selection = self.selections.newest::<Point>(cx);
15845
15846        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15847        let range = if selection.is_empty() {
15848            let point = selection.head().to_display_point(&display_map);
15849            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15850            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15851                .to_point(&display_map);
15852            start..end
15853        } else {
15854            selection.range()
15855        };
15856        if display_map.folds_in_range(range).next().is_some() {
15857            self.unfold_recursive(&Default::default(), window, cx)
15858        } else {
15859            self.fold_recursive(&Default::default(), window, cx)
15860        }
15861    }
15862
15863    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
15864        if self.is_singleton(cx) {
15865            let mut to_fold = Vec::new();
15866            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15867            let selections = self.selections.all_adjusted(cx);
15868
15869            for selection in selections {
15870                let range = selection.range().sorted();
15871                let buffer_start_row = range.start.row;
15872
15873                if range.start.row != range.end.row {
15874                    let mut found = false;
15875                    let mut row = range.start.row;
15876                    while row <= range.end.row {
15877                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
15878                        {
15879                            found = true;
15880                            row = crease.range().end.row + 1;
15881                            to_fold.push(crease);
15882                        } else {
15883                            row += 1
15884                        }
15885                    }
15886                    if found {
15887                        continue;
15888                    }
15889                }
15890
15891                for row in (0..=range.start.row).rev() {
15892                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
15893                        if crease.range().end.row >= buffer_start_row {
15894                            to_fold.push(crease);
15895                            if row <= range.start.row {
15896                                break;
15897                            }
15898                        }
15899                    }
15900                }
15901            }
15902
15903            self.fold_creases(to_fold, true, window, cx);
15904        } else {
15905            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15906            let buffer_ids = self
15907                .selections
15908                .disjoint_anchor_ranges()
15909                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15910                .collect::<HashSet<_>>();
15911            for buffer_id in buffer_ids {
15912                self.fold_buffer(buffer_id, cx);
15913            }
15914        }
15915    }
15916
15917    fn fold_at_level(
15918        &mut self,
15919        fold_at: &FoldAtLevel,
15920        window: &mut Window,
15921        cx: &mut Context<Self>,
15922    ) {
15923        if !self.buffer.read(cx).is_singleton() {
15924            return;
15925        }
15926
15927        let fold_at_level = fold_at.0;
15928        let snapshot = self.buffer.read(cx).snapshot(cx);
15929        let mut to_fold = Vec::new();
15930        let mut stack = vec![(0, snapshot.max_row().0, 1)];
15931
15932        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
15933            while start_row < end_row {
15934                match self
15935                    .snapshot(window, cx)
15936                    .crease_for_buffer_row(MultiBufferRow(start_row))
15937                {
15938                    Some(crease) => {
15939                        let nested_start_row = crease.range().start.row + 1;
15940                        let nested_end_row = crease.range().end.row;
15941
15942                        if current_level < fold_at_level {
15943                            stack.push((nested_start_row, nested_end_row, current_level + 1));
15944                        } else if current_level == fold_at_level {
15945                            to_fold.push(crease);
15946                        }
15947
15948                        start_row = nested_end_row + 1;
15949                    }
15950                    None => start_row += 1,
15951                }
15952            }
15953        }
15954
15955        self.fold_creases(to_fold, true, window, cx);
15956    }
15957
15958    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
15959        if self.buffer.read(cx).is_singleton() {
15960            let mut fold_ranges = Vec::new();
15961            let snapshot = self.buffer.read(cx).snapshot(cx);
15962
15963            for row in 0..snapshot.max_row().0 {
15964                if let Some(foldable_range) = self
15965                    .snapshot(window, cx)
15966                    .crease_for_buffer_row(MultiBufferRow(row))
15967                {
15968                    fold_ranges.push(foldable_range);
15969                }
15970            }
15971
15972            self.fold_creases(fold_ranges, true, window, cx);
15973        } else {
15974            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
15975                editor
15976                    .update_in(cx, |editor, _, cx| {
15977                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
15978                            editor.fold_buffer(buffer_id, cx);
15979                        }
15980                    })
15981                    .ok();
15982            });
15983        }
15984    }
15985
15986    pub fn fold_function_bodies(
15987        &mut self,
15988        _: &actions::FoldFunctionBodies,
15989        window: &mut Window,
15990        cx: &mut Context<Self>,
15991    ) {
15992        let snapshot = self.buffer.read(cx).snapshot(cx);
15993
15994        let ranges = snapshot
15995            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
15996            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
15997            .collect::<Vec<_>>();
15998
15999        let creases = ranges
16000            .into_iter()
16001            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16002            .collect();
16003
16004        self.fold_creases(creases, true, window, cx);
16005    }
16006
16007    pub fn fold_recursive(
16008        &mut self,
16009        _: &actions::FoldRecursive,
16010        window: &mut Window,
16011        cx: &mut Context<Self>,
16012    ) {
16013        let mut to_fold = Vec::new();
16014        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16015        let selections = self.selections.all_adjusted(cx);
16016
16017        for selection in selections {
16018            let range = selection.range().sorted();
16019            let buffer_start_row = range.start.row;
16020
16021            if range.start.row != range.end.row {
16022                let mut found = false;
16023                for row in range.start.row..=range.end.row {
16024                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16025                        found = true;
16026                        to_fold.push(crease);
16027                    }
16028                }
16029                if found {
16030                    continue;
16031                }
16032            }
16033
16034            for row in (0..=range.start.row).rev() {
16035                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16036                    if crease.range().end.row >= buffer_start_row {
16037                        to_fold.push(crease);
16038                    } else {
16039                        break;
16040                    }
16041                }
16042            }
16043        }
16044
16045        self.fold_creases(to_fold, true, window, cx);
16046    }
16047
16048    pub fn fold_at(
16049        &mut self,
16050        buffer_row: MultiBufferRow,
16051        window: &mut Window,
16052        cx: &mut Context<Self>,
16053    ) {
16054        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16055
16056        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16057            let autoscroll = self
16058                .selections
16059                .all::<Point>(cx)
16060                .iter()
16061                .any(|selection| crease.range().overlaps(&selection.range()));
16062
16063            self.fold_creases(vec![crease], autoscroll, window, cx);
16064        }
16065    }
16066
16067    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16068        if self.is_singleton(cx) {
16069            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16070            let buffer = &display_map.buffer_snapshot;
16071            let selections = self.selections.all::<Point>(cx);
16072            let ranges = selections
16073                .iter()
16074                .map(|s| {
16075                    let range = s.display_range(&display_map).sorted();
16076                    let mut start = range.start.to_point(&display_map);
16077                    let mut end = range.end.to_point(&display_map);
16078                    start.column = 0;
16079                    end.column = buffer.line_len(MultiBufferRow(end.row));
16080                    start..end
16081                })
16082                .collect::<Vec<_>>();
16083
16084            self.unfold_ranges(&ranges, true, true, cx);
16085        } else {
16086            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16087            let buffer_ids = self
16088                .selections
16089                .disjoint_anchor_ranges()
16090                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16091                .collect::<HashSet<_>>();
16092            for buffer_id in buffer_ids {
16093                self.unfold_buffer(buffer_id, cx);
16094            }
16095        }
16096    }
16097
16098    pub fn unfold_recursive(
16099        &mut self,
16100        _: &UnfoldRecursive,
16101        _window: &mut Window,
16102        cx: &mut Context<Self>,
16103    ) {
16104        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16105        let selections = self.selections.all::<Point>(cx);
16106        let ranges = selections
16107            .iter()
16108            .map(|s| {
16109                let mut range = s.display_range(&display_map).sorted();
16110                *range.start.column_mut() = 0;
16111                *range.end.column_mut() = display_map.line_len(range.end.row());
16112                let start = range.start.to_point(&display_map);
16113                let end = range.end.to_point(&display_map);
16114                start..end
16115            })
16116            .collect::<Vec<_>>();
16117
16118        self.unfold_ranges(&ranges, true, true, cx);
16119    }
16120
16121    pub fn unfold_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        let intersection_range = Point::new(buffer_row.0, 0)
16130            ..Point::new(
16131                buffer_row.0,
16132                display_map.buffer_snapshot.line_len(buffer_row),
16133            );
16134
16135        let autoscroll = self
16136            .selections
16137            .all::<Point>(cx)
16138            .iter()
16139            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16140
16141        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16142    }
16143
16144    pub fn unfold_all(
16145        &mut self,
16146        _: &actions::UnfoldAll,
16147        _window: &mut Window,
16148        cx: &mut Context<Self>,
16149    ) {
16150        if self.buffer.read(cx).is_singleton() {
16151            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16152            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16153        } else {
16154            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16155                editor
16156                    .update(cx, |editor, cx| {
16157                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16158                            editor.unfold_buffer(buffer_id, cx);
16159                        }
16160                    })
16161                    .ok();
16162            });
16163        }
16164    }
16165
16166    pub fn fold_selected_ranges(
16167        &mut self,
16168        _: &FoldSelectedRanges,
16169        window: &mut Window,
16170        cx: &mut Context<Self>,
16171    ) {
16172        let selections = self.selections.all_adjusted(cx);
16173        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16174        let ranges = selections
16175            .into_iter()
16176            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16177            .collect::<Vec<_>>();
16178        self.fold_creases(ranges, true, window, cx);
16179    }
16180
16181    pub fn fold_ranges<T: ToOffset + Clone>(
16182        &mut self,
16183        ranges: Vec<Range<T>>,
16184        auto_scroll: bool,
16185        window: &mut Window,
16186        cx: &mut Context<Self>,
16187    ) {
16188        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16189        let ranges = ranges
16190            .into_iter()
16191            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16192            .collect::<Vec<_>>();
16193        self.fold_creases(ranges, auto_scroll, window, cx);
16194    }
16195
16196    pub fn fold_creases<T: ToOffset + Clone>(
16197        &mut self,
16198        creases: Vec<Crease<T>>,
16199        auto_scroll: bool,
16200        _window: &mut Window,
16201        cx: &mut Context<Self>,
16202    ) {
16203        if creases.is_empty() {
16204            return;
16205        }
16206
16207        let mut buffers_affected = HashSet::default();
16208        let multi_buffer = self.buffer().read(cx);
16209        for crease in &creases {
16210            if let Some((_, buffer, _)) =
16211                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16212            {
16213                buffers_affected.insert(buffer.read(cx).remote_id());
16214            };
16215        }
16216
16217        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16218
16219        if auto_scroll {
16220            self.request_autoscroll(Autoscroll::fit(), cx);
16221        }
16222
16223        cx.notify();
16224
16225        self.scrollbar_marker_state.dirty = true;
16226        self.folds_did_change(cx);
16227    }
16228
16229    /// Removes any folds whose ranges intersect any of the given ranges.
16230    pub fn unfold_ranges<T: ToOffset + Clone>(
16231        &mut self,
16232        ranges: &[Range<T>],
16233        inclusive: bool,
16234        auto_scroll: bool,
16235        cx: &mut Context<Self>,
16236    ) {
16237        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16238            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16239        });
16240        self.folds_did_change(cx);
16241    }
16242
16243    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16244        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16245            return;
16246        }
16247        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16248        self.display_map.update(cx, |display_map, cx| {
16249            display_map.fold_buffers([buffer_id], cx)
16250        });
16251        cx.emit(EditorEvent::BufferFoldToggled {
16252            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16253            folded: true,
16254        });
16255        cx.notify();
16256    }
16257
16258    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16259        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16260            return;
16261        }
16262        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16263        self.display_map.update(cx, |display_map, cx| {
16264            display_map.unfold_buffers([buffer_id], cx);
16265        });
16266        cx.emit(EditorEvent::BufferFoldToggled {
16267            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16268            folded: false,
16269        });
16270        cx.notify();
16271    }
16272
16273    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16274        self.display_map.read(cx).is_buffer_folded(buffer)
16275    }
16276
16277    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16278        self.display_map.read(cx).folded_buffers()
16279    }
16280
16281    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16282        self.display_map.update(cx, |display_map, cx| {
16283            display_map.disable_header_for_buffer(buffer_id, cx);
16284        });
16285        cx.notify();
16286    }
16287
16288    /// Removes any folds with the given ranges.
16289    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16290        &mut self,
16291        ranges: &[Range<T>],
16292        type_id: TypeId,
16293        auto_scroll: bool,
16294        cx: &mut Context<Self>,
16295    ) {
16296        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16297            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16298        });
16299        self.folds_did_change(cx);
16300    }
16301
16302    fn remove_folds_with<T: ToOffset + Clone>(
16303        &mut self,
16304        ranges: &[Range<T>],
16305        auto_scroll: bool,
16306        cx: &mut Context<Self>,
16307        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16308    ) {
16309        if ranges.is_empty() {
16310            return;
16311        }
16312
16313        let mut buffers_affected = HashSet::default();
16314        let multi_buffer = self.buffer().read(cx);
16315        for range in ranges {
16316            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16317                buffers_affected.insert(buffer.read(cx).remote_id());
16318            };
16319        }
16320
16321        self.display_map.update(cx, update);
16322
16323        if auto_scroll {
16324            self.request_autoscroll(Autoscroll::fit(), cx);
16325        }
16326
16327        cx.notify();
16328        self.scrollbar_marker_state.dirty = true;
16329        self.active_indent_guides_state.dirty = true;
16330    }
16331
16332    pub fn update_fold_widths(
16333        &mut self,
16334        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16335        cx: &mut Context<Self>,
16336    ) -> bool {
16337        self.display_map
16338            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16339    }
16340
16341    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16342        self.display_map.read(cx).fold_placeholder.clone()
16343    }
16344
16345    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16346        self.buffer.update(cx, |buffer, cx| {
16347            buffer.set_all_diff_hunks_expanded(cx);
16348        });
16349    }
16350
16351    pub fn expand_all_diff_hunks(
16352        &mut self,
16353        _: &ExpandAllDiffHunks,
16354        _window: &mut Window,
16355        cx: &mut Context<Self>,
16356    ) {
16357        self.buffer.update(cx, |buffer, cx| {
16358            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16359        });
16360    }
16361
16362    pub fn toggle_selected_diff_hunks(
16363        &mut self,
16364        _: &ToggleSelectedDiffHunks,
16365        _window: &mut Window,
16366        cx: &mut Context<Self>,
16367    ) {
16368        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16369        self.toggle_diff_hunks_in_ranges(ranges, cx);
16370    }
16371
16372    pub fn diff_hunks_in_ranges<'a>(
16373        &'a self,
16374        ranges: &'a [Range<Anchor>],
16375        buffer: &'a MultiBufferSnapshot,
16376    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16377        ranges.iter().flat_map(move |range| {
16378            let end_excerpt_id = range.end.excerpt_id;
16379            let range = range.to_point(buffer);
16380            let mut peek_end = range.end;
16381            if range.end.row < buffer.max_row().0 {
16382                peek_end = Point::new(range.end.row + 1, 0);
16383            }
16384            buffer
16385                .diff_hunks_in_range(range.start..peek_end)
16386                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16387        })
16388    }
16389
16390    pub fn has_stageable_diff_hunks_in_ranges(
16391        &self,
16392        ranges: &[Range<Anchor>],
16393        snapshot: &MultiBufferSnapshot,
16394    ) -> bool {
16395        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16396        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16397    }
16398
16399    pub fn toggle_staged_selected_diff_hunks(
16400        &mut self,
16401        _: &::git::ToggleStaged,
16402        _: &mut Window,
16403        cx: &mut Context<Self>,
16404    ) {
16405        let snapshot = self.buffer.read(cx).snapshot(cx);
16406        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16407        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16408        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16409    }
16410
16411    pub fn set_render_diff_hunk_controls(
16412        &mut self,
16413        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16414        cx: &mut Context<Self>,
16415    ) {
16416        self.render_diff_hunk_controls = render_diff_hunk_controls;
16417        cx.notify();
16418    }
16419
16420    pub fn stage_and_next(
16421        &mut self,
16422        _: &::git::StageAndNext,
16423        window: &mut Window,
16424        cx: &mut Context<Self>,
16425    ) {
16426        self.do_stage_or_unstage_and_next(true, window, cx);
16427    }
16428
16429    pub fn unstage_and_next(
16430        &mut self,
16431        _: &::git::UnstageAndNext,
16432        window: &mut Window,
16433        cx: &mut Context<Self>,
16434    ) {
16435        self.do_stage_or_unstage_and_next(false, window, cx);
16436    }
16437
16438    pub fn stage_or_unstage_diff_hunks(
16439        &mut self,
16440        stage: bool,
16441        ranges: Vec<Range<Anchor>>,
16442        cx: &mut Context<Self>,
16443    ) {
16444        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16445        cx.spawn(async move |this, cx| {
16446            task.await?;
16447            this.update(cx, |this, cx| {
16448                let snapshot = this.buffer.read(cx).snapshot(cx);
16449                let chunk_by = this
16450                    .diff_hunks_in_ranges(&ranges, &snapshot)
16451                    .chunk_by(|hunk| hunk.buffer_id);
16452                for (buffer_id, hunks) in &chunk_by {
16453                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16454                }
16455            })
16456        })
16457        .detach_and_log_err(cx);
16458    }
16459
16460    fn save_buffers_for_ranges_if_needed(
16461        &mut self,
16462        ranges: &[Range<Anchor>],
16463        cx: &mut Context<Editor>,
16464    ) -> Task<Result<()>> {
16465        let multibuffer = self.buffer.read(cx);
16466        let snapshot = multibuffer.read(cx);
16467        let buffer_ids: HashSet<_> = ranges
16468            .iter()
16469            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16470            .collect();
16471        drop(snapshot);
16472
16473        let mut buffers = HashSet::default();
16474        for buffer_id in buffer_ids {
16475            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16476                let buffer = buffer_entity.read(cx);
16477                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16478                {
16479                    buffers.insert(buffer_entity);
16480                }
16481            }
16482        }
16483
16484        if let Some(project) = &self.project {
16485            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16486        } else {
16487            Task::ready(Ok(()))
16488        }
16489    }
16490
16491    fn do_stage_or_unstage_and_next(
16492        &mut self,
16493        stage: bool,
16494        window: &mut Window,
16495        cx: &mut Context<Self>,
16496    ) {
16497        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16498
16499        if ranges.iter().any(|range| range.start != range.end) {
16500            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16501            return;
16502        }
16503
16504        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16505        let snapshot = self.snapshot(window, cx);
16506        let position = self.selections.newest::<Point>(cx).head();
16507        let mut row = snapshot
16508            .buffer_snapshot
16509            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16510            .find(|hunk| hunk.row_range.start.0 > position.row)
16511            .map(|hunk| hunk.row_range.start);
16512
16513        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16514        // Outside of the project diff editor, wrap around to the beginning.
16515        if !all_diff_hunks_expanded {
16516            row = row.or_else(|| {
16517                snapshot
16518                    .buffer_snapshot
16519                    .diff_hunks_in_range(Point::zero()..position)
16520                    .find(|hunk| hunk.row_range.end.0 < position.row)
16521                    .map(|hunk| hunk.row_range.start)
16522            });
16523        }
16524
16525        if let Some(row) = row {
16526            let destination = Point::new(row.0, 0);
16527            let autoscroll = Autoscroll::center();
16528
16529            self.unfold_ranges(&[destination..destination], false, false, cx);
16530            self.change_selections(Some(autoscroll), window, cx, |s| {
16531                s.select_ranges([destination..destination]);
16532            });
16533        }
16534    }
16535
16536    fn do_stage_or_unstage(
16537        &self,
16538        stage: bool,
16539        buffer_id: BufferId,
16540        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16541        cx: &mut App,
16542    ) -> Option<()> {
16543        let project = self.project.as_ref()?;
16544        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16545        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16546        let buffer_snapshot = buffer.read(cx).snapshot();
16547        let file_exists = buffer_snapshot
16548            .file()
16549            .is_some_and(|file| file.disk_state().exists());
16550        diff.update(cx, |diff, cx| {
16551            diff.stage_or_unstage_hunks(
16552                stage,
16553                &hunks
16554                    .map(|hunk| buffer_diff::DiffHunk {
16555                        buffer_range: hunk.buffer_range,
16556                        diff_base_byte_range: hunk.diff_base_byte_range,
16557                        secondary_status: hunk.secondary_status,
16558                        range: Point::zero()..Point::zero(), // unused
16559                    })
16560                    .collect::<Vec<_>>(),
16561                &buffer_snapshot,
16562                file_exists,
16563                cx,
16564            )
16565        });
16566        None
16567    }
16568
16569    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16570        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16571        self.buffer
16572            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16573    }
16574
16575    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16576        self.buffer.update(cx, |buffer, cx| {
16577            let ranges = vec![Anchor::min()..Anchor::max()];
16578            if !buffer.all_diff_hunks_expanded()
16579                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16580            {
16581                buffer.collapse_diff_hunks(ranges, cx);
16582                true
16583            } else {
16584                false
16585            }
16586        })
16587    }
16588
16589    fn toggle_diff_hunks_in_ranges(
16590        &mut self,
16591        ranges: Vec<Range<Anchor>>,
16592        cx: &mut Context<Editor>,
16593    ) {
16594        self.buffer.update(cx, |buffer, cx| {
16595            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16596            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16597        })
16598    }
16599
16600    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16601        self.buffer.update(cx, |buffer, cx| {
16602            let snapshot = buffer.snapshot(cx);
16603            let excerpt_id = range.end.excerpt_id;
16604            let point_range = range.to_point(&snapshot);
16605            let expand = !buffer.single_hunk_is_expanded(range, cx);
16606            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16607        })
16608    }
16609
16610    pub(crate) fn apply_all_diff_hunks(
16611        &mut self,
16612        _: &ApplyAllDiffHunks,
16613        window: &mut Window,
16614        cx: &mut Context<Self>,
16615    ) {
16616        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16617
16618        let buffers = self.buffer.read(cx).all_buffers();
16619        for branch_buffer in buffers {
16620            branch_buffer.update(cx, |branch_buffer, cx| {
16621                branch_buffer.merge_into_base(Vec::new(), cx);
16622            });
16623        }
16624
16625        if let Some(project) = self.project.clone() {
16626            self.save(true, project, window, cx).detach_and_log_err(cx);
16627        }
16628    }
16629
16630    pub(crate) fn apply_selected_diff_hunks(
16631        &mut self,
16632        _: &ApplyDiffHunk,
16633        window: &mut Window,
16634        cx: &mut Context<Self>,
16635    ) {
16636        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16637        let snapshot = self.snapshot(window, cx);
16638        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16639        let mut ranges_by_buffer = HashMap::default();
16640        self.transact(window, cx, |editor, _window, cx| {
16641            for hunk in hunks {
16642                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16643                    ranges_by_buffer
16644                        .entry(buffer.clone())
16645                        .or_insert_with(Vec::new)
16646                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16647                }
16648            }
16649
16650            for (buffer, ranges) in ranges_by_buffer {
16651                buffer.update(cx, |buffer, cx| {
16652                    buffer.merge_into_base(ranges, cx);
16653                });
16654            }
16655        });
16656
16657        if let Some(project) = self.project.clone() {
16658            self.save(true, project, window, cx).detach_and_log_err(cx);
16659        }
16660    }
16661
16662    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16663        if hovered != self.gutter_hovered {
16664            self.gutter_hovered = hovered;
16665            cx.notify();
16666        }
16667    }
16668
16669    pub fn insert_blocks(
16670        &mut self,
16671        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16672        autoscroll: Option<Autoscroll>,
16673        cx: &mut Context<Self>,
16674    ) -> Vec<CustomBlockId> {
16675        let blocks = self
16676            .display_map
16677            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16678        if let Some(autoscroll) = autoscroll {
16679            self.request_autoscroll(autoscroll, cx);
16680        }
16681        cx.notify();
16682        blocks
16683    }
16684
16685    pub fn resize_blocks(
16686        &mut self,
16687        heights: HashMap<CustomBlockId, u32>,
16688        autoscroll: Option<Autoscroll>,
16689        cx: &mut Context<Self>,
16690    ) {
16691        self.display_map
16692            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16693        if let Some(autoscroll) = autoscroll {
16694            self.request_autoscroll(autoscroll, cx);
16695        }
16696        cx.notify();
16697    }
16698
16699    pub fn replace_blocks(
16700        &mut self,
16701        renderers: HashMap<CustomBlockId, RenderBlock>,
16702        autoscroll: Option<Autoscroll>,
16703        cx: &mut Context<Self>,
16704    ) {
16705        self.display_map
16706            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16707        if let Some(autoscroll) = autoscroll {
16708            self.request_autoscroll(autoscroll, cx);
16709        }
16710        cx.notify();
16711    }
16712
16713    pub fn remove_blocks(
16714        &mut self,
16715        block_ids: HashSet<CustomBlockId>,
16716        autoscroll: Option<Autoscroll>,
16717        cx: &mut Context<Self>,
16718    ) {
16719        self.display_map.update(cx, |display_map, cx| {
16720            display_map.remove_blocks(block_ids, cx)
16721        });
16722        if let Some(autoscroll) = autoscroll {
16723            self.request_autoscroll(autoscroll, cx);
16724        }
16725        cx.notify();
16726    }
16727
16728    pub fn row_for_block(
16729        &self,
16730        block_id: CustomBlockId,
16731        cx: &mut Context<Self>,
16732    ) -> Option<DisplayRow> {
16733        self.display_map
16734            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16735    }
16736
16737    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16738        self.focused_block = Some(focused_block);
16739    }
16740
16741    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16742        self.focused_block.take()
16743    }
16744
16745    pub fn insert_creases(
16746        &mut self,
16747        creases: impl IntoIterator<Item = Crease<Anchor>>,
16748        cx: &mut Context<Self>,
16749    ) -> Vec<CreaseId> {
16750        self.display_map
16751            .update(cx, |map, cx| map.insert_creases(creases, cx))
16752    }
16753
16754    pub fn remove_creases(
16755        &mut self,
16756        ids: impl IntoIterator<Item = CreaseId>,
16757        cx: &mut Context<Self>,
16758    ) -> Vec<(CreaseId, Range<Anchor>)> {
16759        self.display_map
16760            .update(cx, |map, cx| map.remove_creases(ids, cx))
16761    }
16762
16763    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16764        self.display_map
16765            .update(cx, |map, cx| map.snapshot(cx))
16766            .longest_row()
16767    }
16768
16769    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16770        self.display_map
16771            .update(cx, |map, cx| map.snapshot(cx))
16772            .max_point()
16773    }
16774
16775    pub fn text(&self, cx: &App) -> String {
16776        self.buffer.read(cx).read(cx).text()
16777    }
16778
16779    pub fn is_empty(&self, cx: &App) -> bool {
16780        self.buffer.read(cx).read(cx).is_empty()
16781    }
16782
16783    pub fn text_option(&self, cx: &App) -> Option<String> {
16784        let text = self.text(cx);
16785        let text = text.trim();
16786
16787        if text.is_empty() {
16788            return None;
16789        }
16790
16791        Some(text.to_string())
16792    }
16793
16794    pub fn set_text(
16795        &mut self,
16796        text: impl Into<Arc<str>>,
16797        window: &mut Window,
16798        cx: &mut Context<Self>,
16799    ) {
16800        self.transact(window, cx, |this, _, cx| {
16801            this.buffer
16802                .read(cx)
16803                .as_singleton()
16804                .expect("you can only call set_text on editors for singleton buffers")
16805                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16806        });
16807    }
16808
16809    pub fn display_text(&self, cx: &mut App) -> String {
16810        self.display_map
16811            .update(cx, |map, cx| map.snapshot(cx))
16812            .text()
16813    }
16814
16815    fn create_minimap(
16816        &self,
16817        minimap_settings: MinimapSettings,
16818        window: &mut Window,
16819        cx: &mut Context<Self>,
16820    ) -> Option<Entity<Self>> {
16821        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16822            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16823    }
16824
16825    fn initialize_new_minimap(
16826        &self,
16827        minimap_settings: MinimapSettings,
16828        window: &mut Window,
16829        cx: &mut Context<Self>,
16830    ) -> Entity<Self> {
16831        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16832
16833        let mut minimap = Editor::new_internal(
16834            EditorMode::Minimap {
16835                parent: cx.weak_entity(),
16836            },
16837            self.buffer.clone(),
16838            self.project.clone(),
16839            Some(self.display_map.clone()),
16840            window,
16841            cx,
16842        );
16843        minimap.scroll_manager.clone_state(&self.scroll_manager);
16844        minimap.set_text_style_refinement(TextStyleRefinement {
16845            font_size: Some(MINIMAP_FONT_SIZE),
16846            font_weight: Some(MINIMAP_FONT_WEIGHT),
16847            ..Default::default()
16848        });
16849        minimap.update_minimap_configuration(minimap_settings, cx);
16850        cx.new(|_| minimap)
16851    }
16852
16853    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
16854        let current_line_highlight = minimap_settings
16855            .current_line_highlight
16856            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
16857        self.set_current_line_highlight(Some(current_line_highlight));
16858    }
16859
16860    pub fn minimap(&self) -> Option<&Entity<Self>> {
16861        self.minimap
16862            .as_ref()
16863            .filter(|_| self.minimap_visibility.visible())
16864    }
16865
16866    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
16867        let mut wrap_guides = smallvec![];
16868
16869        if self.show_wrap_guides == Some(false) {
16870            return wrap_guides;
16871        }
16872
16873        let settings = self.buffer.read(cx).language_settings(cx);
16874        if settings.show_wrap_guides {
16875            match self.soft_wrap_mode(cx) {
16876                SoftWrap::Column(soft_wrap) => {
16877                    wrap_guides.push((soft_wrap as usize, true));
16878                }
16879                SoftWrap::Bounded(soft_wrap) => {
16880                    wrap_guides.push((soft_wrap as usize, true));
16881                }
16882                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
16883            }
16884            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
16885        }
16886
16887        wrap_guides
16888    }
16889
16890    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
16891        let settings = self.buffer.read(cx).language_settings(cx);
16892        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
16893        match mode {
16894            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
16895                SoftWrap::None
16896            }
16897            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
16898            language_settings::SoftWrap::PreferredLineLength => {
16899                SoftWrap::Column(settings.preferred_line_length)
16900            }
16901            language_settings::SoftWrap::Bounded => {
16902                SoftWrap::Bounded(settings.preferred_line_length)
16903            }
16904        }
16905    }
16906
16907    pub fn set_soft_wrap_mode(
16908        &mut self,
16909        mode: language_settings::SoftWrap,
16910
16911        cx: &mut Context<Self>,
16912    ) {
16913        self.soft_wrap_mode_override = Some(mode);
16914        cx.notify();
16915    }
16916
16917    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
16918        self.hard_wrap = hard_wrap;
16919        cx.notify();
16920    }
16921
16922    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
16923        self.text_style_refinement = Some(style);
16924    }
16925
16926    /// called by the Element so we know what style we were most recently rendered with.
16927    pub(crate) fn set_style(
16928        &mut self,
16929        style: EditorStyle,
16930        window: &mut Window,
16931        cx: &mut Context<Self>,
16932    ) {
16933        // We intentionally do not inform the display map about the minimap style
16934        // so that wrapping is not recalculated and stays consistent for the editor
16935        // and its linked minimap.
16936        if !self.mode.is_minimap() {
16937            let rem_size = window.rem_size();
16938            self.display_map.update(cx, |map, cx| {
16939                map.set_font(
16940                    style.text.font(),
16941                    style.text.font_size.to_pixels(rem_size),
16942                    cx,
16943                )
16944            });
16945        }
16946        self.style = Some(style);
16947    }
16948
16949    pub fn style(&self) -> Option<&EditorStyle> {
16950        self.style.as_ref()
16951    }
16952
16953    // Called by the element. This method is not designed to be called outside of the editor
16954    // element's layout code because it does not notify when rewrapping is computed synchronously.
16955    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
16956        self.display_map
16957            .update(cx, |map, cx| map.set_wrap_width(width, cx))
16958    }
16959
16960    pub fn set_soft_wrap(&mut self) {
16961        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
16962    }
16963
16964    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
16965        if self.soft_wrap_mode_override.is_some() {
16966            self.soft_wrap_mode_override.take();
16967        } else {
16968            let soft_wrap = match self.soft_wrap_mode(cx) {
16969                SoftWrap::GitDiff => return,
16970                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
16971                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
16972                    language_settings::SoftWrap::None
16973                }
16974            };
16975            self.soft_wrap_mode_override = Some(soft_wrap);
16976        }
16977        cx.notify();
16978    }
16979
16980    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
16981        let Some(workspace) = self.workspace() else {
16982            return;
16983        };
16984        let fs = workspace.read(cx).app_state().fs.clone();
16985        let current_show = TabBarSettings::get_global(cx).show;
16986        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
16987            setting.show = Some(!current_show);
16988        });
16989    }
16990
16991    pub fn toggle_indent_guides(
16992        &mut self,
16993        _: &ToggleIndentGuides,
16994        _: &mut Window,
16995        cx: &mut Context<Self>,
16996    ) {
16997        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
16998            self.buffer
16999                .read(cx)
17000                .language_settings(cx)
17001                .indent_guides
17002                .enabled
17003        });
17004        self.show_indent_guides = Some(!currently_enabled);
17005        cx.notify();
17006    }
17007
17008    fn should_show_indent_guides(&self) -> Option<bool> {
17009        self.show_indent_guides
17010    }
17011
17012    pub fn toggle_line_numbers(
17013        &mut self,
17014        _: &ToggleLineNumbers,
17015        _: &mut Window,
17016        cx: &mut Context<Self>,
17017    ) {
17018        let mut editor_settings = EditorSettings::get_global(cx).clone();
17019        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17020        EditorSettings::override_global(editor_settings, cx);
17021    }
17022
17023    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17024        if let Some(show_line_numbers) = self.show_line_numbers {
17025            return show_line_numbers;
17026        }
17027        EditorSettings::get_global(cx).gutter.line_numbers
17028    }
17029
17030    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17031        self.use_relative_line_numbers
17032            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17033    }
17034
17035    pub fn toggle_relative_line_numbers(
17036        &mut self,
17037        _: &ToggleRelativeLineNumbers,
17038        _: &mut Window,
17039        cx: &mut Context<Self>,
17040    ) {
17041        let is_relative = self.should_use_relative_line_numbers(cx);
17042        self.set_relative_line_number(Some(!is_relative), cx)
17043    }
17044
17045    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17046        self.use_relative_line_numbers = is_relative;
17047        cx.notify();
17048    }
17049
17050    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17051        self.show_gutter = show_gutter;
17052        cx.notify();
17053    }
17054
17055    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17056        self.show_scrollbars = ScrollbarAxes {
17057            horizontal: show,
17058            vertical: show,
17059        };
17060        cx.notify();
17061    }
17062
17063    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17064        self.show_scrollbars.vertical = show;
17065        cx.notify();
17066    }
17067
17068    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17069        self.show_scrollbars.horizontal = show;
17070        cx.notify();
17071    }
17072
17073    pub fn set_minimap_visibility(
17074        &mut self,
17075        minimap_visibility: MinimapVisibility,
17076        window: &mut Window,
17077        cx: &mut Context<Self>,
17078    ) {
17079        if self.minimap_visibility != minimap_visibility {
17080            if minimap_visibility.visible() && self.minimap.is_none() {
17081                let minimap_settings = EditorSettings::get_global(cx).minimap;
17082                self.minimap =
17083                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17084            }
17085            self.minimap_visibility = minimap_visibility;
17086            cx.notify();
17087        }
17088    }
17089
17090    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17091        self.set_show_scrollbars(false, cx);
17092        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17093    }
17094
17095    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17096        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17097    }
17098
17099    /// Normally the text in full mode and auto height editors is padded on the
17100    /// left side by roughly half a character width for improved hit testing.
17101    ///
17102    /// Use this method to disable this for cases where this is not wanted (e.g.
17103    /// if you want to align the editor text with some other text above or below)
17104    /// or if you want to add this padding to single-line editors.
17105    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17106        self.offset_content = offset_content;
17107        cx.notify();
17108    }
17109
17110    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17111        self.show_line_numbers = Some(show_line_numbers);
17112        cx.notify();
17113    }
17114
17115    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17116        self.disable_expand_excerpt_buttons = true;
17117        cx.notify();
17118    }
17119
17120    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17121        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17122        cx.notify();
17123    }
17124
17125    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17126        self.show_code_actions = Some(show_code_actions);
17127        cx.notify();
17128    }
17129
17130    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17131        self.show_runnables = Some(show_runnables);
17132        cx.notify();
17133    }
17134
17135    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17136        self.show_breakpoints = Some(show_breakpoints);
17137        cx.notify();
17138    }
17139
17140    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17141        if self.display_map.read(cx).masked != masked {
17142            self.display_map.update(cx, |map, _| map.masked = masked);
17143        }
17144        cx.notify()
17145    }
17146
17147    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17148        self.show_wrap_guides = Some(show_wrap_guides);
17149        cx.notify();
17150    }
17151
17152    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17153        self.show_indent_guides = Some(show_indent_guides);
17154        cx.notify();
17155    }
17156
17157    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17158        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17159            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17160                if let Some(dir) = file.abs_path(cx).parent() {
17161                    return Some(dir.to_owned());
17162                }
17163            }
17164
17165            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17166                return Some(project_path.path.to_path_buf());
17167            }
17168        }
17169
17170        None
17171    }
17172
17173    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17174        self.active_excerpt(cx)?
17175            .1
17176            .read(cx)
17177            .file()
17178            .and_then(|f| f.as_local())
17179    }
17180
17181    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17182        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17183            let buffer = buffer.read(cx);
17184            if let Some(project_path) = buffer.project_path(cx) {
17185                let project = self.project.as_ref()?.read(cx);
17186                project.absolute_path(&project_path, cx)
17187            } else {
17188                buffer
17189                    .file()
17190                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17191            }
17192        })
17193    }
17194
17195    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17196        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17197            let project_path = buffer.read(cx).project_path(cx)?;
17198            let project = self.project.as_ref()?.read(cx);
17199            let entry = project.entry_for_path(&project_path, cx)?;
17200            let path = entry.path.to_path_buf();
17201            Some(path)
17202        })
17203    }
17204
17205    pub fn reveal_in_finder(
17206        &mut self,
17207        _: &RevealInFileManager,
17208        _window: &mut Window,
17209        cx: &mut Context<Self>,
17210    ) {
17211        if let Some(target) = self.target_file(cx) {
17212            cx.reveal_path(&target.abs_path(cx));
17213        }
17214    }
17215
17216    pub fn copy_path(
17217        &mut self,
17218        _: &zed_actions::workspace::CopyPath,
17219        _window: &mut Window,
17220        cx: &mut Context<Self>,
17221    ) {
17222        if let Some(path) = self.target_file_abs_path(cx) {
17223            if let Some(path) = path.to_str() {
17224                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17225            }
17226        }
17227    }
17228
17229    pub fn copy_relative_path(
17230        &mut self,
17231        _: &zed_actions::workspace::CopyRelativePath,
17232        _window: &mut Window,
17233        cx: &mut Context<Self>,
17234    ) {
17235        if let Some(path) = self.target_file_path(cx) {
17236            if let Some(path) = path.to_str() {
17237                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17238            }
17239        }
17240    }
17241
17242    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17243        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17244            buffer.read(cx).project_path(cx)
17245        } else {
17246            None
17247        }
17248    }
17249
17250    // Returns true if the editor handled a go-to-line request
17251    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17252        maybe!({
17253            let breakpoint_store = self.breakpoint_store.as_ref()?;
17254
17255            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17256            else {
17257                self.clear_row_highlights::<ActiveDebugLine>();
17258                return None;
17259            };
17260
17261            let position = active_stack_frame.position;
17262            let buffer_id = position.buffer_id?;
17263            let snapshot = self
17264                .project
17265                .as_ref()?
17266                .read(cx)
17267                .buffer_for_id(buffer_id, cx)?
17268                .read(cx)
17269                .snapshot();
17270
17271            let mut handled = false;
17272            for (id, ExcerptRange { context, .. }) in
17273                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17274            {
17275                if context.start.cmp(&position, &snapshot).is_ge()
17276                    || context.end.cmp(&position, &snapshot).is_lt()
17277                {
17278                    continue;
17279                }
17280                let snapshot = self.buffer.read(cx).snapshot(cx);
17281                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17282
17283                handled = true;
17284                self.clear_row_highlights::<ActiveDebugLine>();
17285
17286                self.go_to_line::<ActiveDebugLine>(
17287                    multibuffer_anchor,
17288                    Some(cx.theme().colors().editor_debugger_active_line_background),
17289                    window,
17290                    cx,
17291                );
17292
17293                cx.notify();
17294            }
17295
17296            handled.then_some(())
17297        })
17298        .is_some()
17299    }
17300
17301    pub fn copy_file_name_without_extension(
17302        &mut self,
17303        _: &CopyFileNameWithoutExtension,
17304        _: &mut Window,
17305        cx: &mut Context<Self>,
17306    ) {
17307        if let Some(file) = self.target_file(cx) {
17308            if let Some(file_stem) = file.path().file_stem() {
17309                if let Some(name) = file_stem.to_str() {
17310                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17311                }
17312            }
17313        }
17314    }
17315
17316    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17317        if let Some(file) = self.target_file(cx) {
17318            if let Some(file_name) = file.path().file_name() {
17319                if let Some(name) = file_name.to_str() {
17320                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17321                }
17322            }
17323        }
17324    }
17325
17326    pub fn toggle_git_blame(
17327        &mut self,
17328        _: &::git::Blame,
17329        window: &mut Window,
17330        cx: &mut Context<Self>,
17331    ) {
17332        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17333
17334        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17335            self.start_git_blame(true, window, cx);
17336        }
17337
17338        cx.notify();
17339    }
17340
17341    pub fn toggle_git_blame_inline(
17342        &mut self,
17343        _: &ToggleGitBlameInline,
17344        window: &mut Window,
17345        cx: &mut Context<Self>,
17346    ) {
17347        self.toggle_git_blame_inline_internal(true, window, cx);
17348        cx.notify();
17349    }
17350
17351    pub fn open_git_blame_commit(
17352        &mut self,
17353        _: &OpenGitBlameCommit,
17354        window: &mut Window,
17355        cx: &mut Context<Self>,
17356    ) {
17357        self.open_git_blame_commit_internal(window, cx);
17358    }
17359
17360    fn open_git_blame_commit_internal(
17361        &mut self,
17362        window: &mut Window,
17363        cx: &mut Context<Self>,
17364    ) -> Option<()> {
17365        let blame = self.blame.as_ref()?;
17366        let snapshot = self.snapshot(window, cx);
17367        let cursor = self.selections.newest::<Point>(cx).head();
17368        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17369        let blame_entry = blame
17370            .update(cx, |blame, cx| {
17371                blame
17372                    .blame_for_rows(
17373                        &[RowInfo {
17374                            buffer_id: Some(buffer.remote_id()),
17375                            buffer_row: Some(point.row),
17376                            ..Default::default()
17377                        }],
17378                        cx,
17379                    )
17380                    .next()
17381            })
17382            .flatten()?;
17383        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17384        let repo = blame.read(cx).repository(cx)?;
17385        let workspace = self.workspace()?.downgrade();
17386        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17387        None
17388    }
17389
17390    pub fn git_blame_inline_enabled(&self) -> bool {
17391        self.git_blame_inline_enabled
17392    }
17393
17394    pub fn toggle_selection_menu(
17395        &mut self,
17396        _: &ToggleSelectionMenu,
17397        _: &mut Window,
17398        cx: &mut Context<Self>,
17399    ) {
17400        self.show_selection_menu = self
17401            .show_selection_menu
17402            .map(|show_selections_menu| !show_selections_menu)
17403            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17404
17405        cx.notify();
17406    }
17407
17408    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17409        self.show_selection_menu
17410            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17411    }
17412
17413    fn start_git_blame(
17414        &mut self,
17415        user_triggered: bool,
17416        window: &mut Window,
17417        cx: &mut Context<Self>,
17418    ) {
17419        if let Some(project) = self.project.as_ref() {
17420            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17421                return;
17422            };
17423
17424            if buffer.read(cx).file().is_none() {
17425                return;
17426            }
17427
17428            let focused = self.focus_handle(cx).contains_focused(window, cx);
17429
17430            let project = project.clone();
17431            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17432            self.blame_subscription =
17433                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17434            self.blame = Some(blame);
17435        }
17436    }
17437
17438    fn toggle_git_blame_inline_internal(
17439        &mut self,
17440        user_triggered: bool,
17441        window: &mut Window,
17442        cx: &mut Context<Self>,
17443    ) {
17444        if self.git_blame_inline_enabled {
17445            self.git_blame_inline_enabled = false;
17446            self.show_git_blame_inline = false;
17447            self.show_git_blame_inline_delay_task.take();
17448        } else {
17449            self.git_blame_inline_enabled = true;
17450            self.start_git_blame_inline(user_triggered, window, cx);
17451        }
17452
17453        cx.notify();
17454    }
17455
17456    fn start_git_blame_inline(
17457        &mut self,
17458        user_triggered: bool,
17459        window: &mut Window,
17460        cx: &mut Context<Self>,
17461    ) {
17462        self.start_git_blame(user_triggered, window, cx);
17463
17464        if ProjectSettings::get_global(cx)
17465            .git
17466            .inline_blame_delay()
17467            .is_some()
17468        {
17469            self.start_inline_blame_timer(window, cx);
17470        } else {
17471            self.show_git_blame_inline = true
17472        }
17473    }
17474
17475    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17476        self.blame.as_ref()
17477    }
17478
17479    pub fn show_git_blame_gutter(&self) -> bool {
17480        self.show_git_blame_gutter
17481    }
17482
17483    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17484        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17485    }
17486
17487    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17488        self.show_git_blame_inline
17489            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17490            && !self.newest_selection_head_on_empty_line(cx)
17491            && self.has_blame_entries(cx)
17492    }
17493
17494    fn has_blame_entries(&self, cx: &App) -> bool {
17495        self.blame()
17496            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17497    }
17498
17499    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17500        let cursor_anchor = self.selections.newest_anchor().head();
17501
17502        let snapshot = self.buffer.read(cx).snapshot(cx);
17503        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17504
17505        snapshot.line_len(buffer_row) == 0
17506    }
17507
17508    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17509        let buffer_and_selection = maybe!({
17510            let selection = self.selections.newest::<Point>(cx);
17511            let selection_range = selection.range();
17512
17513            let multi_buffer = self.buffer().read(cx);
17514            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17515            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17516
17517            let (buffer, range, _) = if selection.reversed {
17518                buffer_ranges.first()
17519            } else {
17520                buffer_ranges.last()
17521            }?;
17522
17523            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17524                ..text::ToPoint::to_point(&range.end, &buffer).row;
17525            Some((
17526                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17527                selection,
17528            ))
17529        });
17530
17531        let Some((buffer, selection)) = buffer_and_selection else {
17532            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17533        };
17534
17535        let Some(project) = self.project.as_ref() else {
17536            return Task::ready(Err(anyhow!("editor does not have project")));
17537        };
17538
17539        project.update(cx, |project, cx| {
17540            project.get_permalink_to_line(&buffer, selection, cx)
17541        })
17542    }
17543
17544    pub fn copy_permalink_to_line(
17545        &mut self,
17546        _: &CopyPermalinkToLine,
17547        window: &mut Window,
17548        cx: &mut Context<Self>,
17549    ) {
17550        let permalink_task = self.get_permalink_to_line(cx);
17551        let workspace = self.workspace();
17552
17553        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17554            Ok(permalink) => {
17555                cx.update(|_, cx| {
17556                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17557                })
17558                .ok();
17559            }
17560            Err(err) => {
17561                let message = format!("Failed to copy permalink: {err}");
17562
17563                anyhow::Result::<()>::Err(err).log_err();
17564
17565                if let Some(workspace) = workspace {
17566                    workspace
17567                        .update_in(cx, |workspace, _, cx| {
17568                            struct CopyPermalinkToLine;
17569
17570                            workspace.show_toast(
17571                                Toast::new(
17572                                    NotificationId::unique::<CopyPermalinkToLine>(),
17573                                    message,
17574                                ),
17575                                cx,
17576                            )
17577                        })
17578                        .ok();
17579                }
17580            }
17581        })
17582        .detach();
17583    }
17584
17585    pub fn copy_file_location(
17586        &mut self,
17587        _: &CopyFileLocation,
17588        _: &mut Window,
17589        cx: &mut Context<Self>,
17590    ) {
17591        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17592        if let Some(file) = self.target_file(cx) {
17593            if let Some(path) = file.path().to_str() {
17594                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17595            }
17596        }
17597    }
17598
17599    pub fn open_permalink_to_line(
17600        &mut self,
17601        _: &OpenPermalinkToLine,
17602        window: &mut Window,
17603        cx: &mut Context<Self>,
17604    ) {
17605        let permalink_task = self.get_permalink_to_line(cx);
17606        let workspace = self.workspace();
17607
17608        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17609            Ok(permalink) => {
17610                cx.update(|_, cx| {
17611                    cx.open_url(permalink.as_ref());
17612                })
17613                .ok();
17614            }
17615            Err(err) => {
17616                let message = format!("Failed to open permalink: {err}");
17617
17618                anyhow::Result::<()>::Err(err).log_err();
17619
17620                if let Some(workspace) = workspace {
17621                    workspace
17622                        .update(cx, |workspace, cx| {
17623                            struct OpenPermalinkToLine;
17624
17625                            workspace.show_toast(
17626                                Toast::new(
17627                                    NotificationId::unique::<OpenPermalinkToLine>(),
17628                                    message,
17629                                ),
17630                                cx,
17631                            )
17632                        })
17633                        .ok();
17634                }
17635            }
17636        })
17637        .detach();
17638    }
17639
17640    pub fn insert_uuid_v4(
17641        &mut self,
17642        _: &InsertUuidV4,
17643        window: &mut Window,
17644        cx: &mut Context<Self>,
17645    ) {
17646        self.insert_uuid(UuidVersion::V4, window, cx);
17647    }
17648
17649    pub fn insert_uuid_v7(
17650        &mut self,
17651        _: &InsertUuidV7,
17652        window: &mut Window,
17653        cx: &mut Context<Self>,
17654    ) {
17655        self.insert_uuid(UuidVersion::V7, window, cx);
17656    }
17657
17658    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17659        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17660        self.transact(window, cx, |this, window, cx| {
17661            let edits = this
17662                .selections
17663                .all::<Point>(cx)
17664                .into_iter()
17665                .map(|selection| {
17666                    let uuid = match version {
17667                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17668                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17669                    };
17670
17671                    (selection.range(), uuid.to_string())
17672                });
17673            this.edit(edits, cx);
17674            this.refresh_inline_completion(true, false, window, cx);
17675        });
17676    }
17677
17678    pub fn open_selections_in_multibuffer(
17679        &mut self,
17680        _: &OpenSelectionsInMultibuffer,
17681        window: &mut Window,
17682        cx: &mut Context<Self>,
17683    ) {
17684        let multibuffer = self.buffer.read(cx);
17685
17686        let Some(buffer) = multibuffer.as_singleton() else {
17687            return;
17688        };
17689
17690        let Some(workspace) = self.workspace() else {
17691            return;
17692        };
17693
17694        let locations = self
17695            .selections
17696            .disjoint_anchors()
17697            .iter()
17698            .map(|selection| {
17699                let range = if selection.reversed {
17700                    selection.end.text_anchor..selection.start.text_anchor
17701                } else {
17702                    selection.start.text_anchor..selection.end.text_anchor
17703                };
17704                Location {
17705                    buffer: buffer.clone(),
17706                    range,
17707                }
17708            })
17709            .collect::<Vec<_>>();
17710
17711        let title = multibuffer.title(cx).to_string();
17712
17713        cx.spawn_in(window, async move |_, cx| {
17714            workspace.update_in(cx, |workspace, window, cx| {
17715                Self::open_locations_in_multibuffer(
17716                    workspace,
17717                    locations,
17718                    format!("Selections for '{title}'"),
17719                    false,
17720                    MultibufferSelectionMode::All,
17721                    window,
17722                    cx,
17723                );
17724            })
17725        })
17726        .detach();
17727    }
17728
17729    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17730    /// last highlight added will be used.
17731    ///
17732    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17733    pub fn highlight_rows<T: 'static>(
17734        &mut self,
17735        range: Range<Anchor>,
17736        color: Hsla,
17737        options: RowHighlightOptions,
17738        cx: &mut Context<Self>,
17739    ) {
17740        let snapshot = self.buffer().read(cx).snapshot(cx);
17741        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17742        let ix = row_highlights.binary_search_by(|highlight| {
17743            Ordering::Equal
17744                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17745                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17746        });
17747
17748        if let Err(mut ix) = ix {
17749            let index = post_inc(&mut self.highlight_order);
17750
17751            // If this range intersects with the preceding highlight, then merge it with
17752            // the preceding highlight. Otherwise insert a new highlight.
17753            let mut merged = false;
17754            if ix > 0 {
17755                let prev_highlight = &mut row_highlights[ix - 1];
17756                if prev_highlight
17757                    .range
17758                    .end
17759                    .cmp(&range.start, &snapshot)
17760                    .is_ge()
17761                {
17762                    ix -= 1;
17763                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17764                        prev_highlight.range.end = range.end;
17765                    }
17766                    merged = true;
17767                    prev_highlight.index = index;
17768                    prev_highlight.color = color;
17769                    prev_highlight.options = options;
17770                }
17771            }
17772
17773            if !merged {
17774                row_highlights.insert(
17775                    ix,
17776                    RowHighlight {
17777                        range: range.clone(),
17778                        index,
17779                        color,
17780                        options,
17781                        type_id: TypeId::of::<T>(),
17782                    },
17783                );
17784            }
17785
17786            // If any of the following highlights intersect with this one, merge them.
17787            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17788                let highlight = &row_highlights[ix];
17789                if next_highlight
17790                    .range
17791                    .start
17792                    .cmp(&highlight.range.end, &snapshot)
17793                    .is_le()
17794                {
17795                    if next_highlight
17796                        .range
17797                        .end
17798                        .cmp(&highlight.range.end, &snapshot)
17799                        .is_gt()
17800                    {
17801                        row_highlights[ix].range.end = next_highlight.range.end;
17802                    }
17803                    row_highlights.remove(ix + 1);
17804                } else {
17805                    break;
17806                }
17807            }
17808        }
17809    }
17810
17811    /// Remove any highlighted row ranges of the given type that intersect the
17812    /// given ranges.
17813    pub fn remove_highlighted_rows<T: 'static>(
17814        &mut self,
17815        ranges_to_remove: Vec<Range<Anchor>>,
17816        cx: &mut Context<Self>,
17817    ) {
17818        let snapshot = self.buffer().read(cx).snapshot(cx);
17819        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17820        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17821        row_highlights.retain(|highlight| {
17822            while let Some(range_to_remove) = ranges_to_remove.peek() {
17823                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17824                    Ordering::Less | Ordering::Equal => {
17825                        ranges_to_remove.next();
17826                    }
17827                    Ordering::Greater => {
17828                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17829                            Ordering::Less | Ordering::Equal => {
17830                                return false;
17831                            }
17832                            Ordering::Greater => break,
17833                        }
17834                    }
17835                }
17836            }
17837
17838            true
17839        })
17840    }
17841
17842    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
17843    pub fn clear_row_highlights<T: 'static>(&mut self) {
17844        self.highlighted_rows.remove(&TypeId::of::<T>());
17845    }
17846
17847    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
17848    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
17849        self.highlighted_rows
17850            .get(&TypeId::of::<T>())
17851            .map_or(&[] as &[_], |vec| vec.as_slice())
17852            .iter()
17853            .map(|highlight| (highlight.range.clone(), highlight.color))
17854    }
17855
17856    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
17857    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
17858    /// Allows to ignore certain kinds of highlights.
17859    pub fn highlighted_display_rows(
17860        &self,
17861        window: &mut Window,
17862        cx: &mut App,
17863    ) -> BTreeMap<DisplayRow, LineHighlight> {
17864        let snapshot = self.snapshot(window, cx);
17865        let mut used_highlight_orders = HashMap::default();
17866        self.highlighted_rows
17867            .iter()
17868            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
17869            .fold(
17870                BTreeMap::<DisplayRow, LineHighlight>::new(),
17871                |mut unique_rows, highlight| {
17872                    let start = highlight.range.start.to_display_point(&snapshot);
17873                    let end = highlight.range.end.to_display_point(&snapshot);
17874                    let start_row = start.row().0;
17875                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
17876                        && end.column() == 0
17877                    {
17878                        end.row().0.saturating_sub(1)
17879                    } else {
17880                        end.row().0
17881                    };
17882                    for row in start_row..=end_row {
17883                        let used_index =
17884                            used_highlight_orders.entry(row).or_insert(highlight.index);
17885                        if highlight.index >= *used_index {
17886                            *used_index = highlight.index;
17887                            unique_rows.insert(
17888                                DisplayRow(row),
17889                                LineHighlight {
17890                                    include_gutter: highlight.options.include_gutter,
17891                                    border: None,
17892                                    background: highlight.color.into(),
17893                                    type_id: Some(highlight.type_id),
17894                                },
17895                            );
17896                        }
17897                    }
17898                    unique_rows
17899                },
17900            )
17901    }
17902
17903    pub fn highlighted_display_row_for_autoscroll(
17904        &self,
17905        snapshot: &DisplaySnapshot,
17906    ) -> Option<DisplayRow> {
17907        self.highlighted_rows
17908            .values()
17909            .flat_map(|highlighted_rows| highlighted_rows.iter())
17910            .filter_map(|highlight| {
17911                if highlight.options.autoscroll {
17912                    Some(highlight.range.start.to_display_point(snapshot).row())
17913                } else {
17914                    None
17915                }
17916            })
17917            .min()
17918    }
17919
17920    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
17921        self.highlight_background::<SearchWithinRange>(
17922            ranges,
17923            |colors| colors.editor_document_highlight_read_background,
17924            cx,
17925        )
17926    }
17927
17928    pub fn set_breadcrumb_header(&mut self, new_header: String) {
17929        self.breadcrumb_header = Some(new_header);
17930    }
17931
17932    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
17933        self.clear_background_highlights::<SearchWithinRange>(cx);
17934    }
17935
17936    pub fn highlight_background<T: 'static>(
17937        &mut self,
17938        ranges: &[Range<Anchor>],
17939        color_fetcher: fn(&ThemeColors) -> Hsla,
17940        cx: &mut Context<Self>,
17941    ) {
17942        self.background_highlights
17943            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17944        self.scrollbar_marker_state.dirty = true;
17945        cx.notify();
17946    }
17947
17948    pub fn clear_background_highlights<T: 'static>(
17949        &mut self,
17950        cx: &mut Context<Self>,
17951    ) -> Option<BackgroundHighlight> {
17952        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
17953        if !text_highlights.1.is_empty() {
17954            self.scrollbar_marker_state.dirty = true;
17955            cx.notify();
17956        }
17957        Some(text_highlights)
17958    }
17959
17960    pub fn highlight_gutter<T: 'static>(
17961        &mut self,
17962        ranges: &[Range<Anchor>],
17963        color_fetcher: fn(&App) -> Hsla,
17964        cx: &mut Context<Self>,
17965    ) {
17966        self.gutter_highlights
17967            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
17968        cx.notify();
17969    }
17970
17971    pub fn clear_gutter_highlights<T: 'static>(
17972        &mut self,
17973        cx: &mut Context<Self>,
17974    ) -> Option<GutterHighlight> {
17975        cx.notify();
17976        self.gutter_highlights.remove(&TypeId::of::<T>())
17977    }
17978
17979    #[cfg(feature = "test-support")]
17980    pub fn all_text_background_highlights(
17981        &self,
17982        window: &mut Window,
17983        cx: &mut Context<Self>,
17984    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
17985        let snapshot = self.snapshot(window, cx);
17986        let buffer = &snapshot.buffer_snapshot;
17987        let start = buffer.anchor_before(0);
17988        let end = buffer.anchor_after(buffer.len());
17989        let theme = cx.theme().colors();
17990        self.background_highlights_in_range(start..end, &snapshot, theme)
17991    }
17992
17993    #[cfg(feature = "test-support")]
17994    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
17995        let snapshot = self.buffer().read(cx).snapshot(cx);
17996
17997        let highlights = self
17998            .background_highlights
17999            .get(&TypeId::of::<items::BufferSearchHighlights>());
18000
18001        if let Some((_color, ranges)) = highlights {
18002            ranges
18003                .iter()
18004                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18005                .collect_vec()
18006        } else {
18007            vec![]
18008        }
18009    }
18010
18011    fn document_highlights_for_position<'a>(
18012        &'a self,
18013        position: Anchor,
18014        buffer: &'a MultiBufferSnapshot,
18015    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18016        let read_highlights = self
18017            .background_highlights
18018            .get(&TypeId::of::<DocumentHighlightRead>())
18019            .map(|h| &h.1);
18020        let write_highlights = self
18021            .background_highlights
18022            .get(&TypeId::of::<DocumentHighlightWrite>())
18023            .map(|h| &h.1);
18024        let left_position = position.bias_left(buffer);
18025        let right_position = position.bias_right(buffer);
18026        read_highlights
18027            .into_iter()
18028            .chain(write_highlights)
18029            .flat_map(move |ranges| {
18030                let start_ix = match ranges.binary_search_by(|probe| {
18031                    let cmp = probe.end.cmp(&left_position, buffer);
18032                    if cmp.is_ge() {
18033                        Ordering::Greater
18034                    } else {
18035                        Ordering::Less
18036                    }
18037                }) {
18038                    Ok(i) | Err(i) => i,
18039                };
18040
18041                ranges[start_ix..]
18042                    .iter()
18043                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18044            })
18045    }
18046
18047    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18048        self.background_highlights
18049            .get(&TypeId::of::<T>())
18050            .map_or(false, |(_, highlights)| !highlights.is_empty())
18051    }
18052
18053    pub fn background_highlights_in_range(
18054        &self,
18055        search_range: Range<Anchor>,
18056        display_snapshot: &DisplaySnapshot,
18057        theme: &ThemeColors,
18058    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18059        let mut results = Vec::new();
18060        for (color_fetcher, ranges) in self.background_highlights.values() {
18061            let color = color_fetcher(theme);
18062            let start_ix = match ranges.binary_search_by(|probe| {
18063                let cmp = probe
18064                    .end
18065                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18066                if cmp.is_gt() {
18067                    Ordering::Greater
18068                } else {
18069                    Ordering::Less
18070                }
18071            }) {
18072                Ok(i) | Err(i) => i,
18073            };
18074            for range in &ranges[start_ix..] {
18075                if range
18076                    .start
18077                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18078                    .is_ge()
18079                {
18080                    break;
18081                }
18082
18083                let start = range.start.to_display_point(display_snapshot);
18084                let end = range.end.to_display_point(display_snapshot);
18085                results.push((start..end, color))
18086            }
18087        }
18088        results
18089    }
18090
18091    pub fn background_highlight_row_ranges<T: 'static>(
18092        &self,
18093        search_range: Range<Anchor>,
18094        display_snapshot: &DisplaySnapshot,
18095        count: usize,
18096    ) -> Vec<RangeInclusive<DisplayPoint>> {
18097        let mut results = Vec::new();
18098        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18099            return vec![];
18100        };
18101
18102        let start_ix = match ranges.binary_search_by(|probe| {
18103            let cmp = probe
18104                .end
18105                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18106            if cmp.is_gt() {
18107                Ordering::Greater
18108            } else {
18109                Ordering::Less
18110            }
18111        }) {
18112            Ok(i) | Err(i) => i,
18113        };
18114        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18115            if let (Some(start_display), Some(end_display)) = (start, end) {
18116                results.push(
18117                    start_display.to_display_point(display_snapshot)
18118                        ..=end_display.to_display_point(display_snapshot),
18119                );
18120            }
18121        };
18122        let mut start_row: Option<Point> = None;
18123        let mut end_row: Option<Point> = None;
18124        if ranges.len() > count {
18125            return Vec::new();
18126        }
18127        for range in &ranges[start_ix..] {
18128            if range
18129                .start
18130                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18131                .is_ge()
18132            {
18133                break;
18134            }
18135            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18136            if let Some(current_row) = &end_row {
18137                if end.row == current_row.row {
18138                    continue;
18139                }
18140            }
18141            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18142            if start_row.is_none() {
18143                assert_eq!(end_row, None);
18144                start_row = Some(start);
18145                end_row = Some(end);
18146                continue;
18147            }
18148            if let Some(current_end) = end_row.as_mut() {
18149                if start.row > current_end.row + 1 {
18150                    push_region(start_row, end_row);
18151                    start_row = Some(start);
18152                    end_row = Some(end);
18153                } else {
18154                    // Merge two hunks.
18155                    *current_end = end;
18156                }
18157            } else {
18158                unreachable!();
18159            }
18160        }
18161        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18162        push_region(start_row, end_row);
18163        results
18164    }
18165
18166    pub fn gutter_highlights_in_range(
18167        &self,
18168        search_range: Range<Anchor>,
18169        display_snapshot: &DisplaySnapshot,
18170        cx: &App,
18171    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18172        let mut results = Vec::new();
18173        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18174            let color = color_fetcher(cx);
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            for range in &ranges[start_ix..] {
18188                if range
18189                    .start
18190                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18191                    .is_ge()
18192                {
18193                    break;
18194                }
18195
18196                let start = range.start.to_display_point(display_snapshot);
18197                let end = range.end.to_display_point(display_snapshot);
18198                results.push((start..end, color))
18199            }
18200        }
18201        results
18202    }
18203
18204    /// Get the text ranges corresponding to the redaction query
18205    pub fn redacted_ranges(
18206        &self,
18207        search_range: Range<Anchor>,
18208        display_snapshot: &DisplaySnapshot,
18209        cx: &App,
18210    ) -> Vec<Range<DisplayPoint>> {
18211        display_snapshot
18212            .buffer_snapshot
18213            .redacted_ranges(search_range, |file| {
18214                if let Some(file) = file {
18215                    file.is_private()
18216                        && EditorSettings::get(
18217                            Some(SettingsLocation {
18218                                worktree_id: file.worktree_id(cx),
18219                                path: file.path().as_ref(),
18220                            }),
18221                            cx,
18222                        )
18223                        .redact_private_values
18224                } else {
18225                    false
18226                }
18227            })
18228            .map(|range| {
18229                range.start.to_display_point(display_snapshot)
18230                    ..range.end.to_display_point(display_snapshot)
18231            })
18232            .collect()
18233    }
18234
18235    pub fn highlight_text<T: 'static>(
18236        &mut self,
18237        ranges: Vec<Range<Anchor>>,
18238        style: HighlightStyle,
18239        cx: &mut Context<Self>,
18240    ) {
18241        self.display_map.update(cx, |map, _| {
18242            map.highlight_text(TypeId::of::<T>(), ranges, style)
18243        });
18244        cx.notify();
18245    }
18246
18247    pub(crate) fn highlight_inlays<T: 'static>(
18248        &mut self,
18249        highlights: Vec<InlayHighlight>,
18250        style: HighlightStyle,
18251        cx: &mut Context<Self>,
18252    ) {
18253        self.display_map.update(cx, |map, _| {
18254            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18255        });
18256        cx.notify();
18257    }
18258
18259    pub fn text_highlights<'a, T: 'static>(
18260        &'a self,
18261        cx: &'a App,
18262    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18263        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18264    }
18265
18266    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18267        let cleared = self
18268            .display_map
18269            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18270        if cleared {
18271            cx.notify();
18272        }
18273    }
18274
18275    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18276        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18277            && self.focus_handle.is_focused(window)
18278    }
18279
18280    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18281        self.show_cursor_when_unfocused = is_enabled;
18282        cx.notify();
18283    }
18284
18285    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18286        cx.notify();
18287    }
18288
18289    fn on_debug_session_event(
18290        &mut self,
18291        _session: Entity<Session>,
18292        event: &SessionEvent,
18293        cx: &mut Context<Self>,
18294    ) {
18295        match event {
18296            SessionEvent::InvalidateInlineValue => {
18297                self.refresh_inline_values(cx);
18298            }
18299            _ => {}
18300        }
18301    }
18302
18303    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18304        let Some(project) = self.project.clone() else {
18305            return;
18306        };
18307
18308        if !self.inline_value_cache.enabled {
18309            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18310            self.splice_inlays(&inlays, Vec::new(), cx);
18311            return;
18312        }
18313
18314        let current_execution_position = self
18315            .highlighted_rows
18316            .get(&TypeId::of::<ActiveDebugLine>())
18317            .and_then(|lines| lines.last().map(|line| line.range.start));
18318
18319        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18320            let inline_values = editor
18321                .update(cx, |editor, cx| {
18322                    let Some(current_execution_position) = current_execution_position else {
18323                        return Some(Task::ready(Ok(Vec::new())));
18324                    };
18325
18326                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18327                        let snapshot = buffer.snapshot(cx);
18328
18329                        let excerpt = snapshot.excerpt_containing(
18330                            current_execution_position..current_execution_position,
18331                        )?;
18332
18333                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18334                    })?;
18335
18336                    let range =
18337                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18338
18339                    project.inline_values(buffer, range, cx)
18340                })
18341                .ok()
18342                .flatten()?
18343                .await
18344                .context("refreshing debugger inlays")
18345                .log_err()?;
18346
18347            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18348
18349            for (buffer_id, inline_value) in inline_values
18350                .into_iter()
18351                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18352            {
18353                buffer_inline_values
18354                    .entry(buffer_id)
18355                    .or_default()
18356                    .push(inline_value);
18357            }
18358
18359            editor
18360                .update(cx, |editor, cx| {
18361                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18362                    let mut new_inlays = Vec::default();
18363
18364                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18365                        let buffer_id = buffer_snapshot.remote_id();
18366                        buffer_inline_values
18367                            .get(&buffer_id)
18368                            .into_iter()
18369                            .flatten()
18370                            .for_each(|hint| {
18371                                let inlay = Inlay::debugger_hint(
18372                                    post_inc(&mut editor.next_inlay_id),
18373                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18374                                    hint.text(),
18375                                );
18376
18377                                new_inlays.push(inlay);
18378                            });
18379                    }
18380
18381                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18382                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18383
18384                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18385                })
18386                .ok()?;
18387            Some(())
18388        });
18389    }
18390
18391    fn on_buffer_event(
18392        &mut self,
18393        multibuffer: &Entity<MultiBuffer>,
18394        event: &multi_buffer::Event,
18395        window: &mut Window,
18396        cx: &mut Context<Self>,
18397    ) {
18398        match event {
18399            multi_buffer::Event::Edited {
18400                singleton_buffer_edited,
18401                edited_buffer: buffer_edited,
18402            } => {
18403                self.scrollbar_marker_state.dirty = true;
18404                self.active_indent_guides_state.dirty = true;
18405                self.refresh_active_diagnostics(cx);
18406                self.refresh_code_actions(window, cx);
18407                self.refresh_selected_text_highlights(true, window, cx);
18408                refresh_matching_bracket_highlights(self, window, cx);
18409                if self.has_active_inline_completion() {
18410                    self.update_visible_inline_completion(window, cx);
18411                }
18412                if let Some(buffer) = buffer_edited {
18413                    let buffer_id = buffer.read(cx).remote_id();
18414                    if !self.registered_buffers.contains_key(&buffer_id) {
18415                        if let Some(project) = self.project.as_ref() {
18416                            project.update(cx, |project, cx| {
18417                                self.registered_buffers.insert(
18418                                    buffer_id,
18419                                    project.register_buffer_with_language_servers(&buffer, cx),
18420                                );
18421                            })
18422                        }
18423                    }
18424                }
18425                cx.emit(EditorEvent::BufferEdited);
18426                cx.emit(SearchEvent::MatchesInvalidated);
18427                if *singleton_buffer_edited {
18428                    if let Some(project) = &self.project {
18429                        #[allow(clippy::mutable_key_type)]
18430                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18431                            multibuffer
18432                                .all_buffers()
18433                                .into_iter()
18434                                .filter_map(|buffer| {
18435                                    buffer.update(cx, |buffer, cx| {
18436                                        let language = buffer.language()?;
18437                                        let should_discard = project.update(cx, |project, cx| {
18438                                            project.is_local()
18439                                                && !project.has_language_servers_for(buffer, cx)
18440                                        });
18441                                        should_discard.not().then_some(language.clone())
18442                                    })
18443                                })
18444                                .collect::<HashSet<_>>()
18445                        });
18446                        if !languages_affected.is_empty() {
18447                            self.refresh_inlay_hints(
18448                                InlayHintRefreshReason::BufferEdited(languages_affected),
18449                                cx,
18450                            );
18451                        }
18452                    }
18453                }
18454
18455                let Some(project) = &self.project else { return };
18456                let (telemetry, is_via_ssh) = {
18457                    let project = project.read(cx);
18458                    let telemetry = project.client().telemetry().clone();
18459                    let is_via_ssh = project.is_via_ssh();
18460                    (telemetry, is_via_ssh)
18461                };
18462                refresh_linked_ranges(self, window, cx);
18463                telemetry.log_edit_event("editor", is_via_ssh);
18464            }
18465            multi_buffer::Event::ExcerptsAdded {
18466                buffer,
18467                predecessor,
18468                excerpts,
18469            } => {
18470                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18471                let buffer_id = buffer.read(cx).remote_id();
18472                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18473                    if let Some(project) = &self.project {
18474                        update_uncommitted_diff_for_buffer(
18475                            cx.entity(),
18476                            project,
18477                            [buffer.clone()],
18478                            self.buffer.clone(),
18479                            cx,
18480                        )
18481                        .detach();
18482                    }
18483                }
18484                cx.emit(EditorEvent::ExcerptsAdded {
18485                    buffer: buffer.clone(),
18486                    predecessor: *predecessor,
18487                    excerpts: excerpts.clone(),
18488                });
18489                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18490            }
18491            multi_buffer::Event::ExcerptsRemoved {
18492                ids,
18493                removed_buffer_ids,
18494            } => {
18495                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18496                let buffer = self.buffer.read(cx);
18497                self.registered_buffers
18498                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18499                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18500                cx.emit(EditorEvent::ExcerptsRemoved {
18501                    ids: ids.clone(),
18502                    removed_buffer_ids: removed_buffer_ids.clone(),
18503                })
18504            }
18505            multi_buffer::Event::ExcerptsEdited {
18506                excerpt_ids,
18507                buffer_ids,
18508            } => {
18509                self.display_map.update(cx, |map, cx| {
18510                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18511                });
18512                cx.emit(EditorEvent::ExcerptsEdited {
18513                    ids: excerpt_ids.clone(),
18514                })
18515            }
18516            multi_buffer::Event::ExcerptsExpanded { ids } => {
18517                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18518                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18519            }
18520            multi_buffer::Event::Reparsed(buffer_id) => {
18521                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18522                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18523
18524                cx.emit(EditorEvent::Reparsed(*buffer_id));
18525            }
18526            multi_buffer::Event::DiffHunksToggled => {
18527                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18528            }
18529            multi_buffer::Event::LanguageChanged(buffer_id) => {
18530                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18531                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18532                cx.emit(EditorEvent::Reparsed(*buffer_id));
18533                cx.notify();
18534            }
18535            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18536            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18537            multi_buffer::Event::FileHandleChanged
18538            | multi_buffer::Event::Reloaded
18539            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18540            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18541            multi_buffer::Event::DiagnosticsUpdated => {
18542                self.refresh_active_diagnostics(cx);
18543                self.refresh_inline_diagnostics(true, window, cx);
18544                self.scrollbar_marker_state.dirty = true;
18545                cx.notify();
18546            }
18547            _ => {}
18548        };
18549    }
18550
18551    pub fn start_temporary_diff_override(&mut self) {
18552        self.load_diff_task.take();
18553        self.temporary_diff_override = true;
18554    }
18555
18556    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18557        self.temporary_diff_override = false;
18558        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18559        self.buffer.update(cx, |buffer, cx| {
18560            buffer.set_all_diff_hunks_collapsed(cx);
18561        });
18562
18563        if let Some(project) = self.project.clone() {
18564            self.load_diff_task = Some(
18565                update_uncommitted_diff_for_buffer(
18566                    cx.entity(),
18567                    &project,
18568                    self.buffer.read(cx).all_buffers(),
18569                    self.buffer.clone(),
18570                    cx,
18571                )
18572                .shared(),
18573            );
18574        }
18575    }
18576
18577    fn on_display_map_changed(
18578        &mut self,
18579        _: Entity<DisplayMap>,
18580        _: &mut Window,
18581        cx: &mut Context<Self>,
18582    ) {
18583        cx.notify();
18584    }
18585
18586    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18587        let new_severity = if self.diagnostics_enabled() {
18588            EditorSettings::get_global(cx)
18589                .diagnostics_max_severity
18590                .unwrap_or(DiagnosticSeverity::Hint)
18591        } else {
18592            DiagnosticSeverity::Off
18593        };
18594        self.set_max_diagnostics_severity(new_severity, cx);
18595        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18596        self.update_edit_prediction_settings(cx);
18597        self.refresh_inline_completion(true, false, window, cx);
18598        self.refresh_inlay_hints(
18599            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18600                self.selections.newest_anchor().head(),
18601                &self.buffer.read(cx).snapshot(cx),
18602                cx,
18603            )),
18604            cx,
18605        );
18606
18607        let old_cursor_shape = self.cursor_shape;
18608
18609        {
18610            let editor_settings = EditorSettings::get_global(cx);
18611            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18612            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18613            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18614            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18615        }
18616
18617        if old_cursor_shape != self.cursor_shape {
18618            cx.emit(EditorEvent::CursorShapeChanged);
18619        }
18620
18621        let project_settings = ProjectSettings::get_global(cx);
18622        self.serialize_dirty_buffers =
18623            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18624
18625        if self.mode.is_full() {
18626            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18627            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18628            if self.show_inline_diagnostics != show_inline_diagnostics {
18629                self.show_inline_diagnostics = show_inline_diagnostics;
18630                self.refresh_inline_diagnostics(false, window, cx);
18631            }
18632
18633            if self.git_blame_inline_enabled != inline_blame_enabled {
18634                self.toggle_git_blame_inline_internal(false, window, cx);
18635            }
18636
18637            let minimap_settings = EditorSettings::get_global(cx).minimap;
18638            if self.minimap_visibility != MinimapVisibility::Disabled {
18639                if self.minimap_visibility.settings_visibility()
18640                    != minimap_settings.minimap_enabled()
18641                {
18642                    self.set_minimap_visibility(
18643                        MinimapVisibility::for_mode(self.mode(), cx),
18644                        window,
18645                        cx,
18646                    );
18647                } else if let Some(minimap_entity) = self.minimap.as_ref() {
18648                    minimap_entity.update(cx, |minimap_editor, cx| {
18649                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
18650                    })
18651                }
18652            }
18653        }
18654
18655        cx.notify();
18656    }
18657
18658    pub fn set_searchable(&mut self, searchable: bool) {
18659        self.searchable = searchable;
18660    }
18661
18662    pub fn searchable(&self) -> bool {
18663        self.searchable
18664    }
18665
18666    fn open_proposed_changes_editor(
18667        &mut self,
18668        _: &OpenProposedChangesEditor,
18669        window: &mut Window,
18670        cx: &mut Context<Self>,
18671    ) {
18672        let Some(workspace) = self.workspace() else {
18673            cx.propagate();
18674            return;
18675        };
18676
18677        let selections = self.selections.all::<usize>(cx);
18678        let multi_buffer = self.buffer.read(cx);
18679        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18680        let mut new_selections_by_buffer = HashMap::default();
18681        for selection in selections {
18682            for (buffer, range, _) in
18683                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18684            {
18685                let mut range = range.to_point(buffer);
18686                range.start.column = 0;
18687                range.end.column = buffer.line_len(range.end.row);
18688                new_selections_by_buffer
18689                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18690                    .or_insert(Vec::new())
18691                    .push(range)
18692            }
18693        }
18694
18695        let proposed_changes_buffers = new_selections_by_buffer
18696            .into_iter()
18697            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18698            .collect::<Vec<_>>();
18699        let proposed_changes_editor = cx.new(|cx| {
18700            ProposedChangesEditor::new(
18701                "Proposed changes",
18702                proposed_changes_buffers,
18703                self.project.clone(),
18704                window,
18705                cx,
18706            )
18707        });
18708
18709        window.defer(cx, move |window, cx| {
18710            workspace.update(cx, |workspace, cx| {
18711                workspace.active_pane().update(cx, |pane, cx| {
18712                    pane.add_item(
18713                        Box::new(proposed_changes_editor),
18714                        true,
18715                        true,
18716                        None,
18717                        window,
18718                        cx,
18719                    );
18720                });
18721            });
18722        });
18723    }
18724
18725    pub fn open_excerpts_in_split(
18726        &mut self,
18727        _: &OpenExcerptsSplit,
18728        window: &mut Window,
18729        cx: &mut Context<Self>,
18730    ) {
18731        self.open_excerpts_common(None, true, window, cx)
18732    }
18733
18734    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18735        self.open_excerpts_common(None, false, window, cx)
18736    }
18737
18738    fn open_excerpts_common(
18739        &mut self,
18740        jump_data: Option<JumpData>,
18741        split: bool,
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        if self.buffer.read(cx).is_singleton() {
18751            cx.propagate();
18752            return;
18753        }
18754
18755        let mut new_selections_by_buffer = HashMap::default();
18756        match &jump_data {
18757            Some(JumpData::MultiBufferPoint {
18758                excerpt_id,
18759                position,
18760                anchor,
18761                line_offset_from_top,
18762            }) => {
18763                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18764                if let Some(buffer) = multi_buffer_snapshot
18765                    .buffer_id_for_excerpt(*excerpt_id)
18766                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18767                {
18768                    let buffer_snapshot = buffer.read(cx).snapshot();
18769                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18770                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18771                    } else {
18772                        buffer_snapshot.clip_point(*position, Bias::Left)
18773                    };
18774                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18775                    new_selections_by_buffer.insert(
18776                        buffer,
18777                        (
18778                            vec![jump_to_offset..jump_to_offset],
18779                            Some(*line_offset_from_top),
18780                        ),
18781                    );
18782                }
18783            }
18784            Some(JumpData::MultiBufferRow {
18785                row,
18786                line_offset_from_top,
18787            }) => {
18788                let point = MultiBufferPoint::new(row.0, 0);
18789                if let Some((buffer, buffer_point, _)) =
18790                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18791                {
18792                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18793                    new_selections_by_buffer
18794                        .entry(buffer)
18795                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18796                        .0
18797                        .push(buffer_offset..buffer_offset)
18798                }
18799            }
18800            None => {
18801                let selections = self.selections.all::<usize>(cx);
18802                let multi_buffer = self.buffer.read(cx);
18803                for selection in selections {
18804                    for (snapshot, range, _, anchor) in multi_buffer
18805                        .snapshot(cx)
18806                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18807                    {
18808                        if let Some(anchor) = anchor {
18809                            // selection is in a deleted hunk
18810                            let Some(buffer_id) = anchor.buffer_id else {
18811                                continue;
18812                            };
18813                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18814                                continue;
18815                            };
18816                            let offset = text::ToOffset::to_offset(
18817                                &anchor.text_anchor,
18818                                &buffer_handle.read(cx).snapshot(),
18819                            );
18820                            let range = offset..offset;
18821                            new_selections_by_buffer
18822                                .entry(buffer_handle)
18823                                .or_insert((Vec::new(), None))
18824                                .0
18825                                .push(range)
18826                        } else {
18827                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18828                            else {
18829                                continue;
18830                            };
18831                            new_selections_by_buffer
18832                                .entry(buffer_handle)
18833                                .or_insert((Vec::new(), None))
18834                                .0
18835                                .push(range)
18836                        }
18837                    }
18838                }
18839            }
18840        }
18841
18842        new_selections_by_buffer
18843            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
18844
18845        if new_selections_by_buffer.is_empty() {
18846            return;
18847        }
18848
18849        // We defer the pane interaction because we ourselves are a workspace item
18850        // and activating a new item causes the pane to call a method on us reentrantly,
18851        // which panics if we're on the stack.
18852        window.defer(cx, move |window, cx| {
18853            workspace.update(cx, |workspace, cx| {
18854                let pane = if split {
18855                    workspace.adjacent_pane(window, cx)
18856                } else {
18857                    workspace.active_pane().clone()
18858                };
18859
18860                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
18861                    let editor = buffer
18862                        .read(cx)
18863                        .file()
18864                        .is_none()
18865                        .then(|| {
18866                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
18867                            // so `workspace.open_project_item` will never find them, always opening a new editor.
18868                            // Instead, we try to activate the existing editor in the pane first.
18869                            let (editor, pane_item_index) =
18870                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
18871                                    let editor = item.downcast::<Editor>()?;
18872                                    let singleton_buffer =
18873                                        editor.read(cx).buffer().read(cx).as_singleton()?;
18874                                    if singleton_buffer == buffer {
18875                                        Some((editor, i))
18876                                    } else {
18877                                        None
18878                                    }
18879                                })?;
18880                            pane.update(cx, |pane, cx| {
18881                                pane.activate_item(pane_item_index, true, true, window, cx)
18882                            });
18883                            Some(editor)
18884                        })
18885                        .flatten()
18886                        .unwrap_or_else(|| {
18887                            workspace.open_project_item::<Self>(
18888                                pane.clone(),
18889                                buffer,
18890                                true,
18891                                true,
18892                                window,
18893                                cx,
18894                            )
18895                        });
18896
18897                    editor.update(cx, |editor, cx| {
18898                        let autoscroll = match scroll_offset {
18899                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
18900                            None => Autoscroll::newest(),
18901                        };
18902                        let nav_history = editor.nav_history.take();
18903                        editor.change_selections(Some(autoscroll), window, cx, |s| {
18904                            s.select_ranges(ranges);
18905                        });
18906                        editor.nav_history = nav_history;
18907                    });
18908                }
18909            })
18910        });
18911    }
18912
18913    // For now, don't allow opening excerpts in buffers that aren't backed by
18914    // regular project files.
18915    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
18916        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
18917    }
18918
18919    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
18920        let snapshot = self.buffer.read(cx).read(cx);
18921        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
18922        Some(
18923            ranges
18924                .iter()
18925                .map(move |range| {
18926                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
18927                })
18928                .collect(),
18929        )
18930    }
18931
18932    fn selection_replacement_ranges(
18933        &self,
18934        range: Range<OffsetUtf16>,
18935        cx: &mut App,
18936    ) -> Vec<Range<OffsetUtf16>> {
18937        let selections = self.selections.all::<OffsetUtf16>(cx);
18938        let newest_selection = selections
18939            .iter()
18940            .max_by_key(|selection| selection.id)
18941            .unwrap();
18942        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
18943        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
18944        let snapshot = self.buffer.read(cx).read(cx);
18945        selections
18946            .into_iter()
18947            .map(|mut selection| {
18948                selection.start.0 =
18949                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
18950                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
18951                snapshot.clip_offset_utf16(selection.start, Bias::Left)
18952                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
18953            })
18954            .collect()
18955    }
18956
18957    fn report_editor_event(
18958        &self,
18959        event_type: &'static str,
18960        file_extension: Option<String>,
18961        cx: &App,
18962    ) {
18963        if cfg!(any(test, feature = "test-support")) {
18964            return;
18965        }
18966
18967        let Some(project) = &self.project else { return };
18968
18969        // If None, we are in a file without an extension
18970        let file = self
18971            .buffer
18972            .read(cx)
18973            .as_singleton()
18974            .and_then(|b| b.read(cx).file());
18975        let file_extension = file_extension.or(file
18976            .as_ref()
18977            .and_then(|file| Path::new(file.file_name(cx)).extension())
18978            .and_then(|e| e.to_str())
18979            .map(|a| a.to_string()));
18980
18981        let vim_mode = vim_enabled(cx);
18982
18983        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
18984        let copilot_enabled = edit_predictions_provider
18985            == language::language_settings::EditPredictionProvider::Copilot;
18986        let copilot_enabled_for_language = self
18987            .buffer
18988            .read(cx)
18989            .language_settings(cx)
18990            .show_edit_predictions;
18991
18992        let project = project.read(cx);
18993        telemetry::event!(
18994            event_type,
18995            file_extension,
18996            vim_mode,
18997            copilot_enabled,
18998            copilot_enabled_for_language,
18999            edit_predictions_provider,
19000            is_via_ssh = project.is_via_ssh(),
19001        );
19002    }
19003
19004    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19005    /// with each line being an array of {text, highlight} objects.
19006    fn copy_highlight_json(
19007        &mut self,
19008        _: &CopyHighlightJson,
19009        window: &mut Window,
19010        cx: &mut Context<Self>,
19011    ) {
19012        #[derive(Serialize)]
19013        struct Chunk<'a> {
19014            text: String,
19015            highlight: Option<&'a str>,
19016        }
19017
19018        let snapshot = self.buffer.read(cx).snapshot(cx);
19019        let range = self
19020            .selected_text_range(false, window, cx)
19021            .and_then(|selection| {
19022                if selection.range.is_empty() {
19023                    None
19024                } else {
19025                    Some(selection.range)
19026                }
19027            })
19028            .unwrap_or_else(|| 0..snapshot.len());
19029
19030        let chunks = snapshot.chunks(range, true);
19031        let mut lines = Vec::new();
19032        let mut line: VecDeque<Chunk> = VecDeque::new();
19033
19034        let Some(style) = self.style.as_ref() else {
19035            return;
19036        };
19037
19038        for chunk in chunks {
19039            let highlight = chunk
19040                .syntax_highlight_id
19041                .and_then(|id| id.name(&style.syntax));
19042            let mut chunk_lines = chunk.text.split('\n').peekable();
19043            while let Some(text) = chunk_lines.next() {
19044                let mut merged_with_last_token = false;
19045                if let Some(last_token) = line.back_mut() {
19046                    if last_token.highlight == highlight {
19047                        last_token.text.push_str(text);
19048                        merged_with_last_token = true;
19049                    }
19050                }
19051
19052                if !merged_with_last_token {
19053                    line.push_back(Chunk {
19054                        text: text.into(),
19055                        highlight,
19056                    });
19057                }
19058
19059                if chunk_lines.peek().is_some() {
19060                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19061                        line.pop_front();
19062                    }
19063                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19064                        line.pop_back();
19065                    }
19066
19067                    lines.push(mem::take(&mut line));
19068                }
19069            }
19070        }
19071
19072        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19073            return;
19074        };
19075        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19076    }
19077
19078    pub fn open_context_menu(
19079        &mut self,
19080        _: &OpenContextMenu,
19081        window: &mut Window,
19082        cx: &mut Context<Self>,
19083    ) {
19084        self.request_autoscroll(Autoscroll::newest(), cx);
19085        let position = self.selections.newest_display(cx).start;
19086        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19087    }
19088
19089    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19090        &self.inlay_hint_cache
19091    }
19092
19093    pub fn replay_insert_event(
19094        &mut self,
19095        text: &str,
19096        relative_utf16_range: Option<Range<isize>>,
19097        window: &mut Window,
19098        cx: &mut Context<Self>,
19099    ) {
19100        if !self.input_enabled {
19101            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19102            return;
19103        }
19104        if let Some(relative_utf16_range) = relative_utf16_range {
19105            let selections = self.selections.all::<OffsetUtf16>(cx);
19106            self.change_selections(None, window, cx, |s| {
19107                let new_ranges = selections.into_iter().map(|range| {
19108                    let start = OffsetUtf16(
19109                        range
19110                            .head()
19111                            .0
19112                            .saturating_add_signed(relative_utf16_range.start),
19113                    );
19114                    let end = OffsetUtf16(
19115                        range
19116                            .head()
19117                            .0
19118                            .saturating_add_signed(relative_utf16_range.end),
19119                    );
19120                    start..end
19121                });
19122                s.select_ranges(new_ranges);
19123            });
19124        }
19125
19126        self.handle_input(text, window, cx);
19127    }
19128
19129    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19130        let Some(provider) = self.semantics_provider.as_ref() else {
19131            return false;
19132        };
19133
19134        let mut supports = false;
19135        self.buffer().update(cx, |this, cx| {
19136            this.for_each_buffer(|buffer| {
19137                supports |= provider.supports_inlay_hints(buffer, cx);
19138            });
19139        });
19140
19141        supports
19142    }
19143
19144    pub fn is_focused(&self, window: &Window) -> bool {
19145        self.focus_handle.is_focused(window)
19146    }
19147
19148    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19149        cx.emit(EditorEvent::Focused);
19150
19151        if let Some(descendant) = self
19152            .last_focused_descendant
19153            .take()
19154            .and_then(|descendant| descendant.upgrade())
19155        {
19156            window.focus(&descendant);
19157        } else {
19158            if let Some(blame) = self.blame.as_ref() {
19159                blame.update(cx, GitBlame::focus)
19160            }
19161
19162            self.blink_manager.update(cx, BlinkManager::enable);
19163            self.show_cursor_names(window, cx);
19164            self.buffer.update(cx, |buffer, cx| {
19165                buffer.finalize_last_transaction(cx);
19166                if self.leader_id.is_none() {
19167                    buffer.set_active_selections(
19168                        &self.selections.disjoint_anchors(),
19169                        self.selections.line_mode,
19170                        self.cursor_shape,
19171                        cx,
19172                    );
19173                }
19174            });
19175        }
19176    }
19177
19178    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19179        cx.emit(EditorEvent::FocusedIn)
19180    }
19181
19182    fn handle_focus_out(
19183        &mut self,
19184        event: FocusOutEvent,
19185        _window: &mut Window,
19186        cx: &mut Context<Self>,
19187    ) {
19188        if event.blurred != self.focus_handle {
19189            self.last_focused_descendant = Some(event.blurred);
19190        }
19191        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19192    }
19193
19194    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19195        self.blink_manager.update(cx, BlinkManager::disable);
19196        self.buffer
19197            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19198
19199        if let Some(blame) = self.blame.as_ref() {
19200            blame.update(cx, GitBlame::blur)
19201        }
19202        if !self.hover_state.focused(window, cx) {
19203            hide_hover(self, cx);
19204        }
19205        if !self
19206            .context_menu
19207            .borrow()
19208            .as_ref()
19209            .is_some_and(|context_menu| context_menu.focused(window, cx))
19210        {
19211            self.hide_context_menu(window, cx);
19212        }
19213        self.discard_inline_completion(false, cx);
19214        cx.emit(EditorEvent::Blurred);
19215        cx.notify();
19216    }
19217
19218    pub fn register_action<A: Action>(
19219        &mut self,
19220        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19221    ) -> Subscription {
19222        let id = self.next_editor_action_id.post_inc();
19223        let listener = Arc::new(listener);
19224        self.editor_actions.borrow_mut().insert(
19225            id,
19226            Box::new(move |window, _| {
19227                let listener = listener.clone();
19228                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19229                    let action = action.downcast_ref().unwrap();
19230                    if phase == DispatchPhase::Bubble {
19231                        listener(action, window, cx)
19232                    }
19233                })
19234            }),
19235        );
19236
19237        let editor_actions = self.editor_actions.clone();
19238        Subscription::new(move || {
19239            editor_actions.borrow_mut().remove(&id);
19240        })
19241    }
19242
19243    pub fn file_header_size(&self) -> u32 {
19244        FILE_HEADER_HEIGHT
19245    }
19246
19247    pub fn restore(
19248        &mut self,
19249        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19250        window: &mut Window,
19251        cx: &mut Context<Self>,
19252    ) {
19253        let workspace = self.workspace();
19254        let project = self.project.as_ref();
19255        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19256            let mut tasks = Vec::new();
19257            for (buffer_id, changes) in revert_changes {
19258                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19259                    buffer.update(cx, |buffer, cx| {
19260                        buffer.edit(
19261                            changes
19262                                .into_iter()
19263                                .map(|(range, text)| (range, text.to_string())),
19264                            None,
19265                            cx,
19266                        );
19267                    });
19268
19269                    if let Some(project) =
19270                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19271                    {
19272                        project.update(cx, |project, cx| {
19273                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19274                        })
19275                    }
19276                }
19277            }
19278            tasks
19279        });
19280        cx.spawn_in(window, async move |_, cx| {
19281            for (buffer, task) in save_tasks {
19282                let result = task.await;
19283                if result.is_err() {
19284                    let Some(path) = buffer
19285                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19286                        .ok()
19287                    else {
19288                        continue;
19289                    };
19290                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19291                        let Some(task) = cx
19292                            .update_window_entity(&workspace, |workspace, window, cx| {
19293                                workspace
19294                                    .open_path_preview(path, None, false, false, false, window, cx)
19295                            })
19296                            .ok()
19297                        else {
19298                            continue;
19299                        };
19300                        task.await.log_err();
19301                    }
19302                }
19303            }
19304        })
19305        .detach();
19306        self.change_selections(None, window, cx, |selections| selections.refresh());
19307    }
19308
19309    pub fn to_pixel_point(
19310        &self,
19311        source: multi_buffer::Anchor,
19312        editor_snapshot: &EditorSnapshot,
19313        window: &mut Window,
19314    ) -> Option<gpui::Point<Pixels>> {
19315        let source_point = source.to_display_point(editor_snapshot);
19316        self.display_to_pixel_point(source_point, editor_snapshot, window)
19317    }
19318
19319    pub fn display_to_pixel_point(
19320        &self,
19321        source: DisplayPoint,
19322        editor_snapshot: &EditorSnapshot,
19323        window: &mut Window,
19324    ) -> Option<gpui::Point<Pixels>> {
19325        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19326        let text_layout_details = self.text_layout_details(window);
19327        let scroll_top = text_layout_details
19328            .scroll_anchor
19329            .scroll_position(editor_snapshot)
19330            .y;
19331
19332        if source.row().as_f32() < scroll_top.floor() {
19333            return None;
19334        }
19335        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19336        let source_y = line_height * (source.row().as_f32() - scroll_top);
19337        Some(gpui::Point::new(source_x, source_y))
19338    }
19339
19340    pub fn has_visible_completions_menu(&self) -> bool {
19341        !self.edit_prediction_preview_is_active()
19342            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19343                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19344            })
19345    }
19346
19347    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19348        if self.mode.is_minimap() {
19349            return;
19350        }
19351        self.addons
19352            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19353    }
19354
19355    pub fn unregister_addon<T: Addon>(&mut self) {
19356        self.addons.remove(&std::any::TypeId::of::<T>());
19357    }
19358
19359    pub fn addon<T: Addon>(&self) -> Option<&T> {
19360        let type_id = std::any::TypeId::of::<T>();
19361        self.addons
19362            .get(&type_id)
19363            .and_then(|item| item.to_any().downcast_ref::<T>())
19364    }
19365
19366    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19367        let type_id = std::any::TypeId::of::<T>();
19368        self.addons
19369            .get_mut(&type_id)
19370            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19371    }
19372
19373    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19374        let text_layout_details = self.text_layout_details(window);
19375        let style = &text_layout_details.editor_style;
19376        let font_id = window.text_system().resolve_font(&style.text.font());
19377        let font_size = style.text.font_size.to_pixels(window.rem_size());
19378        let line_height = style.text.line_height_in_pixels(window.rem_size());
19379        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19380
19381        gpui::Size::new(em_width, line_height)
19382    }
19383
19384    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19385        self.load_diff_task.clone()
19386    }
19387
19388    fn read_metadata_from_db(
19389        &mut self,
19390        item_id: u64,
19391        workspace_id: WorkspaceId,
19392        window: &mut Window,
19393        cx: &mut Context<Editor>,
19394    ) {
19395        if self.is_singleton(cx)
19396            && !self.mode.is_minimap()
19397            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19398        {
19399            let buffer_snapshot = OnceCell::new();
19400
19401            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19402                if !folds.is_empty() {
19403                    let snapshot =
19404                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19405                    self.fold_ranges(
19406                        folds
19407                            .into_iter()
19408                            .map(|(start, end)| {
19409                                snapshot.clip_offset(start, Bias::Left)
19410                                    ..snapshot.clip_offset(end, Bias::Right)
19411                            })
19412                            .collect(),
19413                        false,
19414                        window,
19415                        cx,
19416                    );
19417                }
19418            }
19419
19420            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19421                if !selections.is_empty() {
19422                    let snapshot =
19423                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19424                    self.change_selections(None, window, cx, |s| {
19425                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19426                            snapshot.clip_offset(start, Bias::Left)
19427                                ..snapshot.clip_offset(end, Bias::Right)
19428                        }));
19429                    });
19430                }
19431            };
19432        }
19433
19434        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19435    }
19436}
19437
19438fn vim_enabled(cx: &App) -> bool {
19439    cx.global::<SettingsStore>()
19440        .raw_user_settings()
19441        .get("vim_mode")
19442        == Some(&serde_json::Value::Bool(true))
19443}
19444
19445// Consider user intent and default settings
19446fn choose_completion_range(
19447    completion: &Completion,
19448    intent: CompletionIntent,
19449    buffer: &Entity<Buffer>,
19450    cx: &mut Context<Editor>,
19451) -> Range<usize> {
19452    fn should_replace(
19453        completion: &Completion,
19454        insert_range: &Range<text::Anchor>,
19455        intent: CompletionIntent,
19456        completion_mode_setting: LspInsertMode,
19457        buffer: &Buffer,
19458    ) -> bool {
19459        // specific actions take precedence over settings
19460        match intent {
19461            CompletionIntent::CompleteWithInsert => return false,
19462            CompletionIntent::CompleteWithReplace => return true,
19463            CompletionIntent::Complete | CompletionIntent::Compose => {}
19464        }
19465
19466        match completion_mode_setting {
19467            LspInsertMode::Insert => false,
19468            LspInsertMode::Replace => true,
19469            LspInsertMode::ReplaceSubsequence => {
19470                let mut text_to_replace = buffer.chars_for_range(
19471                    buffer.anchor_before(completion.replace_range.start)
19472                        ..buffer.anchor_after(completion.replace_range.end),
19473                );
19474                let mut completion_text = completion.new_text.chars();
19475
19476                // is `text_to_replace` a subsequence of `completion_text`
19477                text_to_replace
19478                    .all(|needle_ch| completion_text.any(|haystack_ch| haystack_ch == needle_ch))
19479            }
19480            LspInsertMode::ReplaceSuffix => {
19481                let range_after_cursor = insert_range.end..completion.replace_range.end;
19482
19483                let text_after_cursor = buffer
19484                    .text_for_range(
19485                        buffer.anchor_before(range_after_cursor.start)
19486                            ..buffer.anchor_after(range_after_cursor.end),
19487                    )
19488                    .collect::<String>();
19489                completion.new_text.ends_with(&text_after_cursor)
19490            }
19491        }
19492    }
19493
19494    let buffer = buffer.read(cx);
19495
19496    if let CompletionSource::Lsp {
19497        insert_range: Some(insert_range),
19498        ..
19499    } = &completion.source
19500    {
19501        let completion_mode_setting =
19502            language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19503                .completions
19504                .lsp_insert_mode;
19505
19506        if !should_replace(
19507            completion,
19508            &insert_range,
19509            intent,
19510            completion_mode_setting,
19511            buffer,
19512        ) {
19513            return insert_range.to_offset(buffer);
19514        }
19515    }
19516
19517    completion.replace_range.to_offset(buffer)
19518}
19519
19520fn insert_extra_newline_brackets(
19521    buffer: &MultiBufferSnapshot,
19522    range: Range<usize>,
19523    language: &language::LanguageScope,
19524) -> bool {
19525    let leading_whitespace_len = buffer
19526        .reversed_chars_at(range.start)
19527        .take_while(|c| c.is_whitespace() && *c != '\n')
19528        .map(|c| c.len_utf8())
19529        .sum::<usize>();
19530    let trailing_whitespace_len = buffer
19531        .chars_at(range.end)
19532        .take_while(|c| c.is_whitespace() && *c != '\n')
19533        .map(|c| c.len_utf8())
19534        .sum::<usize>();
19535    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19536
19537    language.brackets().any(|(pair, enabled)| {
19538        let pair_start = pair.start.trim_end();
19539        let pair_end = pair.end.trim_start();
19540
19541        enabled
19542            && pair.newline
19543            && buffer.contains_str_at(range.end, pair_end)
19544            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19545    })
19546}
19547
19548fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19549    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19550        [(buffer, range, _)] => (*buffer, range.clone()),
19551        _ => return false,
19552    };
19553    let pair = {
19554        let mut result: Option<BracketMatch> = None;
19555
19556        for pair in buffer
19557            .all_bracket_ranges(range.clone())
19558            .filter(move |pair| {
19559                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19560            })
19561        {
19562            let len = pair.close_range.end - pair.open_range.start;
19563
19564            if let Some(existing) = &result {
19565                let existing_len = existing.close_range.end - existing.open_range.start;
19566                if len > existing_len {
19567                    continue;
19568                }
19569            }
19570
19571            result = Some(pair);
19572        }
19573
19574        result
19575    };
19576    let Some(pair) = pair else {
19577        return false;
19578    };
19579    pair.newline_only
19580        && buffer
19581            .chars_for_range(pair.open_range.end..range.start)
19582            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19583            .all(|c| c.is_whitespace() && c != '\n')
19584}
19585
19586fn update_uncommitted_diff_for_buffer(
19587    editor: Entity<Editor>,
19588    project: &Entity<Project>,
19589    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19590    buffer: Entity<MultiBuffer>,
19591    cx: &mut App,
19592) -> Task<()> {
19593    let mut tasks = Vec::new();
19594    project.update(cx, |project, cx| {
19595        for buffer in buffers {
19596            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19597                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19598            }
19599        }
19600    });
19601    cx.spawn(async move |cx| {
19602        let diffs = future::join_all(tasks).await;
19603        if editor
19604            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19605            .unwrap_or(false)
19606        {
19607            return;
19608        }
19609
19610        buffer
19611            .update(cx, |buffer, cx| {
19612                for diff in diffs.into_iter().flatten() {
19613                    buffer.add_diff(diff, cx);
19614                }
19615            })
19616            .ok();
19617    })
19618}
19619
19620fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
19621    let tab_size = tab_size.get() as usize;
19622    let mut width = offset;
19623
19624    for ch in text.chars() {
19625        width += if ch == '\t' {
19626            tab_size - (width % tab_size)
19627        } else {
19628            1
19629        };
19630    }
19631
19632    width - offset
19633}
19634
19635#[cfg(test)]
19636mod tests {
19637    use super::*;
19638
19639    #[test]
19640    fn test_string_size_with_expanded_tabs() {
19641        let nz = |val| NonZeroU32::new(val).unwrap();
19642        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
19643        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
19644        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
19645        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
19646        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
19647        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
19648        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
19649        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
19650    }
19651}
19652
19653/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
19654struct WordBreakingTokenizer<'a> {
19655    input: &'a str,
19656}
19657
19658impl<'a> WordBreakingTokenizer<'a> {
19659    fn new(input: &'a str) -> Self {
19660        Self { input }
19661    }
19662}
19663
19664fn is_char_ideographic(ch: char) -> bool {
19665    use unicode_script::Script::*;
19666    use unicode_script::UnicodeScript;
19667    matches!(ch.script(), Han | Tangut | Yi)
19668}
19669
19670fn is_grapheme_ideographic(text: &str) -> bool {
19671    text.chars().any(is_char_ideographic)
19672}
19673
19674fn is_grapheme_whitespace(text: &str) -> bool {
19675    text.chars().any(|x| x.is_whitespace())
19676}
19677
19678fn should_stay_with_preceding_ideograph(text: &str) -> bool {
19679    text.chars().next().map_or(false, |ch| {
19680        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
19681    })
19682}
19683
19684#[derive(PartialEq, Eq, Debug, Clone, Copy)]
19685enum WordBreakToken<'a> {
19686    Word { token: &'a str, grapheme_len: usize },
19687    InlineWhitespace { token: &'a str, grapheme_len: usize },
19688    Newline,
19689}
19690
19691impl<'a> Iterator for WordBreakingTokenizer<'a> {
19692    /// Yields a span, the count of graphemes in the token, and whether it was
19693    /// whitespace. Note that it also breaks at word boundaries.
19694    type Item = WordBreakToken<'a>;
19695
19696    fn next(&mut self) -> Option<Self::Item> {
19697        use unicode_segmentation::UnicodeSegmentation;
19698        if self.input.is_empty() {
19699            return None;
19700        }
19701
19702        let mut iter = self.input.graphemes(true).peekable();
19703        let mut offset = 0;
19704        let mut grapheme_len = 0;
19705        if let Some(first_grapheme) = iter.next() {
19706            let is_newline = first_grapheme == "\n";
19707            let is_whitespace = is_grapheme_whitespace(first_grapheme);
19708            offset += first_grapheme.len();
19709            grapheme_len += 1;
19710            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
19711                if let Some(grapheme) = iter.peek().copied() {
19712                    if should_stay_with_preceding_ideograph(grapheme) {
19713                        offset += grapheme.len();
19714                        grapheme_len += 1;
19715                    }
19716                }
19717            } else {
19718                let mut words = self.input[offset..].split_word_bound_indices().peekable();
19719                let mut next_word_bound = words.peek().copied();
19720                if next_word_bound.map_or(false, |(i, _)| i == 0) {
19721                    next_word_bound = words.next();
19722                }
19723                while let Some(grapheme) = iter.peek().copied() {
19724                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
19725                        break;
19726                    };
19727                    if is_grapheme_whitespace(grapheme) != is_whitespace
19728                        || (grapheme == "\n") != is_newline
19729                    {
19730                        break;
19731                    };
19732                    offset += grapheme.len();
19733                    grapheme_len += 1;
19734                    iter.next();
19735                }
19736            }
19737            let token = &self.input[..offset];
19738            self.input = &self.input[offset..];
19739            if token == "\n" {
19740                Some(WordBreakToken::Newline)
19741            } else if is_whitespace {
19742                Some(WordBreakToken::InlineWhitespace {
19743                    token,
19744                    grapheme_len,
19745                })
19746            } else {
19747                Some(WordBreakToken::Word {
19748                    token,
19749                    grapheme_len,
19750                })
19751            }
19752        } else {
19753            None
19754        }
19755    }
19756}
19757
19758#[test]
19759fn test_word_breaking_tokenizer() {
19760    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
19761        ("", &[]),
19762        ("  ", &[whitespace("  ", 2)]),
19763        ("Ʒ", &[word("Ʒ", 1)]),
19764        ("Ǽ", &[word("Ǽ", 1)]),
19765        ("", &[word("", 1)]),
19766        ("⋑⋑", &[word("⋑⋑", 2)]),
19767        (
19768            "原理,进而",
19769            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
19770        ),
19771        (
19772            "hello world",
19773            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
19774        ),
19775        (
19776            "hello, world",
19777            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
19778        ),
19779        (
19780            "  hello world",
19781            &[
19782                whitespace("  ", 2),
19783                word("hello", 5),
19784                whitespace(" ", 1),
19785                word("world", 5),
19786            ],
19787        ),
19788        (
19789            "这是什么 \n 钢笔",
19790            &[
19791                word("", 1),
19792                word("", 1),
19793                word("", 1),
19794                word("", 1),
19795                whitespace(" ", 1),
19796                newline(),
19797                whitespace(" ", 1),
19798                word("", 1),
19799                word("", 1),
19800            ],
19801        ),
19802        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
19803    ];
19804
19805    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19806        WordBreakToken::Word {
19807            token,
19808            grapheme_len,
19809        }
19810    }
19811
19812    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
19813        WordBreakToken::InlineWhitespace {
19814            token,
19815            grapheme_len,
19816        }
19817    }
19818
19819    fn newline() -> WordBreakToken<'static> {
19820        WordBreakToken::Newline
19821    }
19822
19823    for (input, result) in tests {
19824        assert_eq!(
19825            WordBreakingTokenizer::new(input)
19826                .collect::<Vec<_>>()
19827                .as_slice(),
19828            *result,
19829        );
19830    }
19831}
19832
19833fn wrap_with_prefix(
19834    line_prefix: String,
19835    unwrapped_text: String,
19836    wrap_column: usize,
19837    tab_size: NonZeroU32,
19838    preserve_existing_whitespace: bool,
19839) -> String {
19840    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
19841    let mut wrapped_text = String::new();
19842    let mut current_line = line_prefix.clone();
19843
19844    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
19845    let mut current_line_len = line_prefix_len;
19846    let mut in_whitespace = false;
19847    for token in tokenizer {
19848        let have_preceding_whitespace = in_whitespace;
19849        match token {
19850            WordBreakToken::Word {
19851                token,
19852                grapheme_len,
19853            } => {
19854                in_whitespace = false;
19855                if current_line_len + grapheme_len > wrap_column
19856                    && current_line_len != line_prefix_len
19857                {
19858                    wrapped_text.push_str(current_line.trim_end());
19859                    wrapped_text.push('\n');
19860                    current_line.truncate(line_prefix.len());
19861                    current_line_len = line_prefix_len;
19862                }
19863                current_line.push_str(token);
19864                current_line_len += grapheme_len;
19865            }
19866            WordBreakToken::InlineWhitespace {
19867                mut token,
19868                mut grapheme_len,
19869            } => {
19870                in_whitespace = true;
19871                if have_preceding_whitespace && !preserve_existing_whitespace {
19872                    continue;
19873                }
19874                if !preserve_existing_whitespace {
19875                    token = " ";
19876                    grapheme_len = 1;
19877                }
19878                if current_line_len + grapheme_len > wrap_column {
19879                    wrapped_text.push_str(current_line.trim_end());
19880                    wrapped_text.push('\n');
19881                    current_line.truncate(line_prefix.len());
19882                    current_line_len = line_prefix_len;
19883                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
19884                    current_line.push_str(token);
19885                    current_line_len += grapheme_len;
19886                }
19887            }
19888            WordBreakToken::Newline => {
19889                in_whitespace = true;
19890                if preserve_existing_whitespace {
19891                    wrapped_text.push_str(current_line.trim_end());
19892                    wrapped_text.push('\n');
19893                    current_line.truncate(line_prefix.len());
19894                    current_line_len = line_prefix_len;
19895                } else if have_preceding_whitespace {
19896                    continue;
19897                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
19898                {
19899                    wrapped_text.push_str(current_line.trim_end());
19900                    wrapped_text.push('\n');
19901                    current_line.truncate(line_prefix.len());
19902                    current_line_len = line_prefix_len;
19903                } else if current_line_len != line_prefix_len {
19904                    current_line.push(' ');
19905                    current_line_len += 1;
19906                }
19907            }
19908        }
19909    }
19910
19911    if !current_line.is_empty() {
19912        wrapped_text.push_str(&current_line);
19913    }
19914    wrapped_text
19915}
19916
19917#[test]
19918fn test_wrap_with_prefix() {
19919    assert_eq!(
19920        wrap_with_prefix(
19921            "# ".to_string(),
19922            "abcdefg".to_string(),
19923            4,
19924            NonZeroU32::new(4).unwrap(),
19925            false,
19926        ),
19927        "# abcdefg"
19928    );
19929    assert_eq!(
19930        wrap_with_prefix(
19931            "".to_string(),
19932            "\thello world".to_string(),
19933            8,
19934            NonZeroU32::new(4).unwrap(),
19935            false,
19936        ),
19937        "hello\nworld"
19938    );
19939    assert_eq!(
19940        wrap_with_prefix(
19941            "// ".to_string(),
19942            "xx \nyy zz aa bb cc".to_string(),
19943            12,
19944            NonZeroU32::new(4).unwrap(),
19945            false,
19946        ),
19947        "// xx yy zz\n// aa bb cc"
19948    );
19949    assert_eq!(
19950        wrap_with_prefix(
19951            String::new(),
19952            "这是什么 \n 钢笔".to_string(),
19953            3,
19954            NonZeroU32::new(4).unwrap(),
19955            false,
19956        ),
19957        "这是什\n么 钢\n"
19958    );
19959}
19960
19961pub trait CollaborationHub {
19962    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
19963    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
19964    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
19965}
19966
19967impl CollaborationHub for Entity<Project> {
19968    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
19969        self.read(cx).collaborators()
19970    }
19971
19972    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
19973        self.read(cx).user_store().read(cx).participant_indices()
19974    }
19975
19976    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
19977        let this = self.read(cx);
19978        let user_ids = this.collaborators().values().map(|c| c.user_id);
19979        this.user_store().read(cx).participant_names(user_ids, cx)
19980    }
19981}
19982
19983pub trait SemanticsProvider {
19984    fn hover(
19985        &self,
19986        buffer: &Entity<Buffer>,
19987        position: text::Anchor,
19988        cx: &mut App,
19989    ) -> Option<Task<Vec<project::Hover>>>;
19990
19991    fn inline_values(
19992        &self,
19993        buffer_handle: Entity<Buffer>,
19994        range: Range<text::Anchor>,
19995        cx: &mut App,
19996    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
19997
19998    fn inlay_hints(
19999        &self,
20000        buffer_handle: Entity<Buffer>,
20001        range: Range<text::Anchor>,
20002        cx: &mut App,
20003    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20004
20005    fn resolve_inlay_hint(
20006        &self,
20007        hint: InlayHint,
20008        buffer_handle: Entity<Buffer>,
20009        server_id: LanguageServerId,
20010        cx: &mut App,
20011    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20012
20013    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20014
20015    fn document_highlights(
20016        &self,
20017        buffer: &Entity<Buffer>,
20018        position: text::Anchor,
20019        cx: &mut App,
20020    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20021
20022    fn definitions(
20023        &self,
20024        buffer: &Entity<Buffer>,
20025        position: text::Anchor,
20026        kind: GotoDefinitionKind,
20027        cx: &mut App,
20028    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20029
20030    fn range_for_rename(
20031        &self,
20032        buffer: &Entity<Buffer>,
20033        position: text::Anchor,
20034        cx: &mut App,
20035    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20036
20037    fn perform_rename(
20038        &self,
20039        buffer: &Entity<Buffer>,
20040        position: text::Anchor,
20041        new_name: String,
20042        cx: &mut App,
20043    ) -> Option<Task<Result<ProjectTransaction>>>;
20044}
20045
20046pub trait CompletionProvider {
20047    fn completions(
20048        &self,
20049        excerpt_id: ExcerptId,
20050        buffer: &Entity<Buffer>,
20051        buffer_position: text::Anchor,
20052        trigger: CompletionContext,
20053        window: &mut Window,
20054        cx: &mut Context<Editor>,
20055    ) -> Task<Result<Option<Vec<Completion>>>>;
20056
20057    fn resolve_completions(
20058        &self,
20059        buffer: Entity<Buffer>,
20060        completion_indices: Vec<usize>,
20061        completions: Rc<RefCell<Box<[Completion]>>>,
20062        cx: &mut Context<Editor>,
20063    ) -> Task<Result<bool>>;
20064
20065    fn apply_additional_edits_for_completion(
20066        &self,
20067        _buffer: Entity<Buffer>,
20068        _completions: Rc<RefCell<Box<[Completion]>>>,
20069        _completion_index: usize,
20070        _push_to_history: bool,
20071        _cx: &mut Context<Editor>,
20072    ) -> Task<Result<Option<language::Transaction>>> {
20073        Task::ready(Ok(None))
20074    }
20075
20076    fn is_completion_trigger(
20077        &self,
20078        buffer: &Entity<Buffer>,
20079        position: language::Anchor,
20080        text: &str,
20081        trigger_in_words: bool,
20082        cx: &mut Context<Editor>,
20083    ) -> bool;
20084
20085    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20086
20087    fn sort_completions(&self) -> bool {
20088        true
20089    }
20090
20091    fn filter_completions(&self) -> bool {
20092        true
20093    }
20094}
20095
20096pub trait CodeActionProvider {
20097    fn id(&self) -> Arc<str>;
20098
20099    fn code_actions(
20100        &self,
20101        buffer: &Entity<Buffer>,
20102        range: Range<text::Anchor>,
20103        window: &mut Window,
20104        cx: &mut App,
20105    ) -> Task<Result<Vec<CodeAction>>>;
20106
20107    fn apply_code_action(
20108        &self,
20109        buffer_handle: Entity<Buffer>,
20110        action: CodeAction,
20111        excerpt_id: ExcerptId,
20112        push_to_history: bool,
20113        window: &mut Window,
20114        cx: &mut App,
20115    ) -> Task<Result<ProjectTransaction>>;
20116}
20117
20118impl CodeActionProvider for Entity<Project> {
20119    fn id(&self) -> Arc<str> {
20120        "project".into()
20121    }
20122
20123    fn code_actions(
20124        &self,
20125        buffer: &Entity<Buffer>,
20126        range: Range<text::Anchor>,
20127        _window: &mut Window,
20128        cx: &mut App,
20129    ) -> Task<Result<Vec<CodeAction>>> {
20130        self.update(cx, |project, cx| {
20131            let code_lens = project.code_lens(buffer, range.clone(), cx);
20132            let code_actions = project.code_actions(buffer, range, None, cx);
20133            cx.background_spawn(async move {
20134                let (code_lens, code_actions) = join(code_lens, code_actions).await;
20135                Ok(code_lens
20136                    .context("code lens fetch")?
20137                    .into_iter()
20138                    .chain(code_actions.context("code action fetch")?)
20139                    .collect())
20140            })
20141        })
20142    }
20143
20144    fn apply_code_action(
20145        &self,
20146        buffer_handle: Entity<Buffer>,
20147        action: CodeAction,
20148        _excerpt_id: ExcerptId,
20149        push_to_history: bool,
20150        _window: &mut Window,
20151        cx: &mut App,
20152    ) -> Task<Result<ProjectTransaction>> {
20153        self.update(cx, |project, cx| {
20154            project.apply_code_action(buffer_handle, action, push_to_history, cx)
20155        })
20156    }
20157}
20158
20159fn snippet_completions(
20160    project: &Project,
20161    buffer: &Entity<Buffer>,
20162    buffer_position: text::Anchor,
20163    cx: &mut App,
20164) -> Task<Result<Vec<Completion>>> {
20165    let languages = buffer.read(cx).languages_at(buffer_position);
20166    let snippet_store = project.snippets().read(cx);
20167
20168    let scopes: Vec<_> = languages
20169        .iter()
20170        .filter_map(|language| {
20171            let language_name = language.lsp_id();
20172            let snippets = snippet_store.snippets_for(Some(language_name), cx);
20173
20174            if snippets.is_empty() {
20175                None
20176            } else {
20177                Some((language.default_scope(), snippets))
20178            }
20179        })
20180        .collect();
20181
20182    if scopes.is_empty() {
20183        return Task::ready(Ok(vec![]));
20184    }
20185
20186    let snapshot = buffer.read(cx).text_snapshot();
20187    let chars: String = snapshot
20188        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
20189        .collect();
20190    let executor = cx.background_executor().clone();
20191
20192    cx.background_spawn(async move {
20193        let mut all_results: Vec<Completion> = Vec::new();
20194        for (scope, snippets) in scopes.into_iter() {
20195            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
20196            let mut last_word = chars
20197                .chars()
20198                .take_while(|c| classifier.is_word(*c))
20199                .collect::<String>();
20200            last_word = last_word.chars().rev().collect();
20201
20202            if last_word.is_empty() {
20203                return Ok(vec![]);
20204            }
20205
20206            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
20207            let to_lsp = |point: &text::Anchor| {
20208                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
20209                point_to_lsp(end)
20210            };
20211            let lsp_end = to_lsp(&buffer_position);
20212
20213            let candidates = snippets
20214                .iter()
20215                .enumerate()
20216                .flat_map(|(ix, snippet)| {
20217                    snippet
20218                        .prefix
20219                        .iter()
20220                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
20221                })
20222                .collect::<Vec<StringMatchCandidate>>();
20223
20224            let mut matches = fuzzy::match_strings(
20225                &candidates,
20226                &last_word,
20227                last_word.chars().any(|c| c.is_uppercase()),
20228                100,
20229                &Default::default(),
20230                executor.clone(),
20231            )
20232            .await;
20233
20234            // Remove all candidates where the query's start does not match the start of any word in the candidate
20235            if let Some(query_start) = last_word.chars().next() {
20236                matches.retain(|string_match| {
20237                    split_words(&string_match.string).any(|word| {
20238                        // Check that the first codepoint of the word as lowercase matches the first
20239                        // codepoint of the query as lowercase
20240                        word.chars()
20241                            .flat_map(|codepoint| codepoint.to_lowercase())
20242                            .zip(query_start.to_lowercase())
20243                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20244                    })
20245                });
20246            }
20247
20248            let matched_strings = matches
20249                .into_iter()
20250                .map(|m| m.string)
20251                .collect::<HashSet<_>>();
20252
20253            let mut result: Vec<Completion> = snippets
20254                .iter()
20255                .filter_map(|snippet| {
20256                    let matching_prefix = snippet
20257                        .prefix
20258                        .iter()
20259                        .find(|prefix| matched_strings.contains(*prefix))?;
20260                    let start = as_offset - last_word.len();
20261                    let start = snapshot.anchor_before(start);
20262                    let range = start..buffer_position;
20263                    let lsp_start = to_lsp(&start);
20264                    let lsp_range = lsp::Range {
20265                        start: lsp_start,
20266                        end: lsp_end,
20267                    };
20268                    Some(Completion {
20269                        replace_range: range,
20270                        new_text: snippet.body.clone(),
20271                        source: CompletionSource::Lsp {
20272                            insert_range: None,
20273                            server_id: LanguageServerId(usize::MAX),
20274                            resolved: true,
20275                            lsp_completion: Box::new(lsp::CompletionItem {
20276                                label: snippet.prefix.first().unwrap().clone(),
20277                                kind: Some(CompletionItemKind::SNIPPET),
20278                                label_details: snippet.description.as_ref().map(|description| {
20279                                    lsp::CompletionItemLabelDetails {
20280                                        detail: Some(description.clone()),
20281                                        description: None,
20282                                    }
20283                                }),
20284                                insert_text_format: Some(InsertTextFormat::SNIPPET),
20285                                text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20286                                    lsp::InsertReplaceEdit {
20287                                        new_text: snippet.body.clone(),
20288                                        insert: lsp_range,
20289                                        replace: lsp_range,
20290                                    },
20291                                )),
20292                                filter_text: Some(snippet.body.clone()),
20293                                sort_text: Some(char::MAX.to_string()),
20294                                ..lsp::CompletionItem::default()
20295                            }),
20296                            lsp_defaults: None,
20297                        },
20298                        label: CodeLabel {
20299                            text: matching_prefix.clone(),
20300                            runs: Vec::new(),
20301                            filter_range: 0..matching_prefix.len(),
20302                        },
20303                        icon_path: None,
20304                        documentation: Some(
20305                            CompletionDocumentation::SingleLineAndMultiLinePlainText {
20306                                single_line: snippet.name.clone().into(),
20307                                plain_text: snippet
20308                                    .description
20309                                    .clone()
20310                                    .map(|description| description.into()),
20311                            },
20312                        ),
20313                        insert_text_mode: None,
20314                        confirm: None,
20315                    })
20316                })
20317                .collect();
20318
20319            all_results.append(&mut result);
20320        }
20321
20322        Ok(all_results)
20323    })
20324}
20325
20326impl CompletionProvider for Entity<Project> {
20327    fn completions(
20328        &self,
20329        _excerpt_id: ExcerptId,
20330        buffer: &Entity<Buffer>,
20331        buffer_position: text::Anchor,
20332        options: CompletionContext,
20333        _window: &mut Window,
20334        cx: &mut Context<Editor>,
20335    ) -> Task<Result<Option<Vec<Completion>>>> {
20336        self.update(cx, |project, cx| {
20337            let snippets = snippet_completions(project, buffer, buffer_position, cx);
20338            let project_completions = project.completions(buffer, buffer_position, options, cx);
20339            cx.background_spawn(async move {
20340                let snippets_completions = snippets.await?;
20341                match project_completions.await? {
20342                    Some(mut completions) => {
20343                        completions.extend(snippets_completions);
20344                        Ok(Some(completions))
20345                    }
20346                    None => {
20347                        if snippets_completions.is_empty() {
20348                            Ok(None)
20349                        } else {
20350                            Ok(Some(snippets_completions))
20351                        }
20352                    }
20353                }
20354            })
20355        })
20356    }
20357
20358    fn resolve_completions(
20359        &self,
20360        buffer: Entity<Buffer>,
20361        completion_indices: Vec<usize>,
20362        completions: Rc<RefCell<Box<[Completion]>>>,
20363        cx: &mut Context<Editor>,
20364    ) -> Task<Result<bool>> {
20365        self.update(cx, |project, cx| {
20366            project.lsp_store().update(cx, |lsp_store, cx| {
20367                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
20368            })
20369        })
20370    }
20371
20372    fn apply_additional_edits_for_completion(
20373        &self,
20374        buffer: Entity<Buffer>,
20375        completions: Rc<RefCell<Box<[Completion]>>>,
20376        completion_index: usize,
20377        push_to_history: bool,
20378        cx: &mut Context<Editor>,
20379    ) -> Task<Result<Option<language::Transaction>>> {
20380        self.update(cx, |project, cx| {
20381            project.lsp_store().update(cx, |lsp_store, cx| {
20382                lsp_store.apply_additional_edits_for_completion(
20383                    buffer,
20384                    completions,
20385                    completion_index,
20386                    push_to_history,
20387                    cx,
20388                )
20389            })
20390        })
20391    }
20392
20393    fn is_completion_trigger(
20394        &self,
20395        buffer: &Entity<Buffer>,
20396        position: language::Anchor,
20397        text: &str,
20398        trigger_in_words: bool,
20399        cx: &mut Context<Editor>,
20400    ) -> bool {
20401        let mut chars = text.chars();
20402        let char = if let Some(char) = chars.next() {
20403            char
20404        } else {
20405            return false;
20406        };
20407        if chars.next().is_some() {
20408            return false;
20409        }
20410
20411        let buffer = buffer.read(cx);
20412        let snapshot = buffer.snapshot();
20413        if !snapshot.settings_at(position, cx).show_completions_on_input {
20414            return false;
20415        }
20416        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20417        if trigger_in_words && classifier.is_word(char) {
20418            return true;
20419        }
20420
20421        buffer.completion_triggers().contains(text)
20422    }
20423}
20424
20425impl SemanticsProvider for Entity<Project> {
20426    fn hover(
20427        &self,
20428        buffer: &Entity<Buffer>,
20429        position: text::Anchor,
20430        cx: &mut App,
20431    ) -> Option<Task<Vec<project::Hover>>> {
20432        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20433    }
20434
20435    fn document_highlights(
20436        &self,
20437        buffer: &Entity<Buffer>,
20438        position: text::Anchor,
20439        cx: &mut App,
20440    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20441        Some(self.update(cx, |project, cx| {
20442            project.document_highlights(buffer, position, cx)
20443        }))
20444    }
20445
20446    fn definitions(
20447        &self,
20448        buffer: &Entity<Buffer>,
20449        position: text::Anchor,
20450        kind: GotoDefinitionKind,
20451        cx: &mut App,
20452    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20453        Some(self.update(cx, |project, cx| match kind {
20454            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20455            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20456            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20457            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20458        }))
20459    }
20460
20461    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20462        // TODO: make this work for remote projects
20463        self.update(cx, |project, cx| {
20464            if project
20465                .active_debug_session(cx)
20466                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20467            {
20468                return true;
20469            }
20470
20471            buffer.update(cx, |buffer, cx| {
20472                project.any_language_server_supports_inlay_hints(buffer, cx)
20473            })
20474        })
20475    }
20476
20477    fn inline_values(
20478        &self,
20479        buffer_handle: Entity<Buffer>,
20480
20481        range: Range<text::Anchor>,
20482        cx: &mut App,
20483    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20484        self.update(cx, |project, cx| {
20485            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20486
20487            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20488        })
20489    }
20490
20491    fn inlay_hints(
20492        &self,
20493        buffer_handle: Entity<Buffer>,
20494        range: Range<text::Anchor>,
20495        cx: &mut App,
20496    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20497        Some(self.update(cx, |project, cx| {
20498            project.inlay_hints(buffer_handle, range, cx)
20499        }))
20500    }
20501
20502    fn resolve_inlay_hint(
20503        &self,
20504        hint: InlayHint,
20505        buffer_handle: Entity<Buffer>,
20506        server_id: LanguageServerId,
20507        cx: &mut App,
20508    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20509        Some(self.update(cx, |project, cx| {
20510            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20511        }))
20512    }
20513
20514    fn range_for_rename(
20515        &self,
20516        buffer: &Entity<Buffer>,
20517        position: text::Anchor,
20518        cx: &mut App,
20519    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20520        Some(self.update(cx, |project, cx| {
20521            let buffer = buffer.clone();
20522            let task = project.prepare_rename(buffer.clone(), position, cx);
20523            cx.spawn(async move |_, cx| {
20524                Ok(match task.await? {
20525                    PrepareRenameResponse::Success(range) => Some(range),
20526                    PrepareRenameResponse::InvalidPosition => None,
20527                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20528                        // Fallback on using TreeSitter info to determine identifier range
20529                        buffer.read_with(cx, |buffer, _| {
20530                            let snapshot = buffer.snapshot();
20531                            let (range, kind) = snapshot.surrounding_word(position);
20532                            if kind != Some(CharKind::Word) {
20533                                return None;
20534                            }
20535                            Some(
20536                                snapshot.anchor_before(range.start)
20537                                    ..snapshot.anchor_after(range.end),
20538                            )
20539                        })?
20540                    }
20541                })
20542            })
20543        }))
20544    }
20545
20546    fn perform_rename(
20547        &self,
20548        buffer: &Entity<Buffer>,
20549        position: text::Anchor,
20550        new_name: String,
20551        cx: &mut App,
20552    ) -> Option<Task<Result<ProjectTransaction>>> {
20553        Some(self.update(cx, |project, cx| {
20554            project.perform_rename(buffer.clone(), position, new_name, cx)
20555        }))
20556    }
20557}
20558
20559fn inlay_hint_settings(
20560    location: Anchor,
20561    snapshot: &MultiBufferSnapshot,
20562    cx: &mut Context<Editor>,
20563) -> InlayHintSettings {
20564    let file = snapshot.file_at(location);
20565    let language = snapshot.language_at(location).map(|l| l.name());
20566    language_settings(language, file, cx).inlay_hints
20567}
20568
20569fn consume_contiguous_rows(
20570    contiguous_row_selections: &mut Vec<Selection<Point>>,
20571    selection: &Selection<Point>,
20572    display_map: &DisplaySnapshot,
20573    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20574) -> (MultiBufferRow, MultiBufferRow) {
20575    contiguous_row_selections.push(selection.clone());
20576    let start_row = MultiBufferRow(selection.start.row);
20577    let mut end_row = ending_row(selection, display_map);
20578
20579    while let Some(next_selection) = selections.peek() {
20580        if next_selection.start.row <= end_row.0 {
20581            end_row = ending_row(next_selection, display_map);
20582            contiguous_row_selections.push(selections.next().unwrap().clone());
20583        } else {
20584            break;
20585        }
20586    }
20587    (start_row, end_row)
20588}
20589
20590fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20591    if next_selection.end.column > 0 || next_selection.is_empty() {
20592        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20593    } else {
20594        MultiBufferRow(next_selection.end.row)
20595    }
20596}
20597
20598impl EditorSnapshot {
20599    pub fn remote_selections_in_range<'a>(
20600        &'a self,
20601        range: &'a Range<Anchor>,
20602        collaboration_hub: &dyn CollaborationHub,
20603        cx: &'a App,
20604    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20605        let participant_names = collaboration_hub.user_names(cx);
20606        let participant_indices = collaboration_hub.user_participant_indices(cx);
20607        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20608        let collaborators_by_replica_id = collaborators_by_peer_id
20609            .values()
20610            .map(|collaborator| (collaborator.replica_id, collaborator))
20611            .collect::<HashMap<_, _>>();
20612        self.buffer_snapshot
20613            .selections_in_range(range, false)
20614            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20615                if replica_id == AGENT_REPLICA_ID {
20616                    Some(RemoteSelection {
20617                        replica_id,
20618                        selection,
20619                        cursor_shape,
20620                        line_mode,
20621                        collaborator_id: CollaboratorId::Agent,
20622                        user_name: Some("Agent".into()),
20623                        color: cx.theme().players().agent(),
20624                    })
20625                } else {
20626                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20627                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20628                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20629                    Some(RemoteSelection {
20630                        replica_id,
20631                        selection,
20632                        cursor_shape,
20633                        line_mode,
20634                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20635                        user_name,
20636                        color: if let Some(index) = participant_index {
20637                            cx.theme().players().color_for_participant(index.0)
20638                        } else {
20639                            cx.theme().players().absent()
20640                        },
20641                    })
20642                }
20643            })
20644    }
20645
20646    pub fn hunks_for_ranges(
20647        &self,
20648        ranges: impl IntoIterator<Item = Range<Point>>,
20649    ) -> Vec<MultiBufferDiffHunk> {
20650        let mut hunks = Vec::new();
20651        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20652            HashMap::default();
20653        for query_range in ranges {
20654            let query_rows =
20655                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20656            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20657                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20658            ) {
20659                // Include deleted hunks that are adjacent to the query range, because
20660                // otherwise they would be missed.
20661                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20662                if hunk.status().is_deleted() {
20663                    intersects_range |= hunk.row_range.start == query_rows.end;
20664                    intersects_range |= hunk.row_range.end == query_rows.start;
20665                }
20666                if intersects_range {
20667                    if !processed_buffer_rows
20668                        .entry(hunk.buffer_id)
20669                        .or_default()
20670                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20671                    {
20672                        continue;
20673                    }
20674                    hunks.push(hunk);
20675                }
20676            }
20677        }
20678
20679        hunks
20680    }
20681
20682    fn display_diff_hunks_for_rows<'a>(
20683        &'a self,
20684        display_rows: Range<DisplayRow>,
20685        folded_buffers: &'a HashSet<BufferId>,
20686    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20687        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20688        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20689
20690        self.buffer_snapshot
20691            .diff_hunks_in_range(buffer_start..buffer_end)
20692            .filter_map(|hunk| {
20693                if folded_buffers.contains(&hunk.buffer_id) {
20694                    return None;
20695                }
20696
20697                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20698                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20699
20700                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20701                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20702
20703                let display_hunk = if hunk_display_start.column() != 0 {
20704                    DisplayDiffHunk::Folded {
20705                        display_row: hunk_display_start.row(),
20706                    }
20707                } else {
20708                    let mut end_row = hunk_display_end.row();
20709                    if hunk_display_end.column() > 0 {
20710                        end_row.0 += 1;
20711                    }
20712                    let is_created_file = hunk.is_created_file();
20713                    DisplayDiffHunk::Unfolded {
20714                        status: hunk.status(),
20715                        diff_base_byte_range: hunk.diff_base_byte_range,
20716                        display_row_range: hunk_display_start.row()..end_row,
20717                        multi_buffer_range: Anchor::range_in_buffer(
20718                            hunk.excerpt_id,
20719                            hunk.buffer_id,
20720                            hunk.buffer_range,
20721                        ),
20722                        is_created_file,
20723                    }
20724                };
20725
20726                Some(display_hunk)
20727            })
20728    }
20729
20730    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20731        self.display_snapshot.buffer_snapshot.language_at(position)
20732    }
20733
20734    pub fn is_focused(&self) -> bool {
20735        self.is_focused
20736    }
20737
20738    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20739        self.placeholder_text.as_ref()
20740    }
20741
20742    pub fn scroll_position(&self) -> gpui::Point<f32> {
20743        self.scroll_anchor.scroll_position(&self.display_snapshot)
20744    }
20745
20746    fn gutter_dimensions(
20747        &self,
20748        font_id: FontId,
20749        font_size: Pixels,
20750        max_line_number_width: Pixels,
20751        cx: &App,
20752    ) -> Option<GutterDimensions> {
20753        if !self.show_gutter {
20754            return None;
20755        }
20756
20757        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
20758        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
20759
20760        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
20761            matches!(
20762                ProjectSettings::get_global(cx).git.git_gutter,
20763                Some(GitGutterSetting::TrackedFiles)
20764            )
20765        });
20766        let gutter_settings = EditorSettings::get_global(cx).gutter;
20767        let show_line_numbers = self
20768            .show_line_numbers
20769            .unwrap_or(gutter_settings.line_numbers);
20770        let line_gutter_width = if show_line_numbers {
20771            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
20772            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
20773            max_line_number_width.max(min_width_for_number_on_gutter)
20774        } else {
20775            0.0.into()
20776        };
20777
20778        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
20779        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
20780
20781        let git_blame_entries_width =
20782            self.git_blame_gutter_max_author_length
20783                .map(|max_author_length| {
20784                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20785                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
20786
20787                    /// The number of characters to dedicate to gaps and margins.
20788                    const SPACING_WIDTH: usize = 4;
20789
20790                    let max_char_count = max_author_length.min(renderer.max_author_length())
20791                        + ::git::SHORT_SHA_LENGTH
20792                        + MAX_RELATIVE_TIMESTAMP.len()
20793                        + SPACING_WIDTH;
20794
20795                    em_advance * max_char_count
20796                });
20797
20798        let is_singleton = self.buffer_snapshot.is_singleton();
20799
20800        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
20801        left_padding += if !is_singleton {
20802            em_width * 4.0
20803        } else if show_runnables || show_breakpoints {
20804            em_width * 3.0
20805        } else if show_git_gutter && show_line_numbers {
20806            em_width * 2.0
20807        } else if show_git_gutter || show_line_numbers {
20808            em_width
20809        } else {
20810            px(0.)
20811        };
20812
20813        let shows_folds = is_singleton && gutter_settings.folds;
20814
20815        let right_padding = if shows_folds && show_line_numbers {
20816            em_width * 4.0
20817        } else if shows_folds || (!is_singleton && show_line_numbers) {
20818            em_width * 3.0
20819        } else if show_line_numbers {
20820            em_width
20821        } else {
20822            px(0.)
20823        };
20824
20825        Some(GutterDimensions {
20826            left_padding,
20827            right_padding,
20828            width: line_gutter_width + left_padding + right_padding,
20829            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
20830            git_blame_entries_width,
20831        })
20832    }
20833
20834    pub fn render_crease_toggle(
20835        &self,
20836        buffer_row: MultiBufferRow,
20837        row_contains_cursor: bool,
20838        editor: Entity<Editor>,
20839        window: &mut Window,
20840        cx: &mut App,
20841    ) -> Option<AnyElement> {
20842        let folded = self.is_line_folded(buffer_row);
20843        let mut is_foldable = false;
20844
20845        if let Some(crease) = self
20846            .crease_snapshot
20847            .query_row(buffer_row, &self.buffer_snapshot)
20848        {
20849            is_foldable = true;
20850            match crease {
20851                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
20852                    if let Some(render_toggle) = render_toggle {
20853                        let toggle_callback =
20854                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
20855                                if folded {
20856                                    editor.update(cx, |editor, cx| {
20857                                        editor.fold_at(buffer_row, window, cx)
20858                                    });
20859                                } else {
20860                                    editor.update(cx, |editor, cx| {
20861                                        editor.unfold_at(buffer_row, window, cx)
20862                                    });
20863                                }
20864                            });
20865                        return Some((render_toggle)(
20866                            buffer_row,
20867                            folded,
20868                            toggle_callback,
20869                            window,
20870                            cx,
20871                        ));
20872                    }
20873                }
20874            }
20875        }
20876
20877        is_foldable |= self.starts_indent(buffer_row);
20878
20879        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
20880            Some(
20881                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
20882                    .toggle_state(folded)
20883                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
20884                        if folded {
20885                            this.unfold_at(buffer_row, window, cx);
20886                        } else {
20887                            this.fold_at(buffer_row, window, cx);
20888                        }
20889                    }))
20890                    .into_any_element(),
20891            )
20892        } else {
20893            None
20894        }
20895    }
20896
20897    pub fn render_crease_trailer(
20898        &self,
20899        buffer_row: MultiBufferRow,
20900        window: &mut Window,
20901        cx: &mut App,
20902    ) -> Option<AnyElement> {
20903        let folded = self.is_line_folded(buffer_row);
20904        if let Crease::Inline { render_trailer, .. } = self
20905            .crease_snapshot
20906            .query_row(buffer_row, &self.buffer_snapshot)?
20907        {
20908            let render_trailer = render_trailer.as_ref()?;
20909            Some(render_trailer(buffer_row, folded, window, cx))
20910        } else {
20911            None
20912        }
20913    }
20914}
20915
20916impl Deref for EditorSnapshot {
20917    type Target = DisplaySnapshot;
20918
20919    fn deref(&self) -> &Self::Target {
20920        &self.display_snapshot
20921    }
20922}
20923
20924#[derive(Clone, Debug, PartialEq, Eq)]
20925pub enum EditorEvent {
20926    InputIgnored {
20927        text: Arc<str>,
20928    },
20929    InputHandled {
20930        utf16_range_to_replace: Option<Range<isize>>,
20931        text: Arc<str>,
20932    },
20933    ExcerptsAdded {
20934        buffer: Entity<Buffer>,
20935        predecessor: ExcerptId,
20936        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
20937    },
20938    ExcerptsRemoved {
20939        ids: Vec<ExcerptId>,
20940        removed_buffer_ids: Vec<BufferId>,
20941    },
20942    BufferFoldToggled {
20943        ids: Vec<ExcerptId>,
20944        folded: bool,
20945    },
20946    ExcerptsEdited {
20947        ids: Vec<ExcerptId>,
20948    },
20949    ExcerptsExpanded {
20950        ids: Vec<ExcerptId>,
20951    },
20952    BufferEdited,
20953    Edited {
20954        transaction_id: clock::Lamport,
20955    },
20956    Reparsed(BufferId),
20957    Focused,
20958    FocusedIn,
20959    Blurred,
20960    DirtyChanged,
20961    Saved,
20962    TitleChanged,
20963    DiffBaseChanged,
20964    SelectionsChanged {
20965        local: bool,
20966    },
20967    ScrollPositionChanged {
20968        local: bool,
20969        autoscroll: bool,
20970    },
20971    Closed,
20972    TransactionUndone {
20973        transaction_id: clock::Lamport,
20974    },
20975    TransactionBegun {
20976        transaction_id: clock::Lamport,
20977    },
20978    Reloaded,
20979    CursorShapeChanged,
20980    PushedToNavHistory {
20981        anchor: Anchor,
20982        is_deactivate: bool,
20983    },
20984}
20985
20986impl EventEmitter<EditorEvent> for Editor {}
20987
20988impl Focusable for Editor {
20989    fn focus_handle(&self, _cx: &App) -> FocusHandle {
20990        self.focus_handle.clone()
20991    }
20992}
20993
20994impl Render for Editor {
20995    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
20996        let settings = ThemeSettings::get_global(cx);
20997
20998        let mut text_style = match self.mode {
20999            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21000                color: cx.theme().colors().editor_foreground,
21001                font_family: settings.ui_font.family.clone(),
21002                font_features: settings.ui_font.features.clone(),
21003                font_fallbacks: settings.ui_font.fallbacks.clone(),
21004                font_size: rems(0.875).into(),
21005                font_weight: settings.ui_font.weight,
21006                line_height: relative(settings.buffer_line_height.value()),
21007                ..Default::default()
21008            },
21009            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21010                color: cx.theme().colors().editor_foreground,
21011                font_family: settings.buffer_font.family.clone(),
21012                font_features: settings.buffer_font.features.clone(),
21013                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21014                font_size: settings.buffer_font_size(cx).into(),
21015                font_weight: settings.buffer_font.weight,
21016                line_height: relative(settings.buffer_line_height.value()),
21017                ..Default::default()
21018            },
21019        };
21020        if let Some(text_style_refinement) = &self.text_style_refinement {
21021            text_style.refine(text_style_refinement)
21022        }
21023
21024        let background = match self.mode {
21025            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21026            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
21027            EditorMode::Full { .. } => cx.theme().colors().editor_background,
21028            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
21029        };
21030
21031        EditorElement::new(
21032            &cx.entity(),
21033            EditorStyle {
21034                background,
21035                local_player: cx.theme().players().local(),
21036                text: text_style,
21037                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
21038                syntax: cx.theme().syntax().clone(),
21039                status: cx.theme().status().clone(),
21040                inlay_hints_style: make_inlay_hints_style(cx),
21041                inline_completion_styles: make_suggestion_styles(cx),
21042                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
21043                show_underlines: !self.mode.is_minimap(),
21044            },
21045        )
21046    }
21047}
21048
21049impl EntityInputHandler for Editor {
21050    fn text_for_range(
21051        &mut self,
21052        range_utf16: Range<usize>,
21053        adjusted_range: &mut Option<Range<usize>>,
21054        _: &mut Window,
21055        cx: &mut Context<Self>,
21056    ) -> Option<String> {
21057        let snapshot = self.buffer.read(cx).read(cx);
21058        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
21059        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
21060        if (start.0..end.0) != range_utf16 {
21061            adjusted_range.replace(start.0..end.0);
21062        }
21063        Some(snapshot.text_for_range(start..end).collect())
21064    }
21065
21066    fn selected_text_range(
21067        &mut self,
21068        ignore_disabled_input: bool,
21069        _: &mut Window,
21070        cx: &mut Context<Self>,
21071    ) -> Option<UTF16Selection> {
21072        // Prevent the IME menu from appearing when holding down an alphabetic key
21073        // while input is disabled.
21074        if !ignore_disabled_input && !self.input_enabled {
21075            return None;
21076        }
21077
21078        let selection = self.selections.newest::<OffsetUtf16>(cx);
21079        let range = selection.range();
21080
21081        Some(UTF16Selection {
21082            range: range.start.0..range.end.0,
21083            reversed: selection.reversed,
21084        })
21085    }
21086
21087    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
21088        let snapshot = self.buffer.read(cx).read(cx);
21089        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
21090        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
21091    }
21092
21093    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21094        self.clear_highlights::<InputComposition>(cx);
21095        self.ime_transaction.take();
21096    }
21097
21098    fn replace_text_in_range(
21099        &mut self,
21100        range_utf16: Option<Range<usize>>,
21101        text: &str,
21102        window: &mut Window,
21103        cx: &mut Context<Self>,
21104    ) {
21105        if !self.input_enabled {
21106            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21107            return;
21108        }
21109
21110        self.transact(window, cx, |this, window, cx| {
21111            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
21112                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21113                Some(this.selection_replacement_ranges(range_utf16, cx))
21114            } else {
21115                this.marked_text_ranges(cx)
21116            };
21117
21118            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
21119                let newest_selection_id = this.selections.newest_anchor().id;
21120                this.selections
21121                    .all::<OffsetUtf16>(cx)
21122                    .iter()
21123                    .zip(ranges_to_replace.iter())
21124                    .find_map(|(selection, range)| {
21125                        if selection.id == newest_selection_id {
21126                            Some(
21127                                (range.start.0 as isize - selection.head().0 as isize)
21128                                    ..(range.end.0 as isize - selection.head().0 as isize),
21129                            )
21130                        } else {
21131                            None
21132                        }
21133                    })
21134            });
21135
21136            cx.emit(EditorEvent::InputHandled {
21137                utf16_range_to_replace: range_to_replace,
21138                text: text.into(),
21139            });
21140
21141            if let Some(new_selected_ranges) = new_selected_ranges {
21142                this.change_selections(None, window, cx, |selections| {
21143                    selections.select_ranges(new_selected_ranges)
21144                });
21145                this.backspace(&Default::default(), window, cx);
21146            }
21147
21148            this.handle_input(text, window, cx);
21149        });
21150
21151        if let Some(transaction) = self.ime_transaction {
21152            self.buffer.update(cx, |buffer, cx| {
21153                buffer.group_until_transaction(transaction, cx);
21154            });
21155        }
21156
21157        self.unmark_text(window, cx);
21158    }
21159
21160    fn replace_and_mark_text_in_range(
21161        &mut self,
21162        range_utf16: Option<Range<usize>>,
21163        text: &str,
21164        new_selected_range_utf16: Option<Range<usize>>,
21165        window: &mut Window,
21166        cx: &mut Context<Self>,
21167    ) {
21168        if !self.input_enabled {
21169            return;
21170        }
21171
21172        let transaction = self.transact(window, cx, |this, window, cx| {
21173            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
21174                let snapshot = this.buffer.read(cx).read(cx);
21175                if let Some(relative_range_utf16) = range_utf16.as_ref() {
21176                    for marked_range in &mut marked_ranges {
21177                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
21178                        marked_range.start.0 += relative_range_utf16.start;
21179                        marked_range.start =
21180                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
21181                        marked_range.end =
21182                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
21183                    }
21184                }
21185                Some(marked_ranges)
21186            } else if let Some(range_utf16) = range_utf16 {
21187                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21188                Some(this.selection_replacement_ranges(range_utf16, cx))
21189            } else {
21190                None
21191            };
21192
21193            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
21194                let newest_selection_id = this.selections.newest_anchor().id;
21195                this.selections
21196                    .all::<OffsetUtf16>(cx)
21197                    .iter()
21198                    .zip(ranges_to_replace.iter())
21199                    .find_map(|(selection, range)| {
21200                        if selection.id == newest_selection_id {
21201                            Some(
21202                                (range.start.0 as isize - selection.head().0 as isize)
21203                                    ..(range.end.0 as isize - selection.head().0 as isize),
21204                            )
21205                        } else {
21206                            None
21207                        }
21208                    })
21209            });
21210
21211            cx.emit(EditorEvent::InputHandled {
21212                utf16_range_to_replace: range_to_replace,
21213                text: text.into(),
21214            });
21215
21216            if let Some(ranges) = ranges_to_replace {
21217                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
21218            }
21219
21220            let marked_ranges = {
21221                let snapshot = this.buffer.read(cx).read(cx);
21222                this.selections
21223                    .disjoint_anchors()
21224                    .iter()
21225                    .map(|selection| {
21226                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
21227                    })
21228                    .collect::<Vec<_>>()
21229            };
21230
21231            if text.is_empty() {
21232                this.unmark_text(window, cx);
21233            } else {
21234                this.highlight_text::<InputComposition>(
21235                    marked_ranges.clone(),
21236                    HighlightStyle {
21237                        underline: Some(UnderlineStyle {
21238                            thickness: px(1.),
21239                            color: None,
21240                            wavy: false,
21241                        }),
21242                        ..Default::default()
21243                    },
21244                    cx,
21245                );
21246            }
21247
21248            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
21249            let use_autoclose = this.use_autoclose;
21250            let use_auto_surround = this.use_auto_surround;
21251            this.set_use_autoclose(false);
21252            this.set_use_auto_surround(false);
21253            this.handle_input(text, window, cx);
21254            this.set_use_autoclose(use_autoclose);
21255            this.set_use_auto_surround(use_auto_surround);
21256
21257            if let Some(new_selected_range) = new_selected_range_utf16 {
21258                let snapshot = this.buffer.read(cx).read(cx);
21259                let new_selected_ranges = marked_ranges
21260                    .into_iter()
21261                    .map(|marked_range| {
21262                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
21263                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
21264                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
21265                        snapshot.clip_offset_utf16(new_start, Bias::Left)
21266                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
21267                    })
21268                    .collect::<Vec<_>>();
21269
21270                drop(snapshot);
21271                this.change_selections(None, window, cx, |selections| {
21272                    selections.select_ranges(new_selected_ranges)
21273                });
21274            }
21275        });
21276
21277        self.ime_transaction = self.ime_transaction.or(transaction);
21278        if let Some(transaction) = self.ime_transaction {
21279            self.buffer.update(cx, |buffer, cx| {
21280                buffer.group_until_transaction(transaction, cx);
21281            });
21282        }
21283
21284        if self.text_highlights::<InputComposition>(cx).is_none() {
21285            self.ime_transaction.take();
21286        }
21287    }
21288
21289    fn bounds_for_range(
21290        &mut self,
21291        range_utf16: Range<usize>,
21292        element_bounds: gpui::Bounds<Pixels>,
21293        window: &mut Window,
21294        cx: &mut Context<Self>,
21295    ) -> Option<gpui::Bounds<Pixels>> {
21296        let text_layout_details = self.text_layout_details(window);
21297        let gpui::Size {
21298            width: em_width,
21299            height: line_height,
21300        } = self.character_size(window);
21301
21302        let snapshot = self.snapshot(window, cx);
21303        let scroll_position = snapshot.scroll_position();
21304        let scroll_left = scroll_position.x * em_width;
21305
21306        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
21307        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
21308            + self.gutter_dimensions.width
21309            + self.gutter_dimensions.margin;
21310        let y = line_height * (start.row().as_f32() - scroll_position.y);
21311
21312        Some(Bounds {
21313            origin: element_bounds.origin + point(x, y),
21314            size: size(em_width, line_height),
21315        })
21316    }
21317
21318    fn character_index_for_point(
21319        &mut self,
21320        point: gpui::Point<Pixels>,
21321        _window: &mut Window,
21322        _cx: &mut Context<Self>,
21323    ) -> Option<usize> {
21324        let position_map = self.last_position_map.as_ref()?;
21325        if !position_map.text_hitbox.contains(&point) {
21326            return None;
21327        }
21328        let display_point = position_map.point_for_position(point).previous_valid;
21329        let anchor = position_map
21330            .snapshot
21331            .display_point_to_anchor(display_point, Bias::Left);
21332        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
21333        Some(utf16_offset.0)
21334    }
21335}
21336
21337trait SelectionExt {
21338    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
21339    fn spanned_rows(
21340        &self,
21341        include_end_if_at_line_start: bool,
21342        map: &DisplaySnapshot,
21343    ) -> Range<MultiBufferRow>;
21344}
21345
21346impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
21347    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
21348        let start = self
21349            .start
21350            .to_point(&map.buffer_snapshot)
21351            .to_display_point(map);
21352        let end = self
21353            .end
21354            .to_point(&map.buffer_snapshot)
21355            .to_display_point(map);
21356        if self.reversed {
21357            end..start
21358        } else {
21359            start..end
21360        }
21361    }
21362
21363    fn spanned_rows(
21364        &self,
21365        include_end_if_at_line_start: bool,
21366        map: &DisplaySnapshot,
21367    ) -> Range<MultiBufferRow> {
21368        let start = self.start.to_point(&map.buffer_snapshot);
21369        let mut end = self.end.to_point(&map.buffer_snapshot);
21370        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
21371            end.row -= 1;
21372        }
21373
21374        let buffer_start = map.prev_line_boundary(start).0;
21375        let buffer_end = map.next_line_boundary(end).0;
21376        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
21377    }
21378}
21379
21380impl<T: InvalidationRegion> InvalidationStack<T> {
21381    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
21382    where
21383        S: Clone + ToOffset,
21384    {
21385        while let Some(region) = self.last() {
21386            let all_selections_inside_invalidation_ranges =
21387                if selections.len() == region.ranges().len() {
21388                    selections
21389                        .iter()
21390                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
21391                        .all(|(selection, invalidation_range)| {
21392                            let head = selection.head().to_offset(buffer);
21393                            invalidation_range.start <= head && invalidation_range.end >= head
21394                        })
21395                } else {
21396                    false
21397                };
21398
21399            if all_selections_inside_invalidation_ranges {
21400                break;
21401            } else {
21402                self.pop();
21403            }
21404        }
21405    }
21406}
21407
21408impl<T> Default for InvalidationStack<T> {
21409    fn default() -> Self {
21410        Self(Default::default())
21411    }
21412}
21413
21414impl<T> Deref for InvalidationStack<T> {
21415    type Target = Vec<T>;
21416
21417    fn deref(&self) -> &Self::Target {
21418        &self.0
21419    }
21420}
21421
21422impl<T> DerefMut for InvalidationStack<T> {
21423    fn deref_mut(&mut self) -> &mut Self::Target {
21424        &mut self.0
21425    }
21426}
21427
21428impl InvalidationRegion for SnippetState {
21429    fn ranges(&self) -> &[Range<Anchor>] {
21430        &self.ranges[self.active_index]
21431    }
21432}
21433
21434fn inline_completion_edit_text(
21435    current_snapshot: &BufferSnapshot,
21436    edits: &[(Range<Anchor>, String)],
21437    edit_preview: &EditPreview,
21438    include_deletions: bool,
21439    cx: &App,
21440) -> HighlightedText {
21441    let edits = edits
21442        .iter()
21443        .map(|(anchor, text)| {
21444            (
21445                anchor.start.text_anchor..anchor.end.text_anchor,
21446                text.clone(),
21447            )
21448        })
21449        .collect::<Vec<_>>();
21450
21451    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21452}
21453
21454pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21455    match severity {
21456        lsp::DiagnosticSeverity::ERROR => colors.error,
21457        lsp::DiagnosticSeverity::WARNING => colors.warning,
21458        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21459        lsp::DiagnosticSeverity::HINT => colors.info,
21460        _ => colors.ignored,
21461    }
21462}
21463
21464pub fn styled_runs_for_code_label<'a>(
21465    label: &'a CodeLabel,
21466    syntax_theme: &'a theme::SyntaxTheme,
21467) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21468    let fade_out = HighlightStyle {
21469        fade_out: Some(0.35),
21470        ..Default::default()
21471    };
21472
21473    let mut prev_end = label.filter_range.end;
21474    label
21475        .runs
21476        .iter()
21477        .enumerate()
21478        .flat_map(move |(ix, (range, highlight_id))| {
21479            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21480                style
21481            } else {
21482                return Default::default();
21483            };
21484            let mut muted_style = style;
21485            muted_style.highlight(fade_out);
21486
21487            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21488            if range.start >= label.filter_range.end {
21489                if range.start > prev_end {
21490                    runs.push((prev_end..range.start, fade_out));
21491                }
21492                runs.push((range.clone(), muted_style));
21493            } else if range.end <= label.filter_range.end {
21494                runs.push((range.clone(), style));
21495            } else {
21496                runs.push((range.start..label.filter_range.end, style));
21497                runs.push((label.filter_range.end..range.end, muted_style));
21498            }
21499            prev_end = cmp::max(prev_end, range.end);
21500
21501            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21502                runs.push((prev_end..label.text.len(), fade_out));
21503            }
21504
21505            runs
21506        })
21507}
21508
21509pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21510    let mut prev_index = 0;
21511    let mut prev_codepoint: Option<char> = None;
21512    text.char_indices()
21513        .chain([(text.len(), '\0')])
21514        .filter_map(move |(index, codepoint)| {
21515            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21516            let is_boundary = index == text.len()
21517                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21518                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21519            if is_boundary {
21520                let chunk = &text[prev_index..index];
21521                prev_index = index;
21522                Some(chunk)
21523            } else {
21524                None
21525            }
21526        })
21527}
21528
21529pub trait RangeToAnchorExt: Sized {
21530    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21531
21532    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21533        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21534        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21535    }
21536}
21537
21538impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21539    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21540        let start_offset = self.start.to_offset(snapshot);
21541        let end_offset = self.end.to_offset(snapshot);
21542        if start_offset == end_offset {
21543            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21544        } else {
21545            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21546        }
21547    }
21548}
21549
21550pub trait RowExt {
21551    fn as_f32(&self) -> f32;
21552
21553    fn next_row(&self) -> Self;
21554
21555    fn previous_row(&self) -> Self;
21556
21557    fn minus(&self, other: Self) -> u32;
21558}
21559
21560impl RowExt for DisplayRow {
21561    fn as_f32(&self) -> f32 {
21562        self.0 as f32
21563    }
21564
21565    fn next_row(&self) -> Self {
21566        Self(self.0 + 1)
21567    }
21568
21569    fn previous_row(&self) -> Self {
21570        Self(self.0.saturating_sub(1))
21571    }
21572
21573    fn minus(&self, other: Self) -> u32 {
21574        self.0 - other.0
21575    }
21576}
21577
21578impl RowExt for MultiBufferRow {
21579    fn as_f32(&self) -> f32 {
21580        self.0 as f32
21581    }
21582
21583    fn next_row(&self) -> Self {
21584        Self(self.0 + 1)
21585    }
21586
21587    fn previous_row(&self) -> Self {
21588        Self(self.0.saturating_sub(1))
21589    }
21590
21591    fn minus(&self, other: Self) -> u32 {
21592        self.0 - other.0
21593    }
21594}
21595
21596trait RowRangeExt {
21597    type Row;
21598
21599    fn len(&self) -> usize;
21600
21601    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21602}
21603
21604impl RowRangeExt for Range<MultiBufferRow> {
21605    type Row = MultiBufferRow;
21606
21607    fn len(&self) -> usize {
21608        (self.end.0 - self.start.0) as usize
21609    }
21610
21611    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21612        (self.start.0..self.end.0).map(MultiBufferRow)
21613    }
21614}
21615
21616impl RowRangeExt for Range<DisplayRow> {
21617    type Row = DisplayRow;
21618
21619    fn len(&self) -> usize {
21620        (self.end.0 - self.start.0) as usize
21621    }
21622
21623    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21624        (self.start.0..self.end.0).map(DisplayRow)
21625    }
21626}
21627
21628/// If select range has more than one line, we
21629/// just point the cursor to range.start.
21630fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21631    if range.start.row == range.end.row {
21632        range
21633    } else {
21634        range.start..range.start
21635    }
21636}
21637pub struct KillRing(ClipboardItem);
21638impl Global for KillRing {}
21639
21640const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21641
21642enum BreakpointPromptEditAction {
21643    Log,
21644    Condition,
21645    HitCondition,
21646}
21647
21648struct BreakpointPromptEditor {
21649    pub(crate) prompt: Entity<Editor>,
21650    editor: WeakEntity<Editor>,
21651    breakpoint_anchor: Anchor,
21652    breakpoint: Breakpoint,
21653    edit_action: BreakpointPromptEditAction,
21654    block_ids: HashSet<CustomBlockId>,
21655    editor_margins: Arc<Mutex<EditorMargins>>,
21656    _subscriptions: Vec<Subscription>,
21657}
21658
21659impl BreakpointPromptEditor {
21660    const MAX_LINES: u8 = 4;
21661
21662    fn new(
21663        editor: WeakEntity<Editor>,
21664        breakpoint_anchor: Anchor,
21665        breakpoint: Breakpoint,
21666        edit_action: BreakpointPromptEditAction,
21667        window: &mut Window,
21668        cx: &mut Context<Self>,
21669    ) -> Self {
21670        let base_text = match edit_action {
21671            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21672            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21673            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21674        }
21675        .map(|msg| msg.to_string())
21676        .unwrap_or_default();
21677
21678        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21679        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21680
21681        let prompt = cx.new(|cx| {
21682            let mut prompt = Editor::new(
21683                EditorMode::AutoHeight {
21684                    max_lines: Self::MAX_LINES as usize,
21685                },
21686                buffer,
21687                None,
21688                window,
21689                cx,
21690            );
21691            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21692            prompt.set_show_cursor_when_unfocused(false, cx);
21693            prompt.set_placeholder_text(
21694                match edit_action {
21695                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21696                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21697                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21698                },
21699                cx,
21700            );
21701
21702            prompt
21703        });
21704
21705        Self {
21706            prompt,
21707            editor,
21708            breakpoint_anchor,
21709            breakpoint,
21710            edit_action,
21711            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21712            block_ids: Default::default(),
21713            _subscriptions: vec![],
21714        }
21715    }
21716
21717    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21718        self.block_ids.extend(block_ids)
21719    }
21720
21721    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21722        if let Some(editor) = self.editor.upgrade() {
21723            let message = self
21724                .prompt
21725                .read(cx)
21726                .buffer
21727                .read(cx)
21728                .as_singleton()
21729                .expect("A multi buffer in breakpoint prompt isn't possible")
21730                .read(cx)
21731                .as_rope()
21732                .to_string();
21733
21734            editor.update(cx, |editor, cx| {
21735                editor.edit_breakpoint_at_anchor(
21736                    self.breakpoint_anchor,
21737                    self.breakpoint.clone(),
21738                    match self.edit_action {
21739                        BreakpointPromptEditAction::Log => {
21740                            BreakpointEditAction::EditLogMessage(message.into())
21741                        }
21742                        BreakpointPromptEditAction::Condition => {
21743                            BreakpointEditAction::EditCondition(message.into())
21744                        }
21745                        BreakpointPromptEditAction::HitCondition => {
21746                            BreakpointEditAction::EditHitCondition(message.into())
21747                        }
21748                    },
21749                    cx,
21750                );
21751
21752                editor.remove_blocks(self.block_ids.clone(), None, cx);
21753                cx.focus_self(window);
21754            });
21755        }
21756    }
21757
21758    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
21759        self.editor
21760            .update(cx, |editor, cx| {
21761                editor.remove_blocks(self.block_ids.clone(), None, cx);
21762                window.focus(&editor.focus_handle);
21763            })
21764            .log_err();
21765    }
21766
21767    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
21768        let settings = ThemeSettings::get_global(cx);
21769        let text_style = TextStyle {
21770            color: if self.prompt.read(cx).read_only(cx) {
21771                cx.theme().colors().text_disabled
21772            } else {
21773                cx.theme().colors().text
21774            },
21775            font_family: settings.buffer_font.family.clone(),
21776            font_fallbacks: settings.buffer_font.fallbacks.clone(),
21777            font_size: settings.buffer_font_size(cx).into(),
21778            font_weight: settings.buffer_font.weight,
21779            line_height: relative(settings.buffer_line_height.value()),
21780            ..Default::default()
21781        };
21782        EditorElement::new(
21783            &self.prompt,
21784            EditorStyle {
21785                background: cx.theme().colors().editor_background,
21786                local_player: cx.theme().players().local(),
21787                text: text_style,
21788                ..Default::default()
21789            },
21790        )
21791    }
21792}
21793
21794impl Render for BreakpointPromptEditor {
21795    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21796        let editor_margins = *self.editor_margins.lock();
21797        let gutter_dimensions = editor_margins.gutter;
21798        h_flex()
21799            .key_context("Editor")
21800            .bg(cx.theme().colors().editor_background)
21801            .border_y_1()
21802            .border_color(cx.theme().status().info_border)
21803            .size_full()
21804            .py(window.line_height() / 2.5)
21805            .on_action(cx.listener(Self::confirm))
21806            .on_action(cx.listener(Self::cancel))
21807            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
21808            .child(div().flex_1().child(self.render_prompt_editor(cx)))
21809    }
21810}
21811
21812impl Focusable for BreakpointPromptEditor {
21813    fn focus_handle(&self, cx: &App) -> FocusHandle {
21814        self.prompt.focus_handle(cx)
21815    }
21816}
21817
21818fn all_edits_insertions_or_deletions(
21819    edits: &Vec<(Range<Anchor>, String)>,
21820    snapshot: &MultiBufferSnapshot,
21821) -> bool {
21822    let mut all_insertions = true;
21823    let mut all_deletions = true;
21824
21825    for (range, new_text) in edits.iter() {
21826        let range_is_empty = range.to_offset(&snapshot).is_empty();
21827        let text_is_empty = new_text.is_empty();
21828
21829        if range_is_empty != text_is_empty {
21830            if range_is_empty {
21831                all_deletions = false;
21832            } else {
21833                all_insertions = false;
21834            }
21835        } else {
21836            return false;
21837        }
21838
21839        if !all_insertions && !all_deletions {
21840            return false;
21841        }
21842    }
21843    all_insertions || all_deletions
21844}
21845
21846struct MissingEditPredictionKeybindingTooltip;
21847
21848impl Render for MissingEditPredictionKeybindingTooltip {
21849    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21850        ui::tooltip_container(window, cx, |container, _, cx| {
21851            container
21852                .flex_shrink_0()
21853                .max_w_80()
21854                .min_h(rems_from_px(124.))
21855                .justify_between()
21856                .child(
21857                    v_flex()
21858                        .flex_1()
21859                        .text_ui_sm(cx)
21860                        .child(Label::new("Conflict with Accept Keybinding"))
21861                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
21862                )
21863                .child(
21864                    h_flex()
21865                        .pb_1()
21866                        .gap_1()
21867                        .items_end()
21868                        .w_full()
21869                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
21870                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
21871                        }))
21872                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
21873                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
21874                        })),
21875                )
21876        })
21877    }
21878}
21879
21880#[derive(Debug, Clone, Copy, PartialEq)]
21881pub struct LineHighlight {
21882    pub background: Background,
21883    pub border: Option<gpui::Hsla>,
21884    pub include_gutter: bool,
21885    pub type_id: Option<TypeId>,
21886}
21887
21888fn render_diff_hunk_controls(
21889    row: u32,
21890    status: &DiffHunkStatus,
21891    hunk_range: Range<Anchor>,
21892    is_created_file: bool,
21893    line_height: Pixels,
21894    editor: &Entity<Editor>,
21895    _window: &mut Window,
21896    cx: &mut App,
21897) -> AnyElement {
21898    h_flex()
21899        .h(line_height)
21900        .mr_1()
21901        .gap_1()
21902        .px_0p5()
21903        .pb_1()
21904        .border_x_1()
21905        .border_b_1()
21906        .border_color(cx.theme().colors().border_variant)
21907        .rounded_b_lg()
21908        .bg(cx.theme().colors().editor_background)
21909        .gap_1()
21910        .block_mouse_except_scroll()
21911        .shadow_md()
21912        .child(if status.has_secondary_hunk() {
21913            Button::new(("stage", row as u64), "Stage")
21914                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21915                .tooltip({
21916                    let focus_handle = editor.focus_handle(cx);
21917                    move |window, cx| {
21918                        Tooltip::for_action_in(
21919                            "Stage Hunk",
21920                            &::git::ToggleStaged,
21921                            &focus_handle,
21922                            window,
21923                            cx,
21924                        )
21925                    }
21926                })
21927                .on_click({
21928                    let editor = editor.clone();
21929                    move |_event, _window, cx| {
21930                        editor.update(cx, |editor, cx| {
21931                            editor.stage_or_unstage_diff_hunks(
21932                                true,
21933                                vec![hunk_range.start..hunk_range.start],
21934                                cx,
21935                            );
21936                        });
21937                    }
21938                })
21939        } else {
21940            Button::new(("unstage", row as u64), "Unstage")
21941                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
21942                .tooltip({
21943                    let focus_handle = editor.focus_handle(cx);
21944                    move |window, cx| {
21945                        Tooltip::for_action_in(
21946                            "Unstage Hunk",
21947                            &::git::ToggleStaged,
21948                            &focus_handle,
21949                            window,
21950                            cx,
21951                        )
21952                    }
21953                })
21954                .on_click({
21955                    let editor = editor.clone();
21956                    move |_event, _window, cx| {
21957                        editor.update(cx, |editor, cx| {
21958                            editor.stage_or_unstage_diff_hunks(
21959                                false,
21960                                vec![hunk_range.start..hunk_range.start],
21961                                cx,
21962                            );
21963                        });
21964                    }
21965                })
21966        })
21967        .child(
21968            Button::new(("restore", row as u64), "Restore")
21969                .tooltip({
21970                    let focus_handle = editor.focus_handle(cx);
21971                    move |window, cx| {
21972                        Tooltip::for_action_in(
21973                            "Restore Hunk",
21974                            &::git::Restore,
21975                            &focus_handle,
21976                            window,
21977                            cx,
21978                        )
21979                    }
21980                })
21981                .on_click({
21982                    let editor = editor.clone();
21983                    move |_event, window, cx| {
21984                        editor.update(cx, |editor, cx| {
21985                            let snapshot = editor.snapshot(window, cx);
21986                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
21987                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
21988                        });
21989                    }
21990                })
21991                .disabled(is_created_file),
21992        )
21993        .when(
21994            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
21995            |el| {
21996                el.child(
21997                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
21998                        .shape(IconButtonShape::Square)
21999                        .icon_size(IconSize::Small)
22000                        // .disabled(!has_multiple_hunks)
22001                        .tooltip({
22002                            let focus_handle = editor.focus_handle(cx);
22003                            move |window, cx| {
22004                                Tooltip::for_action_in(
22005                                    "Next Hunk",
22006                                    &GoToHunk,
22007                                    &focus_handle,
22008                                    window,
22009                                    cx,
22010                                )
22011                            }
22012                        })
22013                        .on_click({
22014                            let editor = editor.clone();
22015                            move |_event, window, cx| {
22016                                editor.update(cx, |editor, cx| {
22017                                    let snapshot = editor.snapshot(window, cx);
22018                                    let position =
22019                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22020                                    editor.go_to_hunk_before_or_after_position(
22021                                        &snapshot,
22022                                        position,
22023                                        Direction::Next,
22024                                        window,
22025                                        cx,
22026                                    );
22027                                    editor.expand_selected_diff_hunks(cx);
22028                                });
22029                            }
22030                        }),
22031                )
22032                .child(
22033                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
22034                        .shape(IconButtonShape::Square)
22035                        .icon_size(IconSize::Small)
22036                        // .disabled(!has_multiple_hunks)
22037                        .tooltip({
22038                            let focus_handle = editor.focus_handle(cx);
22039                            move |window, cx| {
22040                                Tooltip::for_action_in(
22041                                    "Previous Hunk",
22042                                    &GoToPreviousHunk,
22043                                    &focus_handle,
22044                                    window,
22045                                    cx,
22046                                )
22047                            }
22048                        })
22049                        .on_click({
22050                            let editor = editor.clone();
22051                            move |_event, window, cx| {
22052                                editor.update(cx, |editor, cx| {
22053                                    let snapshot = editor.snapshot(window, cx);
22054                                    let point =
22055                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
22056                                    editor.go_to_hunk_before_or_after_position(
22057                                        &snapshot,
22058                                        point,
22059                                        Direction::Prev,
22060                                        window,
22061                                        cx,
22062                                    );
22063                                    editor.expand_selected_diff_hunks(cx);
22064                                });
22065                            }
22066                        }),
22067                )
22068            },
22069        )
22070        .into_any_element()
22071}