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, CompletionResponse, 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::signature_help::{SignatureHelpHiddenBy, SignatureHelpState};
  215use crate::{
  216    code_context_menus::CompletionsMenuSource,
  217    hover_links::{find_url, find_url_from_range},
  218};
  219
  220pub const FILE_HEADER_HEIGHT: u32 = 2;
  221pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  222pub const DEFAULT_MULTIBUFFER_CONTEXT: u32 = 2;
  223const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  224const MAX_LINE_LEN: usize = 1024;
  225const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  226const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  227pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  228#[doc(hidden)]
  229pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  230const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  231
  232pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  233pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  234pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  235
  236pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  237pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  238pub(crate) const MIN_LINE_NUMBER_DIGITS: u32 = 4;
  239pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  240
  241pub type RenderDiffHunkControlsFn = Arc<
  242    dyn Fn(
  243        u32,
  244        &DiffHunkStatus,
  245        Range<Anchor>,
  246        bool,
  247        Pixels,
  248        &Entity<Editor>,
  249        &mut Window,
  250        &mut App,
  251    ) -> AnyElement,
  252>;
  253
  254const COLUMNAR_SELECTION_MODIFIERS: Modifiers = Modifiers {
  255    alt: true,
  256    shift: true,
  257    control: false,
  258    platform: false,
  259    function: false,
  260};
  261
  262struct InlineValueCache {
  263    enabled: bool,
  264    inlays: Vec<InlayId>,
  265    refresh_task: Task<Option<()>>,
  266}
  267
  268impl InlineValueCache {
  269    fn new(enabled: bool) -> Self {
  270        Self {
  271            enabled,
  272            inlays: Vec::new(),
  273            refresh_task: Task::ready(None),
  274        }
  275    }
  276}
  277
  278#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  279pub enum InlayId {
  280    InlineCompletion(usize),
  281    Hint(usize),
  282    DebuggerValue(usize),
  283}
  284
  285impl InlayId {
  286    fn id(&self) -> usize {
  287        match self {
  288            Self::InlineCompletion(id) => *id,
  289            Self::Hint(id) => *id,
  290            Self::DebuggerValue(id) => *id,
  291        }
  292    }
  293}
  294
  295pub enum ActiveDebugLine {}
  296pub enum DebugStackFrameLine {}
  297enum DocumentHighlightRead {}
  298enum DocumentHighlightWrite {}
  299enum InputComposition {}
  300enum SelectedTextHighlight {}
  301
  302pub enum ConflictsOuter {}
  303pub enum ConflictsOurs {}
  304pub enum ConflictsTheirs {}
  305pub enum ConflictsOursMarker {}
  306pub enum ConflictsTheirsMarker {}
  307
  308#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  309pub enum Navigated {
  310    Yes,
  311    No,
  312}
  313
  314impl Navigated {
  315    pub fn from_bool(yes: bool) -> Navigated {
  316        if yes { Navigated::Yes } else { Navigated::No }
  317    }
  318}
  319
  320#[derive(Debug, Clone, PartialEq, Eq)]
  321enum DisplayDiffHunk {
  322    Folded {
  323        display_row: DisplayRow,
  324    },
  325    Unfolded {
  326        is_created_file: bool,
  327        diff_base_byte_range: Range<usize>,
  328        display_row_range: Range<DisplayRow>,
  329        multi_buffer_range: Range<Anchor>,
  330        status: DiffHunkStatus,
  331    },
  332}
  333
  334pub enum HideMouseCursorOrigin {
  335    TypingAction,
  336    MovementAction,
  337}
  338
  339pub fn init_settings(cx: &mut App) {
  340    EditorSettings::register(cx);
  341}
  342
  343pub fn init(cx: &mut App) {
  344    init_settings(cx);
  345
  346    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  347
  348    workspace::register_project_item::<Editor>(cx);
  349    workspace::FollowableViewRegistry::register::<Editor>(cx);
  350    workspace::register_serializable_item::<Editor>(cx);
  351
  352    cx.observe_new(
  353        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  354            workspace.register_action(Editor::new_file);
  355            workspace.register_action(Editor::new_file_vertical);
  356            workspace.register_action(Editor::new_file_horizontal);
  357            workspace.register_action(Editor::cancel_language_server_work);
  358        },
  359    )
  360    .detach();
  361
  362    cx.on_action(move |_: &workspace::NewFile, cx| {
  363        let app_state = workspace::AppState::global(cx);
  364        if let Some(app_state) = app_state.upgrade() {
  365            workspace::open_new(
  366                Default::default(),
  367                app_state,
  368                cx,
  369                |workspace, window, cx| {
  370                    Editor::new_file(workspace, &Default::default(), window, cx)
  371                },
  372            )
  373            .detach();
  374        }
  375    });
  376    cx.on_action(move |_: &workspace::NewWindow, cx| {
  377        let app_state = workspace::AppState::global(cx);
  378        if let Some(app_state) = app_state.upgrade() {
  379            workspace::open_new(
  380                Default::default(),
  381                app_state,
  382                cx,
  383                |workspace, window, cx| {
  384                    cx.activate(true);
  385                    Editor::new_file(workspace, &Default::default(), window, cx)
  386                },
  387            )
  388            .detach();
  389        }
  390    });
  391}
  392
  393pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  394    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  395}
  396
  397pub trait DiagnosticRenderer {
  398    fn render_group(
  399        &self,
  400        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  401        buffer_id: BufferId,
  402        snapshot: EditorSnapshot,
  403        editor: WeakEntity<Editor>,
  404        cx: &mut App,
  405    ) -> Vec<BlockProperties<Anchor>>;
  406
  407    fn render_hover(
  408        &self,
  409        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  410        range: Range<Point>,
  411        buffer_id: BufferId,
  412        cx: &mut App,
  413    ) -> Option<Entity<markdown::Markdown>>;
  414
  415    fn open_link(
  416        &self,
  417        editor: &mut Editor,
  418        link: SharedString,
  419        window: &mut Window,
  420        cx: &mut Context<Editor>,
  421    );
  422}
  423
  424pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  425
  426impl GlobalDiagnosticRenderer {
  427    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  428        cx.try_global::<Self>().map(|g| g.0.clone())
  429    }
  430}
  431
  432impl gpui::Global for GlobalDiagnosticRenderer {}
  433pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  434    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  435}
  436
  437pub struct SearchWithinRange;
  438
  439trait InvalidationRegion {
  440    fn ranges(&self) -> &[Range<Anchor>];
  441}
  442
  443#[derive(Clone, Debug, PartialEq)]
  444pub enum SelectPhase {
  445    Begin {
  446        position: DisplayPoint,
  447        add: bool,
  448        click_count: usize,
  449    },
  450    BeginColumnar {
  451        position: DisplayPoint,
  452        reset: bool,
  453        goal_column: u32,
  454    },
  455    Extend {
  456        position: DisplayPoint,
  457        click_count: usize,
  458    },
  459    Update {
  460        position: DisplayPoint,
  461        goal_column: u32,
  462        scroll_delta: gpui::Point<f32>,
  463    },
  464    End,
  465}
  466
  467#[derive(Clone, Debug)]
  468pub enum SelectMode {
  469    Character,
  470    Word(Range<Anchor>),
  471    Line(Range<Anchor>),
  472    All,
  473}
  474
  475#[derive(Clone, PartialEq, Eq, Debug)]
  476pub enum EditorMode {
  477    SingleLine {
  478        auto_width: bool,
  479    },
  480    AutoHeight {
  481        max_lines: usize,
  482    },
  483    Full {
  484        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  485        scale_ui_elements_with_buffer_font_size: bool,
  486        /// When set to `true`, the editor will render a background for the active line.
  487        show_active_line_background: bool,
  488        /// When set to `true`, the editor's height will be determined by its content.
  489        sized_by_content: bool,
  490    },
  491    Minimap {
  492        parent: WeakEntity<Editor>,
  493    },
  494}
  495
  496impl EditorMode {
  497    pub fn full() -> Self {
  498        Self::Full {
  499            scale_ui_elements_with_buffer_font_size: true,
  500            show_active_line_background: true,
  501            sized_by_content: false,
  502        }
  503    }
  504
  505    pub fn is_full(&self) -> bool {
  506        matches!(self, Self::Full { .. })
  507    }
  508
  509    fn is_minimap(&self) -> bool {
  510        matches!(self, Self::Minimap { .. })
  511    }
  512}
  513
  514#[derive(Copy, Clone, Debug)]
  515pub enum SoftWrap {
  516    /// Prefer not to wrap at all.
  517    ///
  518    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  519    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  520    GitDiff,
  521    /// Prefer a single line generally, unless an overly long line is encountered.
  522    None,
  523    /// Soft wrap lines that exceed the editor width.
  524    EditorWidth,
  525    /// Soft wrap lines at the preferred line length.
  526    Column(u32),
  527    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  528    Bounded(u32),
  529}
  530
  531#[derive(Clone)]
  532pub struct EditorStyle {
  533    pub background: Hsla,
  534    pub local_player: PlayerColor,
  535    pub text: TextStyle,
  536    pub scrollbar_width: Pixels,
  537    pub syntax: Arc<SyntaxTheme>,
  538    pub status: StatusColors,
  539    pub inlay_hints_style: HighlightStyle,
  540    pub inline_completion_styles: InlineCompletionStyles,
  541    pub unnecessary_code_fade: f32,
  542    pub show_underlines: bool,
  543}
  544
  545impl Default for EditorStyle {
  546    fn default() -> Self {
  547        Self {
  548            background: Hsla::default(),
  549            local_player: PlayerColor::default(),
  550            text: TextStyle::default(),
  551            scrollbar_width: Pixels::default(),
  552            syntax: Default::default(),
  553            // HACK: Status colors don't have a real default.
  554            // We should look into removing the status colors from the editor
  555            // style and retrieve them directly from the theme.
  556            status: StatusColors::dark(),
  557            inlay_hints_style: HighlightStyle::default(),
  558            inline_completion_styles: InlineCompletionStyles {
  559                insertion: HighlightStyle::default(),
  560                whitespace: HighlightStyle::default(),
  561            },
  562            unnecessary_code_fade: Default::default(),
  563            show_underlines: true,
  564        }
  565    }
  566}
  567
  568pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  569    let show_background = language_settings::language_settings(None, None, cx)
  570        .inlay_hints
  571        .show_background;
  572
  573    HighlightStyle {
  574        color: Some(cx.theme().status().hint),
  575        background_color: show_background.then(|| cx.theme().status().hint_background),
  576        ..HighlightStyle::default()
  577    }
  578}
  579
  580pub fn make_suggestion_styles(cx: &mut App) -> InlineCompletionStyles {
  581    InlineCompletionStyles {
  582        insertion: HighlightStyle {
  583            color: Some(cx.theme().status().predictive),
  584            ..HighlightStyle::default()
  585        },
  586        whitespace: HighlightStyle {
  587            background_color: Some(cx.theme().status().created_background),
  588            ..HighlightStyle::default()
  589        },
  590    }
  591}
  592
  593type CompletionId = usize;
  594
  595pub(crate) enum EditDisplayMode {
  596    TabAccept,
  597    DiffPopover,
  598    Inline,
  599}
  600
  601enum InlineCompletion {
  602    Edit {
  603        edits: Vec<(Range<Anchor>, String)>,
  604        edit_preview: Option<EditPreview>,
  605        display_mode: EditDisplayMode,
  606        snapshot: BufferSnapshot,
  607    },
  608    Move {
  609        target: Anchor,
  610        snapshot: BufferSnapshot,
  611    },
  612}
  613
  614struct InlineCompletionState {
  615    inlay_ids: Vec<InlayId>,
  616    completion: InlineCompletion,
  617    completion_id: Option<SharedString>,
  618    invalidation_range: Range<Anchor>,
  619}
  620
  621enum EditPredictionSettings {
  622    Disabled,
  623    Enabled {
  624        show_in_menu: bool,
  625        preview_requires_modifier: bool,
  626    },
  627}
  628
  629enum InlineCompletionHighlight {}
  630
  631#[derive(Debug, Clone)]
  632struct InlineDiagnostic {
  633    message: SharedString,
  634    group_id: usize,
  635    is_primary: bool,
  636    start: Point,
  637    severity: lsp::DiagnosticSeverity,
  638}
  639
  640pub enum MenuInlineCompletionsPolicy {
  641    Never,
  642    ByProvider,
  643}
  644
  645pub enum EditPredictionPreview {
  646    /// Modifier is not pressed
  647    Inactive { released_too_fast: bool },
  648    /// Modifier pressed
  649    Active {
  650        since: Instant,
  651        previous_scroll_position: Option<ScrollAnchor>,
  652    },
  653}
  654
  655impl EditPredictionPreview {
  656    pub fn released_too_fast(&self) -> bool {
  657        match self {
  658            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  659            EditPredictionPreview::Active { .. } => false,
  660        }
  661    }
  662
  663    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  664        if let EditPredictionPreview::Active {
  665            previous_scroll_position,
  666            ..
  667        } = self
  668        {
  669            *previous_scroll_position = scroll_position;
  670        }
  671    }
  672}
  673
  674pub struct ContextMenuOptions {
  675    pub min_entries_visible: usize,
  676    pub max_entries_visible: usize,
  677    pub placement: Option<ContextMenuPlacement>,
  678}
  679
  680#[derive(Debug, Clone, PartialEq, Eq)]
  681pub enum ContextMenuPlacement {
  682    Above,
  683    Below,
  684}
  685
  686#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  687struct EditorActionId(usize);
  688
  689impl EditorActionId {
  690    pub fn post_inc(&mut self) -> Self {
  691        let answer = self.0;
  692
  693        *self = Self(answer + 1);
  694
  695        Self(answer)
  696    }
  697}
  698
  699// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  700// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  701
  702type BackgroundHighlight = (fn(&ThemeColors) -> Hsla, Arc<[Range<Anchor>]>);
  703type GutterHighlight = (fn(&App) -> Hsla, Arc<[Range<Anchor>]>);
  704
  705#[derive(Default)]
  706struct ScrollbarMarkerState {
  707    scrollbar_size: Size<Pixels>,
  708    dirty: bool,
  709    markers: Arc<[PaintQuad]>,
  710    pending_refresh: Option<Task<Result<()>>>,
  711}
  712
  713impl ScrollbarMarkerState {
  714    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  715        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  716    }
  717}
  718
  719#[derive(Clone, Copy, PartialEq, Eq)]
  720pub enum MinimapVisibility {
  721    Disabled,
  722    Enabled {
  723        /// The configuration currently present in the users settings.
  724        setting_configuration: bool,
  725        /// Whether to override the currently set visibility from the users setting.
  726        toggle_override: bool,
  727    },
  728}
  729
  730impl MinimapVisibility {
  731    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  732        if mode.is_full() {
  733            Self::Enabled {
  734                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  735                toggle_override: false,
  736            }
  737        } else {
  738            Self::Disabled
  739        }
  740    }
  741
  742    fn hidden(&self) -> Self {
  743        match *self {
  744            Self::Enabled {
  745                setting_configuration,
  746                ..
  747            } => Self::Enabled {
  748                setting_configuration,
  749                toggle_override: setting_configuration,
  750            },
  751            Self::Disabled => Self::Disabled,
  752        }
  753    }
  754
  755    fn disabled(&self) -> bool {
  756        match *self {
  757            Self::Disabled => true,
  758            _ => false,
  759        }
  760    }
  761
  762    fn settings_visibility(&self) -> bool {
  763        match *self {
  764            Self::Enabled {
  765                setting_configuration,
  766                ..
  767            } => setting_configuration,
  768            _ => false,
  769        }
  770    }
  771
  772    fn visible(&self) -> bool {
  773        match *self {
  774            Self::Enabled {
  775                setting_configuration,
  776                toggle_override,
  777            } => setting_configuration ^ toggle_override,
  778            _ => false,
  779        }
  780    }
  781
  782    fn toggle_visibility(&self) -> Self {
  783        match *self {
  784            Self::Enabled {
  785                toggle_override,
  786                setting_configuration,
  787            } => Self::Enabled {
  788                setting_configuration,
  789                toggle_override: !toggle_override,
  790            },
  791            Self::Disabled => Self::Disabled,
  792        }
  793    }
  794}
  795
  796#[derive(Clone, Debug)]
  797struct RunnableTasks {
  798    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  799    offset: multi_buffer::Anchor,
  800    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  801    column: u32,
  802    // Values of all named captures, including those starting with '_'
  803    extra_variables: HashMap<String, String>,
  804    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  805    context_range: Range<BufferOffset>,
  806}
  807
  808impl RunnableTasks {
  809    fn resolve<'a>(
  810        &'a self,
  811        cx: &'a task::TaskContext,
  812    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  813        self.templates.iter().filter_map(|(kind, template)| {
  814            template
  815                .resolve_task(&kind.to_id_base(), cx)
  816                .map(|task| (kind.clone(), task))
  817        })
  818    }
  819}
  820
  821#[derive(Clone)]
  822pub struct ResolvedTasks {
  823    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  824    position: Anchor,
  825}
  826
  827#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  828struct BufferOffset(usize);
  829
  830// Addons allow storing per-editor state in other crates (e.g. Vim)
  831pub trait Addon: 'static {
  832    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  833
  834    fn render_buffer_header_controls(
  835        &self,
  836        _: &ExcerptInfo,
  837        _: &Window,
  838        _: &App,
  839    ) -> Option<AnyElement> {
  840        None
  841    }
  842
  843    fn to_any(&self) -> &dyn std::any::Any;
  844
  845    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  846        None
  847    }
  848}
  849
  850/// A set of caret positions, registered when the editor was edited.
  851pub struct ChangeList {
  852    changes: Vec<Vec<Anchor>>,
  853    /// Currently "selected" change.
  854    position: Option<usize>,
  855}
  856
  857impl ChangeList {
  858    pub fn new() -> Self {
  859        Self {
  860            changes: Vec::new(),
  861            position: None,
  862        }
  863    }
  864
  865    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  866    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  867    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  868        if self.changes.is_empty() {
  869            return None;
  870        }
  871
  872        let prev = self.position.unwrap_or(self.changes.len());
  873        let next = if direction == Direction::Prev {
  874            prev.saturating_sub(count)
  875        } else {
  876            (prev + count).min(self.changes.len() - 1)
  877        };
  878        self.position = Some(next);
  879        self.changes.get(next).map(|anchors| anchors.as_slice())
  880    }
  881
  882    /// Adds a new change to the list, resetting the change list position.
  883    pub fn push_to_change_list(&mut self, pop_state: bool, new_positions: Vec<Anchor>) {
  884        self.position.take();
  885        if pop_state {
  886            self.changes.pop();
  887        }
  888        self.changes.push(new_positions.clone());
  889    }
  890
  891    pub fn last(&self) -> Option<&[Anchor]> {
  892        self.changes.last().map(|anchors| anchors.as_slice())
  893    }
  894}
  895
  896#[derive(Clone)]
  897struct InlineBlamePopoverState {
  898    scroll_handle: ScrollHandle,
  899    commit_message: Option<ParsedCommitMessage>,
  900    markdown: Entity<Markdown>,
  901}
  902
  903struct InlineBlamePopover {
  904    position: gpui::Point<Pixels>,
  905    show_task: Option<Task<()>>,
  906    hide_task: Option<Task<()>>,
  907    popover_bounds: Option<Bounds<Pixels>>,
  908    popover_state: InlineBlamePopoverState,
  909}
  910
  911/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  912/// a breakpoint on them.
  913#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  914struct PhantomBreakpointIndicator {
  915    display_row: DisplayRow,
  916    /// There's a small debounce between hovering over the line and showing the indicator.
  917    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  918    is_active: bool,
  919    collides_with_existing_breakpoint: bool,
  920}
  921
  922/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  923///
  924/// See the [module level documentation](self) for more information.
  925pub struct Editor {
  926    focus_handle: FocusHandle,
  927    last_focused_descendant: Option<WeakFocusHandle>,
  928    /// The text buffer being edited
  929    buffer: Entity<MultiBuffer>,
  930    /// Map of how text in the buffer should be displayed.
  931    /// Handles soft wraps, folds, fake inlay text insertions, etc.
  932    pub display_map: Entity<DisplayMap>,
  933    pub selections: SelectionsCollection,
  934    pub scroll_manager: ScrollManager,
  935    /// When inline assist editors are linked, they all render cursors because
  936    /// typing enters text into each of them, even the ones that aren't focused.
  937    pub(crate) show_cursor_when_unfocused: bool,
  938    columnar_selection_tail: Option<Anchor>,
  939    columnar_display_point: Option<DisplayPoint>,
  940    add_selections_state: Option<AddSelectionsState>,
  941    select_next_state: Option<SelectNextState>,
  942    select_prev_state: Option<SelectNextState>,
  943    selection_history: SelectionHistory,
  944    defer_selection_effects: bool,
  945    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
  946    autoclose_regions: Vec<AutocloseRegion>,
  947    snippet_stack: InvalidationStack<SnippetState>,
  948    select_syntax_node_history: SelectSyntaxNodeHistory,
  949    ime_transaction: Option<TransactionId>,
  950    pub diagnostics_max_severity: DiagnosticSeverity,
  951    active_diagnostics: ActiveDiagnostic,
  952    show_inline_diagnostics: bool,
  953    inline_diagnostics_update: Task<()>,
  954    inline_diagnostics_enabled: bool,
  955    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
  956    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
  957    hard_wrap: Option<usize>,
  958
  959    // TODO: make this a access method
  960    pub project: Option<Entity<Project>>,
  961    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
  962    completion_provider: Option<Rc<dyn CompletionProvider>>,
  963    collaboration_hub: Option<Box<dyn CollaborationHub>>,
  964    blink_manager: Entity<BlinkManager>,
  965    show_cursor_names: bool,
  966    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
  967    pub show_local_selections: bool,
  968    mode: EditorMode,
  969    show_breadcrumbs: bool,
  970    show_gutter: bool,
  971    show_scrollbars: ScrollbarAxes,
  972    minimap_visibility: MinimapVisibility,
  973    offset_content: bool,
  974    disable_expand_excerpt_buttons: bool,
  975    show_line_numbers: Option<bool>,
  976    use_relative_line_numbers: Option<bool>,
  977    show_git_diff_gutter: Option<bool>,
  978    show_code_actions: Option<bool>,
  979    show_runnables: Option<bool>,
  980    show_breakpoints: Option<bool>,
  981    show_wrap_guides: Option<bool>,
  982    show_indent_guides: Option<bool>,
  983    placeholder_text: Option<Arc<str>>,
  984    highlight_order: usize,
  985    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
  986    background_highlights: TreeMap<TypeId, BackgroundHighlight>,
  987    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
  988    scrollbar_marker_state: ScrollbarMarkerState,
  989    active_indent_guides_state: ActiveIndentGuidesState,
  990    nav_history: Option<ItemNavHistory>,
  991    context_menu: RefCell<Option<CodeContextMenu>>,
  992    context_menu_options: Option<ContextMenuOptions>,
  993    mouse_context_menu: Option<MouseContextMenu>,
  994    completion_tasks: Vec<(CompletionId, Task<()>)>,
  995    inline_blame_popover: Option<InlineBlamePopover>,
  996    signature_help_state: SignatureHelpState,
  997    auto_signature_help: Option<bool>,
  998    find_all_references_task_sources: Vec<Anchor>,
  999    next_completion_id: CompletionId,
 1000    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1001    code_actions_task: Option<Task<Result<()>>>,
 1002    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1003    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1004    document_highlights_task: Option<Task<()>>,
 1005    linked_editing_range_task: Option<Task<Option<()>>>,
 1006    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1007    pending_rename: Option<RenameState>,
 1008    searchable: bool,
 1009    cursor_shape: CursorShape,
 1010    current_line_highlight: Option<CurrentLineHighlight>,
 1011    collapse_matches: bool,
 1012    autoindent_mode: Option<AutoindentMode>,
 1013    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1014    input_enabled: bool,
 1015    use_modal_editing: bool,
 1016    read_only: bool,
 1017    leader_id: Option<CollaboratorId>,
 1018    remote_id: Option<ViewId>,
 1019    pub hover_state: HoverState,
 1020    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1021    gutter_hovered: bool,
 1022    hovered_link_state: Option<HoveredLinkState>,
 1023    edit_prediction_provider: Option<RegisteredInlineCompletionProvider>,
 1024    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1025    active_inline_completion: Option<InlineCompletionState>,
 1026    /// Used to prevent flickering as the user types while the menu is open
 1027    stale_inline_completion_in_menu: Option<InlineCompletionState>,
 1028    edit_prediction_settings: EditPredictionSettings,
 1029    inline_completions_hidden_for_vim_mode: bool,
 1030    show_inline_completions_override: Option<bool>,
 1031    menu_inline_completions_policy: MenuInlineCompletionsPolicy,
 1032    edit_prediction_preview: EditPredictionPreview,
 1033    edit_prediction_indent_conflict: bool,
 1034    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1035    inlay_hint_cache: InlayHintCache,
 1036    next_inlay_id: usize,
 1037    _subscriptions: Vec<Subscription>,
 1038    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1039    gutter_dimensions: GutterDimensions,
 1040    style: Option<EditorStyle>,
 1041    text_style_refinement: Option<TextStyleRefinement>,
 1042    next_editor_action_id: EditorActionId,
 1043    editor_actions:
 1044        Rc<RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&mut Window, &mut Context<Self>)>>>>,
 1045    use_autoclose: bool,
 1046    use_auto_surround: bool,
 1047    auto_replace_emoji_shortcode: bool,
 1048    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1049    show_git_blame_gutter: bool,
 1050    show_git_blame_inline: bool,
 1051    show_git_blame_inline_delay_task: Option<Task<()>>,
 1052    git_blame_inline_enabled: bool,
 1053    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1054    serialize_dirty_buffers: bool,
 1055    show_selection_menu: Option<bool>,
 1056    blame: Option<Entity<GitBlame>>,
 1057    blame_subscription: Option<Subscription>,
 1058    custom_context_menu: Option<
 1059        Box<
 1060            dyn 'static
 1061                + Fn(
 1062                    &mut Self,
 1063                    DisplayPoint,
 1064                    &mut Window,
 1065                    &mut Context<Self>,
 1066                ) -> Option<Entity<ui::ContextMenu>>,
 1067        >,
 1068    >,
 1069    last_bounds: Option<Bounds<Pixels>>,
 1070    last_position_map: Option<Rc<PositionMap>>,
 1071    expect_bounds_change: Option<Bounds<Pixels>>,
 1072    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1073    tasks_update_task: Option<Task<()>>,
 1074    breakpoint_store: Option<Entity<BreakpointStore>>,
 1075    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1076    in_project_search: bool,
 1077    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1078    breadcrumb_header: Option<String>,
 1079    focused_block: Option<FocusedBlock>,
 1080    next_scroll_position: NextScrollCursorCenterTopBottom,
 1081    addons: HashMap<TypeId, Box<dyn Addon>>,
 1082    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1083    load_diff_task: Option<Shared<Task<()>>>,
 1084    /// Whether we are temporarily displaying a diff other than git's
 1085    temporary_diff_override: bool,
 1086    selection_mark_mode: bool,
 1087    toggle_fold_multiple_buffers: Task<()>,
 1088    _scroll_cursor_center_top_bottom_task: Task<()>,
 1089    serialize_selections: Task<()>,
 1090    serialize_folds: Task<()>,
 1091    mouse_cursor_hidden: bool,
 1092    minimap: Option<Entity<Self>>,
 1093    hide_mouse_mode: HideMouseMode,
 1094    pub change_list: ChangeList,
 1095    inline_value_cache: InlineValueCache,
 1096}
 1097
 1098#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1099enum NextScrollCursorCenterTopBottom {
 1100    #[default]
 1101    Center,
 1102    Top,
 1103    Bottom,
 1104}
 1105
 1106impl NextScrollCursorCenterTopBottom {
 1107    fn next(&self) -> Self {
 1108        match self {
 1109            Self::Center => Self::Top,
 1110            Self::Top => Self::Bottom,
 1111            Self::Bottom => Self::Center,
 1112        }
 1113    }
 1114}
 1115
 1116#[derive(Clone)]
 1117pub struct EditorSnapshot {
 1118    pub mode: EditorMode,
 1119    show_gutter: bool,
 1120    show_line_numbers: Option<bool>,
 1121    show_git_diff_gutter: Option<bool>,
 1122    show_code_actions: Option<bool>,
 1123    show_runnables: Option<bool>,
 1124    show_breakpoints: Option<bool>,
 1125    git_blame_gutter_max_author_length: Option<usize>,
 1126    pub display_snapshot: DisplaySnapshot,
 1127    pub placeholder_text: Option<Arc<str>>,
 1128    is_focused: bool,
 1129    scroll_anchor: ScrollAnchor,
 1130    ongoing_scroll: OngoingScroll,
 1131    current_line_highlight: CurrentLineHighlight,
 1132    gutter_hovered: bool,
 1133}
 1134
 1135#[derive(Default, Debug, Clone, Copy)]
 1136pub struct GutterDimensions {
 1137    pub left_padding: Pixels,
 1138    pub right_padding: Pixels,
 1139    pub width: Pixels,
 1140    pub margin: Pixels,
 1141    pub git_blame_entries_width: Option<Pixels>,
 1142}
 1143
 1144impl GutterDimensions {
 1145    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1146        Self {
 1147            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1148            ..Default::default()
 1149        }
 1150    }
 1151
 1152    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1153        -cx.text_system().descent(font_id, font_size)
 1154    }
 1155    /// The full width of the space taken up by the gutter.
 1156    pub fn full_width(&self) -> Pixels {
 1157        self.margin + self.width
 1158    }
 1159
 1160    /// The width of the space reserved for the fold indicators,
 1161    /// use alongside 'justify_end' and `gutter_width` to
 1162    /// right align content with the line numbers
 1163    pub fn fold_area_width(&self) -> Pixels {
 1164        self.margin + self.right_padding
 1165    }
 1166}
 1167
 1168#[derive(Debug)]
 1169pub struct RemoteSelection {
 1170    pub replica_id: ReplicaId,
 1171    pub selection: Selection<Anchor>,
 1172    pub cursor_shape: CursorShape,
 1173    pub collaborator_id: CollaboratorId,
 1174    pub line_mode: bool,
 1175    pub user_name: Option<SharedString>,
 1176    pub color: PlayerColor,
 1177}
 1178
 1179#[derive(Clone, Debug)]
 1180struct SelectionHistoryEntry {
 1181    selections: Arc<[Selection<Anchor>]>,
 1182    select_next_state: Option<SelectNextState>,
 1183    select_prev_state: Option<SelectNextState>,
 1184    add_selections_state: Option<AddSelectionsState>,
 1185}
 1186
 1187enum SelectionHistoryMode {
 1188    Normal,
 1189    Undoing,
 1190    Redoing,
 1191}
 1192
 1193#[derive(Clone, PartialEq, Eq, Hash)]
 1194struct HoveredCursor {
 1195    replica_id: u16,
 1196    selection_id: usize,
 1197}
 1198
 1199impl Default for SelectionHistoryMode {
 1200    fn default() -> Self {
 1201        Self::Normal
 1202    }
 1203}
 1204
 1205struct DeferredSelectionEffectsState {
 1206    changed: bool,
 1207    should_update_completions: bool,
 1208    autoscroll: Option<Autoscroll>,
 1209    old_cursor_position: Anchor,
 1210    history_entry: SelectionHistoryEntry,
 1211}
 1212
 1213#[derive(Default)]
 1214struct SelectionHistory {
 1215    #[allow(clippy::type_complexity)]
 1216    selections_by_transaction:
 1217        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1218    mode: SelectionHistoryMode,
 1219    undo_stack: VecDeque<SelectionHistoryEntry>,
 1220    redo_stack: VecDeque<SelectionHistoryEntry>,
 1221}
 1222
 1223impl SelectionHistory {
 1224    #[track_caller]
 1225    fn insert_transaction(
 1226        &mut self,
 1227        transaction_id: TransactionId,
 1228        selections: Arc<[Selection<Anchor>]>,
 1229    ) {
 1230        if selections.is_empty() {
 1231            log::error!(
 1232                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1233                std::panic::Location::caller()
 1234            );
 1235            return;
 1236        }
 1237        self.selections_by_transaction
 1238            .insert(transaction_id, (selections, None));
 1239    }
 1240
 1241    #[allow(clippy::type_complexity)]
 1242    fn transaction(
 1243        &self,
 1244        transaction_id: TransactionId,
 1245    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1246        self.selections_by_transaction.get(&transaction_id)
 1247    }
 1248
 1249    #[allow(clippy::type_complexity)]
 1250    fn transaction_mut(
 1251        &mut self,
 1252        transaction_id: TransactionId,
 1253    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1254        self.selections_by_transaction.get_mut(&transaction_id)
 1255    }
 1256
 1257    fn push(&mut self, entry: SelectionHistoryEntry) {
 1258        if !entry.selections.is_empty() {
 1259            match self.mode {
 1260                SelectionHistoryMode::Normal => {
 1261                    self.push_undo(entry);
 1262                    self.redo_stack.clear();
 1263                }
 1264                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1265                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1266            }
 1267        }
 1268    }
 1269
 1270    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1271        if self
 1272            .undo_stack
 1273            .back()
 1274            .map_or(true, |e| e.selections != entry.selections)
 1275        {
 1276            self.undo_stack.push_back(entry);
 1277            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1278                self.undo_stack.pop_front();
 1279            }
 1280        }
 1281    }
 1282
 1283    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1284        if self
 1285            .redo_stack
 1286            .back()
 1287            .map_or(true, |e| e.selections != entry.selections)
 1288        {
 1289            self.redo_stack.push_back(entry);
 1290            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1291                self.redo_stack.pop_front();
 1292            }
 1293        }
 1294    }
 1295}
 1296
 1297#[derive(Clone, Copy)]
 1298pub struct RowHighlightOptions {
 1299    pub autoscroll: bool,
 1300    pub include_gutter: bool,
 1301}
 1302
 1303impl Default for RowHighlightOptions {
 1304    fn default() -> Self {
 1305        Self {
 1306            autoscroll: Default::default(),
 1307            include_gutter: true,
 1308        }
 1309    }
 1310}
 1311
 1312struct RowHighlight {
 1313    index: usize,
 1314    range: Range<Anchor>,
 1315    color: Hsla,
 1316    options: RowHighlightOptions,
 1317    type_id: TypeId,
 1318}
 1319
 1320#[derive(Clone, Debug)]
 1321struct AddSelectionsState {
 1322    above: bool,
 1323    stack: Vec<usize>,
 1324}
 1325
 1326#[derive(Clone)]
 1327struct SelectNextState {
 1328    query: AhoCorasick,
 1329    wordwise: bool,
 1330    done: bool,
 1331}
 1332
 1333impl std::fmt::Debug for SelectNextState {
 1334    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1335        f.debug_struct(std::any::type_name::<Self>())
 1336            .field("wordwise", &self.wordwise)
 1337            .field("done", &self.done)
 1338            .finish()
 1339    }
 1340}
 1341
 1342#[derive(Debug)]
 1343struct AutocloseRegion {
 1344    selection_id: usize,
 1345    range: Range<Anchor>,
 1346    pair: BracketPair,
 1347}
 1348
 1349#[derive(Debug)]
 1350struct SnippetState {
 1351    ranges: Vec<Vec<Range<Anchor>>>,
 1352    active_index: usize,
 1353    choices: Vec<Option<Vec<String>>>,
 1354}
 1355
 1356#[doc(hidden)]
 1357pub struct RenameState {
 1358    pub range: Range<Anchor>,
 1359    pub old_name: Arc<str>,
 1360    pub editor: Entity<Editor>,
 1361    block_id: CustomBlockId,
 1362}
 1363
 1364struct InvalidationStack<T>(Vec<T>);
 1365
 1366struct RegisteredInlineCompletionProvider {
 1367    provider: Arc<dyn InlineCompletionProviderHandle>,
 1368    _subscription: Subscription,
 1369}
 1370
 1371#[derive(Debug, PartialEq, Eq)]
 1372pub struct ActiveDiagnosticGroup {
 1373    pub active_range: Range<Anchor>,
 1374    pub active_message: String,
 1375    pub group_id: usize,
 1376    pub blocks: HashSet<CustomBlockId>,
 1377}
 1378
 1379#[derive(Debug, PartialEq, Eq)]
 1380
 1381pub(crate) enum ActiveDiagnostic {
 1382    None,
 1383    All,
 1384    Group(ActiveDiagnosticGroup),
 1385}
 1386
 1387#[derive(Serialize, Deserialize, Clone, Debug)]
 1388pub struct ClipboardSelection {
 1389    /// The number of bytes in this selection.
 1390    pub len: usize,
 1391    /// Whether this was a full-line selection.
 1392    pub is_entire_line: bool,
 1393    /// The indentation of the first line when this content was originally copied.
 1394    pub first_line_indent: u32,
 1395}
 1396
 1397// selections, scroll behavior, was newest selection reversed
 1398type SelectSyntaxNodeHistoryState = (
 1399    Box<[Selection<usize>]>,
 1400    SelectSyntaxNodeScrollBehavior,
 1401    bool,
 1402);
 1403
 1404#[derive(Default)]
 1405struct SelectSyntaxNodeHistory {
 1406    stack: Vec<SelectSyntaxNodeHistoryState>,
 1407    // disable temporarily to allow changing selections without losing the stack
 1408    pub disable_clearing: bool,
 1409}
 1410
 1411impl SelectSyntaxNodeHistory {
 1412    pub fn try_clear(&mut self) {
 1413        if !self.disable_clearing {
 1414            self.stack.clear();
 1415        }
 1416    }
 1417
 1418    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1419        self.stack.push(selection);
 1420    }
 1421
 1422    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1423        self.stack.pop()
 1424    }
 1425}
 1426
 1427enum SelectSyntaxNodeScrollBehavior {
 1428    CursorTop,
 1429    FitSelection,
 1430    CursorBottom,
 1431}
 1432
 1433#[derive(Debug)]
 1434pub(crate) struct NavigationData {
 1435    cursor_anchor: Anchor,
 1436    cursor_position: Point,
 1437    scroll_anchor: ScrollAnchor,
 1438    scroll_top_row: u32,
 1439}
 1440
 1441#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1442pub enum GotoDefinitionKind {
 1443    Symbol,
 1444    Declaration,
 1445    Type,
 1446    Implementation,
 1447}
 1448
 1449#[derive(Debug, Clone)]
 1450enum InlayHintRefreshReason {
 1451    ModifiersChanged(bool),
 1452    Toggle(bool),
 1453    SettingsChange(InlayHintSettings),
 1454    NewLinesShown,
 1455    BufferEdited(HashSet<Arc<Language>>),
 1456    RefreshRequested,
 1457    ExcerptsRemoved(Vec<ExcerptId>),
 1458}
 1459
 1460impl InlayHintRefreshReason {
 1461    fn description(&self) -> &'static str {
 1462        match self {
 1463            Self::ModifiersChanged(_) => "modifiers changed",
 1464            Self::Toggle(_) => "toggle",
 1465            Self::SettingsChange(_) => "settings change",
 1466            Self::NewLinesShown => "new lines shown",
 1467            Self::BufferEdited(_) => "buffer edited",
 1468            Self::RefreshRequested => "refresh requested",
 1469            Self::ExcerptsRemoved(_) => "excerpts removed",
 1470        }
 1471    }
 1472}
 1473
 1474pub enum FormatTarget {
 1475    Buffers,
 1476    Ranges(Vec<Range<MultiBufferPoint>>),
 1477}
 1478
 1479pub(crate) struct FocusedBlock {
 1480    id: BlockId,
 1481    focus_handle: WeakFocusHandle,
 1482}
 1483
 1484#[derive(Clone)]
 1485enum JumpData {
 1486    MultiBufferRow {
 1487        row: MultiBufferRow,
 1488        line_offset_from_top: u32,
 1489    },
 1490    MultiBufferPoint {
 1491        excerpt_id: ExcerptId,
 1492        position: Point,
 1493        anchor: text::Anchor,
 1494        line_offset_from_top: u32,
 1495    },
 1496}
 1497
 1498pub enum MultibufferSelectionMode {
 1499    First,
 1500    All,
 1501}
 1502
 1503#[derive(Clone, Copy, Debug, Default)]
 1504pub struct RewrapOptions {
 1505    pub override_language_settings: bool,
 1506    pub preserve_existing_whitespace: bool,
 1507}
 1508
 1509impl Editor {
 1510    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1511        let buffer = cx.new(|cx| Buffer::local("", cx));
 1512        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1513        Self::new(
 1514            EditorMode::SingleLine { auto_width: false },
 1515            buffer,
 1516            None,
 1517            window,
 1518            cx,
 1519        )
 1520    }
 1521
 1522    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1523        let buffer = cx.new(|cx| Buffer::local("", cx));
 1524        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1525        Self::new(EditorMode::full(), buffer, None, window, cx)
 1526    }
 1527
 1528    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1529        let buffer = cx.new(|cx| Buffer::local("", cx));
 1530        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1531        Self::new(
 1532            EditorMode::SingleLine { auto_width: true },
 1533            buffer,
 1534            None,
 1535            window,
 1536            cx,
 1537        )
 1538    }
 1539
 1540    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1541        let buffer = cx.new(|cx| Buffer::local("", cx));
 1542        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1543        Self::new(
 1544            EditorMode::AutoHeight { max_lines },
 1545            buffer,
 1546            None,
 1547            window,
 1548            cx,
 1549        )
 1550    }
 1551
 1552    pub fn for_buffer(
 1553        buffer: Entity<Buffer>,
 1554        project: Option<Entity<Project>>,
 1555        window: &mut Window,
 1556        cx: &mut Context<Self>,
 1557    ) -> Self {
 1558        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1559        Self::new(EditorMode::full(), buffer, project, window, cx)
 1560    }
 1561
 1562    pub fn for_multibuffer(
 1563        buffer: Entity<MultiBuffer>,
 1564        project: Option<Entity<Project>>,
 1565        window: &mut Window,
 1566        cx: &mut Context<Self>,
 1567    ) -> Self {
 1568        Self::new(EditorMode::full(), buffer, project, window, cx)
 1569    }
 1570
 1571    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1572        let mut clone = Self::new(
 1573            self.mode.clone(),
 1574            self.buffer.clone(),
 1575            self.project.clone(),
 1576            window,
 1577            cx,
 1578        );
 1579        self.display_map.update(cx, |display_map, cx| {
 1580            let snapshot = display_map.snapshot(cx);
 1581            clone.display_map.update(cx, |display_map, cx| {
 1582                display_map.set_state(&snapshot, cx);
 1583            });
 1584        });
 1585        clone.folds_did_change(cx);
 1586        clone.selections.clone_state(&self.selections);
 1587        clone.scroll_manager.clone_state(&self.scroll_manager);
 1588        clone.searchable = self.searchable;
 1589        clone.read_only = self.read_only;
 1590        clone
 1591    }
 1592
 1593    pub fn new(
 1594        mode: EditorMode,
 1595        buffer: Entity<MultiBuffer>,
 1596        project: Option<Entity<Project>>,
 1597        window: &mut Window,
 1598        cx: &mut Context<Self>,
 1599    ) -> Self {
 1600        Editor::new_internal(mode, buffer, project, None, window, cx)
 1601    }
 1602
 1603    fn new_internal(
 1604        mode: EditorMode,
 1605        buffer: Entity<MultiBuffer>,
 1606        project: Option<Entity<Project>>,
 1607        display_map: Option<Entity<DisplayMap>>,
 1608        window: &mut Window,
 1609        cx: &mut Context<Self>,
 1610    ) -> Self {
 1611        debug_assert!(
 1612            display_map.is_none() || mode.is_minimap(),
 1613            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1614        );
 1615
 1616        let full_mode = mode.is_full();
 1617        let diagnostics_max_severity = if full_mode {
 1618            EditorSettings::get_global(cx)
 1619                .diagnostics_max_severity
 1620                .unwrap_or(DiagnosticSeverity::Hint)
 1621        } else {
 1622            DiagnosticSeverity::Off
 1623        };
 1624        let style = window.text_style();
 1625        let font_size = style.font_size.to_pixels(window.rem_size());
 1626        let editor = cx.entity().downgrade();
 1627        let fold_placeholder = FoldPlaceholder {
 1628            constrain_width: true,
 1629            render: Arc::new(move |fold_id, fold_range, cx| {
 1630                let editor = editor.clone();
 1631                div()
 1632                    .id(fold_id)
 1633                    .bg(cx.theme().colors().ghost_element_background)
 1634                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1635                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1636                    .rounded_xs()
 1637                    .size_full()
 1638                    .cursor_pointer()
 1639                    .child("")
 1640                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1641                    .on_click(move |_, _window, cx| {
 1642                        editor
 1643                            .update(cx, |editor, cx| {
 1644                                editor.unfold_ranges(
 1645                                    &[fold_range.start..fold_range.end],
 1646                                    true,
 1647                                    false,
 1648                                    cx,
 1649                                );
 1650                                cx.stop_propagation();
 1651                            })
 1652                            .ok();
 1653                    })
 1654                    .into_any()
 1655            }),
 1656            merge_adjacent: true,
 1657            ..FoldPlaceholder::default()
 1658        };
 1659        let display_map = display_map.unwrap_or_else(|| {
 1660            cx.new(|cx| {
 1661                DisplayMap::new(
 1662                    buffer.clone(),
 1663                    style.font(),
 1664                    font_size,
 1665                    None,
 1666                    FILE_HEADER_HEIGHT,
 1667                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1668                    fold_placeholder,
 1669                    diagnostics_max_severity,
 1670                    cx,
 1671                )
 1672            })
 1673        });
 1674
 1675        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1676
 1677        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1678
 1679        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1680            .then(|| language_settings::SoftWrap::None);
 1681
 1682        let mut project_subscriptions = Vec::new();
 1683        if mode.is_full() {
 1684            if let Some(project) = project.as_ref() {
 1685                project_subscriptions.push(cx.subscribe_in(
 1686                    project,
 1687                    window,
 1688                    |editor, _, event, window, cx| match event {
 1689                        project::Event::RefreshCodeLens => {
 1690                            // we always query lens with actions, without storing them, always refreshing them
 1691                        }
 1692                        project::Event::RefreshInlayHints => {
 1693                            editor
 1694                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1695                        }
 1696                        project::Event::LanguageServerAdded(..)
 1697                        | project::Event::LanguageServerRemoved(..) => {
 1698                            if editor.tasks_update_task.is_none() {
 1699                                editor.tasks_update_task =
 1700                                    Some(editor.refresh_runnables(window, cx));
 1701                            }
 1702                        }
 1703                        project::Event::SnippetEdit(id, snippet_edits) => {
 1704                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1705                                let focus_handle = editor.focus_handle(cx);
 1706                                if focus_handle.is_focused(window) {
 1707                                    let snapshot = buffer.read(cx).snapshot();
 1708                                    for (range, snippet) in snippet_edits {
 1709                                        let editor_range =
 1710                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1711                                        editor
 1712                                            .insert_snippet(
 1713                                                &[editor_range],
 1714                                                snippet.clone(),
 1715                                                window,
 1716                                                cx,
 1717                                            )
 1718                                            .ok();
 1719                                    }
 1720                                }
 1721                            }
 1722                        }
 1723                        _ => {}
 1724                    },
 1725                ));
 1726                if let Some(task_inventory) = project
 1727                    .read(cx)
 1728                    .task_store()
 1729                    .read(cx)
 1730                    .task_inventory()
 1731                    .cloned()
 1732                {
 1733                    project_subscriptions.push(cx.observe_in(
 1734                        &task_inventory,
 1735                        window,
 1736                        |editor, _, window, cx| {
 1737                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1738                        },
 1739                    ));
 1740                };
 1741
 1742                project_subscriptions.push(cx.subscribe_in(
 1743                    &project.read(cx).breakpoint_store(),
 1744                    window,
 1745                    |editor, _, event, window, cx| match event {
 1746                        BreakpointStoreEvent::ClearDebugLines => {
 1747                            editor.clear_row_highlights::<ActiveDebugLine>();
 1748                            editor.refresh_inline_values(cx);
 1749                        }
 1750                        BreakpointStoreEvent::SetDebugLine => {
 1751                            if editor.go_to_active_debug_line(window, cx) {
 1752                                cx.stop_propagation();
 1753                            }
 1754
 1755                            editor.refresh_inline_values(cx);
 1756                        }
 1757                        _ => {}
 1758                    },
 1759                ));
 1760            }
 1761        }
 1762
 1763        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1764
 1765        let inlay_hint_settings =
 1766            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1767        let focus_handle = cx.focus_handle();
 1768        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1769            .detach();
 1770        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1771            .detach();
 1772        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1773            .detach();
 1774        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1775            .detach();
 1776
 1777        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1778            Some(false)
 1779        } else {
 1780            None
 1781        };
 1782
 1783        let breakpoint_store = match (&mode, project.as_ref()) {
 1784            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1785            _ => None,
 1786        };
 1787
 1788        let mut code_action_providers = Vec::new();
 1789        let mut load_uncommitted_diff = None;
 1790        if let Some(project) = project.clone() {
 1791            load_uncommitted_diff = Some(
 1792                update_uncommitted_diff_for_buffer(
 1793                    cx.entity(),
 1794                    &project,
 1795                    buffer.read(cx).all_buffers(),
 1796                    buffer.clone(),
 1797                    cx,
 1798                )
 1799                .shared(),
 1800            );
 1801            code_action_providers.push(Rc::new(project) as Rc<_>);
 1802        }
 1803
 1804        let mut this = Self {
 1805            focus_handle,
 1806            show_cursor_when_unfocused: false,
 1807            last_focused_descendant: None,
 1808            buffer: buffer.clone(),
 1809            display_map: display_map.clone(),
 1810            selections,
 1811            scroll_manager: ScrollManager::new(cx),
 1812            columnar_selection_tail: None,
 1813            columnar_display_point: None,
 1814            add_selections_state: None,
 1815            select_next_state: None,
 1816            select_prev_state: None,
 1817            selection_history: SelectionHistory::default(),
 1818            defer_selection_effects: false,
 1819            deferred_selection_effects_state: None,
 1820            autoclose_regions: Vec::new(),
 1821            snippet_stack: InvalidationStack::default(),
 1822            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1823            ime_transaction: None,
 1824            active_diagnostics: ActiveDiagnostic::None,
 1825            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1826            inline_diagnostics_update: Task::ready(()),
 1827            inline_diagnostics: Vec::new(),
 1828            soft_wrap_mode_override,
 1829            diagnostics_max_severity,
 1830            hard_wrap: None,
 1831            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1832            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1833            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1834            project,
 1835            blink_manager: blink_manager.clone(),
 1836            show_local_selections: true,
 1837            show_scrollbars: ScrollbarAxes {
 1838                horizontal: full_mode,
 1839                vertical: full_mode,
 1840            },
 1841            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1842            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1843            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1844            show_gutter: mode.is_full(),
 1845            show_line_numbers: None,
 1846            use_relative_line_numbers: None,
 1847            disable_expand_excerpt_buttons: false,
 1848            show_git_diff_gutter: None,
 1849            show_code_actions: None,
 1850            show_runnables: None,
 1851            show_breakpoints: None,
 1852            show_wrap_guides: None,
 1853            show_indent_guides,
 1854            placeholder_text: None,
 1855            highlight_order: 0,
 1856            highlighted_rows: HashMap::default(),
 1857            background_highlights: TreeMap::default(),
 1858            gutter_highlights: TreeMap::default(),
 1859            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1860            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1861            nav_history: None,
 1862            context_menu: RefCell::new(None),
 1863            context_menu_options: None,
 1864            mouse_context_menu: None,
 1865            completion_tasks: Vec::new(),
 1866            inline_blame_popover: None,
 1867            signature_help_state: SignatureHelpState::default(),
 1868            auto_signature_help: None,
 1869            find_all_references_task_sources: Vec::new(),
 1870            next_completion_id: 0,
 1871            next_inlay_id: 0,
 1872            code_action_providers,
 1873            available_code_actions: None,
 1874            code_actions_task: None,
 1875            quick_selection_highlight_task: None,
 1876            debounced_selection_highlight_task: None,
 1877            document_highlights_task: None,
 1878            linked_editing_range_task: None,
 1879            pending_rename: None,
 1880            searchable: true,
 1881            cursor_shape: EditorSettings::get_global(cx)
 1882                .cursor_shape
 1883                .unwrap_or_default(),
 1884            current_line_highlight: None,
 1885            autoindent_mode: Some(AutoindentMode::EachLine),
 1886            collapse_matches: false,
 1887            workspace: None,
 1888            input_enabled: true,
 1889            use_modal_editing: mode.is_full(),
 1890            read_only: mode.is_minimap(),
 1891            use_autoclose: true,
 1892            use_auto_surround: true,
 1893            auto_replace_emoji_shortcode: false,
 1894            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1895            leader_id: None,
 1896            remote_id: None,
 1897            hover_state: HoverState::default(),
 1898            pending_mouse_down: None,
 1899            hovered_link_state: None,
 1900            edit_prediction_provider: None,
 1901            active_inline_completion: None,
 1902            stale_inline_completion_in_menu: None,
 1903            edit_prediction_preview: EditPredictionPreview::Inactive {
 1904                released_too_fast: false,
 1905            },
 1906            inline_diagnostics_enabled: mode.is_full(),
 1907            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1908            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1909
 1910            gutter_hovered: false,
 1911            pixel_position_of_newest_cursor: None,
 1912            last_bounds: None,
 1913            last_position_map: None,
 1914            expect_bounds_change: None,
 1915            gutter_dimensions: GutterDimensions::default(),
 1916            style: None,
 1917            show_cursor_names: false,
 1918            hovered_cursors: HashMap::default(),
 1919            next_editor_action_id: EditorActionId::default(),
 1920            editor_actions: Rc::default(),
 1921            inline_completions_hidden_for_vim_mode: false,
 1922            show_inline_completions_override: None,
 1923            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1924            edit_prediction_settings: EditPredictionSettings::Disabled,
 1925            edit_prediction_indent_conflict: false,
 1926            edit_prediction_requires_modifier_in_indent_conflict: true,
 1927            custom_context_menu: None,
 1928            show_git_blame_gutter: false,
 1929            show_git_blame_inline: false,
 1930            show_selection_menu: None,
 1931            show_git_blame_inline_delay_task: None,
 1932            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1933            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1934            serialize_dirty_buffers: !mode.is_minimap()
 1935                && ProjectSettings::get_global(cx)
 1936                    .session
 1937                    .restore_unsaved_buffers,
 1938            blame: None,
 1939            blame_subscription: None,
 1940            tasks: BTreeMap::default(),
 1941
 1942            breakpoint_store,
 1943            gutter_breakpoint_indicator: (None, None),
 1944            _subscriptions: vec![
 1945                cx.observe(&buffer, Self::on_buffer_changed),
 1946                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1947                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1948                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1949                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1950                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1951                cx.observe_window_activation(window, |editor, window, cx| {
 1952                    let active = window.is_window_active();
 1953                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1954                        if active {
 1955                            blink_manager.enable(cx);
 1956                        } else {
 1957                            blink_manager.disable(cx);
 1958                        }
 1959                    });
 1960                    if active {
 1961                        editor.show_mouse_cursor();
 1962                    }
 1963                }),
 1964            ],
 1965            tasks_update_task: None,
 1966            linked_edit_ranges: Default::default(),
 1967            in_project_search: false,
 1968            previous_search_ranges: None,
 1969            breadcrumb_header: None,
 1970            focused_block: None,
 1971            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1972            addons: HashMap::default(),
 1973            registered_buffers: HashMap::default(),
 1974            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1975            selection_mark_mode: false,
 1976            toggle_fold_multiple_buffers: Task::ready(()),
 1977            serialize_selections: Task::ready(()),
 1978            serialize_folds: Task::ready(()),
 1979            text_style_refinement: None,
 1980            load_diff_task: load_uncommitted_diff,
 1981            temporary_diff_override: false,
 1982            mouse_cursor_hidden: false,
 1983            minimap: None,
 1984            hide_mouse_mode: EditorSettings::get_global(cx)
 1985                .hide_mouse
 1986                .unwrap_or_default(),
 1987            change_list: ChangeList::new(),
 1988            mode,
 1989        };
 1990        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1991            this._subscriptions
 1992                .push(cx.observe(breakpoints, |_, _, cx| {
 1993                    cx.notify();
 1994                }));
 1995        }
 1996        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1997        this._subscriptions.extend(project_subscriptions);
 1998
 1999        this._subscriptions.push(cx.subscribe_in(
 2000            &cx.entity(),
 2001            window,
 2002            |editor, _, e: &EditorEvent, window, cx| match e {
 2003                EditorEvent::ScrollPositionChanged { local, .. } => {
 2004                    if *local {
 2005                        let new_anchor = editor.scroll_manager.anchor();
 2006                        let snapshot = editor.snapshot(window, cx);
 2007                        editor.update_restoration_data(cx, move |data| {
 2008                            data.scroll_position = (
 2009                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2010                                new_anchor.offset,
 2011                            );
 2012                        });
 2013                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2014                        editor.inline_blame_popover.take();
 2015                    }
 2016                }
 2017                EditorEvent::Edited { .. } => {
 2018                    if !vim_enabled(cx) {
 2019                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2020                        let pop_state = editor
 2021                            .change_list
 2022                            .last()
 2023                            .map(|previous| {
 2024                                previous.len() == selections.len()
 2025                                    && previous.iter().enumerate().all(|(ix, p)| {
 2026                                        p.to_display_point(&map).row()
 2027                                            == selections[ix].head().row()
 2028                                    })
 2029                            })
 2030                            .unwrap_or(false);
 2031                        let new_positions = selections
 2032                            .into_iter()
 2033                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2034                            .collect();
 2035                        editor
 2036                            .change_list
 2037                            .push_to_change_list(pop_state, new_positions);
 2038                    }
 2039                }
 2040                _ => (),
 2041            },
 2042        ));
 2043
 2044        if let Some(dap_store) = this
 2045            .project
 2046            .as_ref()
 2047            .map(|project| project.read(cx).dap_store())
 2048        {
 2049            let weak_editor = cx.weak_entity();
 2050
 2051            this._subscriptions
 2052                .push(
 2053                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2054                        let session_entity = cx.entity();
 2055                        weak_editor
 2056                            .update(cx, |editor, cx| {
 2057                                editor._subscriptions.push(
 2058                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2059                                );
 2060                            })
 2061                            .ok();
 2062                    }),
 2063                );
 2064
 2065            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2066                this._subscriptions
 2067                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2068            }
 2069        }
 2070
 2071        this.end_selection(window, cx);
 2072        this.scroll_manager.show_scrollbars(window, cx);
 2073        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 2074
 2075        if full_mode {
 2076            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2077            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2078
 2079            if this.git_blame_inline_enabled {
 2080                this.start_git_blame_inline(false, window, cx);
 2081            }
 2082
 2083            this.go_to_active_debug_line(window, cx);
 2084
 2085            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2086                if let Some(project) = this.project.as_ref() {
 2087                    let handle = project.update(cx, |project, cx| {
 2088                        project.register_buffer_with_language_servers(&buffer, cx)
 2089                    });
 2090                    this.registered_buffers
 2091                        .insert(buffer.read(cx).remote_id(), handle);
 2092                }
 2093            }
 2094
 2095            this.minimap = this.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2096        }
 2097
 2098        this.report_editor_event("Editor Opened", None, cx);
 2099        this
 2100    }
 2101
 2102    pub fn deploy_mouse_context_menu(
 2103        &mut self,
 2104        position: gpui::Point<Pixels>,
 2105        context_menu: Entity<ContextMenu>,
 2106        window: &mut Window,
 2107        cx: &mut Context<Self>,
 2108    ) {
 2109        self.mouse_context_menu = Some(MouseContextMenu::new(
 2110            self,
 2111            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2112            context_menu,
 2113            window,
 2114            cx,
 2115        ));
 2116    }
 2117
 2118    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2119        self.mouse_context_menu
 2120            .as_ref()
 2121            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2122    }
 2123
 2124    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2125        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2126    }
 2127
 2128    fn key_context_internal(
 2129        &self,
 2130        has_active_edit_prediction: bool,
 2131        window: &Window,
 2132        cx: &App,
 2133    ) -> KeyContext {
 2134        let mut key_context = KeyContext::new_with_defaults();
 2135        key_context.add("Editor");
 2136        let mode = match self.mode {
 2137            EditorMode::SingleLine { .. } => "single_line",
 2138            EditorMode::AutoHeight { .. } => "auto_height",
 2139            EditorMode::Minimap { .. } => "minimap",
 2140            EditorMode::Full { .. } => "full",
 2141        };
 2142
 2143        if EditorSettings::jupyter_enabled(cx) {
 2144            key_context.add("jupyter");
 2145        }
 2146
 2147        key_context.set("mode", mode);
 2148        if self.pending_rename.is_some() {
 2149            key_context.add("renaming");
 2150        }
 2151
 2152        match self.context_menu.borrow().as_ref() {
 2153            Some(CodeContextMenu::Completions(_)) => {
 2154                key_context.add("menu");
 2155                key_context.add("showing_completions");
 2156            }
 2157            Some(CodeContextMenu::CodeActions(_)) => {
 2158                key_context.add("menu");
 2159                key_context.add("showing_code_actions")
 2160            }
 2161            None => {}
 2162        }
 2163
 2164        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2165        if !self.focus_handle(cx).contains_focused(window, cx)
 2166            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2167        {
 2168            for addon in self.addons.values() {
 2169                addon.extend_key_context(&mut key_context, cx)
 2170            }
 2171        }
 2172
 2173        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2174            if let Some(extension) = singleton_buffer
 2175                .read(cx)
 2176                .file()
 2177                .and_then(|file| file.path().extension()?.to_str())
 2178            {
 2179                key_context.set("extension", extension.to_string());
 2180            }
 2181        } else {
 2182            key_context.add("multibuffer");
 2183        }
 2184
 2185        if has_active_edit_prediction {
 2186            if self.edit_prediction_in_conflict() {
 2187                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2188            } else {
 2189                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2190                key_context.add("copilot_suggestion");
 2191            }
 2192        }
 2193
 2194        if self.selection_mark_mode {
 2195            key_context.add("selection_mode");
 2196        }
 2197
 2198        key_context
 2199    }
 2200
 2201    fn show_mouse_cursor(&mut self) {
 2202        self.mouse_cursor_hidden = false;
 2203    }
 2204
 2205    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2206        self.mouse_cursor_hidden = match origin {
 2207            HideMouseCursorOrigin::TypingAction => {
 2208                matches!(
 2209                    self.hide_mouse_mode,
 2210                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2211                )
 2212            }
 2213            HideMouseCursorOrigin::MovementAction => {
 2214                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2215            }
 2216        };
 2217    }
 2218
 2219    pub fn edit_prediction_in_conflict(&self) -> bool {
 2220        if !self.show_edit_predictions_in_menu() {
 2221            return false;
 2222        }
 2223
 2224        let showing_completions = self
 2225            .context_menu
 2226            .borrow()
 2227            .as_ref()
 2228            .map_or(false, |context| {
 2229                matches!(context, CodeContextMenu::Completions(_))
 2230            });
 2231
 2232        showing_completions
 2233            || self.edit_prediction_requires_modifier()
 2234            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2235            // bindings to insert tab characters.
 2236            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2237    }
 2238
 2239    pub fn accept_edit_prediction_keybind(
 2240        &self,
 2241        window: &Window,
 2242        cx: &App,
 2243    ) -> AcceptEditPredictionBinding {
 2244        let key_context = self.key_context_internal(true, window, cx);
 2245        let in_conflict = self.edit_prediction_in_conflict();
 2246
 2247        AcceptEditPredictionBinding(
 2248            window
 2249                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2250                .into_iter()
 2251                .filter(|binding| {
 2252                    !in_conflict
 2253                        || binding
 2254                            .keystrokes()
 2255                            .first()
 2256                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 2257                })
 2258                .rev()
 2259                .min_by_key(|binding| {
 2260                    binding
 2261                        .keystrokes()
 2262                        .first()
 2263                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 2264                }),
 2265        )
 2266    }
 2267
 2268    pub fn new_file(
 2269        workspace: &mut Workspace,
 2270        _: &workspace::NewFile,
 2271        window: &mut Window,
 2272        cx: &mut Context<Workspace>,
 2273    ) {
 2274        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2275            "Failed to create buffer",
 2276            window,
 2277            cx,
 2278            |e, _, _| match e.error_code() {
 2279                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2280                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2281                e.error_tag("required").unwrap_or("the latest version")
 2282            )),
 2283                _ => None,
 2284            },
 2285        );
 2286    }
 2287
 2288    pub fn new_in_workspace(
 2289        workspace: &mut Workspace,
 2290        window: &mut Window,
 2291        cx: &mut Context<Workspace>,
 2292    ) -> Task<Result<Entity<Editor>>> {
 2293        let project = workspace.project().clone();
 2294        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2295
 2296        cx.spawn_in(window, async move |workspace, cx| {
 2297            let buffer = create.await?;
 2298            workspace.update_in(cx, |workspace, window, cx| {
 2299                let editor =
 2300                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2301                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2302                editor
 2303            })
 2304        })
 2305    }
 2306
 2307    fn new_file_vertical(
 2308        workspace: &mut Workspace,
 2309        _: &workspace::NewFileSplitVertical,
 2310        window: &mut Window,
 2311        cx: &mut Context<Workspace>,
 2312    ) {
 2313        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2314    }
 2315
 2316    fn new_file_horizontal(
 2317        workspace: &mut Workspace,
 2318        _: &workspace::NewFileSplitHorizontal,
 2319        window: &mut Window,
 2320        cx: &mut Context<Workspace>,
 2321    ) {
 2322        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2323    }
 2324
 2325    fn new_file_in_direction(
 2326        workspace: &mut Workspace,
 2327        direction: SplitDirection,
 2328        window: &mut Window,
 2329        cx: &mut Context<Workspace>,
 2330    ) {
 2331        let project = workspace.project().clone();
 2332        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2333
 2334        cx.spawn_in(window, async move |workspace, cx| {
 2335            let buffer = create.await?;
 2336            workspace.update_in(cx, move |workspace, window, cx| {
 2337                workspace.split_item(
 2338                    direction,
 2339                    Box::new(
 2340                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2341                    ),
 2342                    window,
 2343                    cx,
 2344                )
 2345            })?;
 2346            anyhow::Ok(())
 2347        })
 2348        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2349            match e.error_code() {
 2350                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2351                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2352                e.error_tag("required").unwrap_or("the latest version")
 2353            )),
 2354                _ => None,
 2355            }
 2356        });
 2357    }
 2358
 2359    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2360        self.leader_id
 2361    }
 2362
 2363    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2364        &self.buffer
 2365    }
 2366
 2367    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2368        self.workspace.as_ref()?.0.upgrade()
 2369    }
 2370
 2371    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2372        self.buffer().read(cx).title(cx)
 2373    }
 2374
 2375    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2376        let git_blame_gutter_max_author_length = self
 2377            .render_git_blame_gutter(cx)
 2378            .then(|| {
 2379                if let Some(blame) = self.blame.as_ref() {
 2380                    let max_author_length =
 2381                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2382                    Some(max_author_length)
 2383                } else {
 2384                    None
 2385                }
 2386            })
 2387            .flatten();
 2388
 2389        EditorSnapshot {
 2390            mode: self.mode.clone(),
 2391            show_gutter: self.show_gutter,
 2392            show_line_numbers: self.show_line_numbers,
 2393            show_git_diff_gutter: self.show_git_diff_gutter,
 2394            show_code_actions: self.show_code_actions,
 2395            show_runnables: self.show_runnables,
 2396            show_breakpoints: self.show_breakpoints,
 2397            git_blame_gutter_max_author_length,
 2398            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2399            scroll_anchor: self.scroll_manager.anchor(),
 2400            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2401            placeholder_text: self.placeholder_text.clone(),
 2402            is_focused: self.focus_handle.is_focused(window),
 2403            current_line_highlight: self
 2404                .current_line_highlight
 2405                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2406            gutter_hovered: self.gutter_hovered,
 2407        }
 2408    }
 2409
 2410    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2411        self.buffer.read(cx).language_at(point, cx)
 2412    }
 2413
 2414    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2415        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2416    }
 2417
 2418    pub fn active_excerpt(
 2419        &self,
 2420        cx: &App,
 2421    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2422        self.buffer
 2423            .read(cx)
 2424            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2425    }
 2426
 2427    pub fn mode(&self) -> &EditorMode {
 2428        &self.mode
 2429    }
 2430
 2431    pub fn set_mode(&mut self, mode: EditorMode) {
 2432        self.mode = mode;
 2433    }
 2434
 2435    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2436        self.collaboration_hub.as_deref()
 2437    }
 2438
 2439    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2440        self.collaboration_hub = Some(hub);
 2441    }
 2442
 2443    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2444        self.in_project_search = in_project_search;
 2445    }
 2446
 2447    pub fn set_custom_context_menu(
 2448        &mut self,
 2449        f: impl 'static
 2450        + Fn(
 2451            &mut Self,
 2452            DisplayPoint,
 2453            &mut Window,
 2454            &mut Context<Self>,
 2455        ) -> Option<Entity<ui::ContextMenu>>,
 2456    ) {
 2457        self.custom_context_menu = Some(Box::new(f))
 2458    }
 2459
 2460    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2461        self.completion_provider = provider;
 2462    }
 2463
 2464    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2465        self.semantics_provider.clone()
 2466    }
 2467
 2468    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2469        self.semantics_provider = provider;
 2470    }
 2471
 2472    pub fn set_edit_prediction_provider<T>(
 2473        &mut self,
 2474        provider: Option<Entity<T>>,
 2475        window: &mut Window,
 2476        cx: &mut Context<Self>,
 2477    ) where
 2478        T: EditPredictionProvider,
 2479    {
 2480        self.edit_prediction_provider =
 2481            provider.map(|provider| RegisteredInlineCompletionProvider {
 2482                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2483                    if this.focus_handle.is_focused(window) {
 2484                        this.update_visible_inline_completion(window, cx);
 2485                    }
 2486                }),
 2487                provider: Arc::new(provider),
 2488            });
 2489        self.update_edit_prediction_settings(cx);
 2490        self.refresh_inline_completion(false, false, window, cx);
 2491    }
 2492
 2493    pub fn placeholder_text(&self) -> Option<&str> {
 2494        self.placeholder_text.as_deref()
 2495    }
 2496
 2497    pub fn set_placeholder_text(
 2498        &mut self,
 2499        placeholder_text: impl Into<Arc<str>>,
 2500        cx: &mut Context<Self>,
 2501    ) {
 2502        let placeholder_text = Some(placeholder_text.into());
 2503        if self.placeholder_text != placeholder_text {
 2504            self.placeholder_text = placeholder_text;
 2505            cx.notify();
 2506        }
 2507    }
 2508
 2509    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2510        self.cursor_shape = cursor_shape;
 2511
 2512        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2513        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2514
 2515        cx.notify();
 2516    }
 2517
 2518    pub fn set_current_line_highlight(
 2519        &mut self,
 2520        current_line_highlight: Option<CurrentLineHighlight>,
 2521    ) {
 2522        self.current_line_highlight = current_line_highlight;
 2523    }
 2524
 2525    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2526        self.collapse_matches = collapse_matches;
 2527    }
 2528
 2529    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2530        let buffers = self.buffer.read(cx).all_buffers();
 2531        let Some(project) = self.project.as_ref() else {
 2532            return;
 2533        };
 2534        project.update(cx, |project, cx| {
 2535            for buffer in buffers {
 2536                self.registered_buffers
 2537                    .entry(buffer.read(cx).remote_id())
 2538                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2539            }
 2540        })
 2541    }
 2542
 2543    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2544        if self.collapse_matches {
 2545            return range.start..range.start;
 2546        }
 2547        range.clone()
 2548    }
 2549
 2550    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2551        if self.display_map.read(cx).clip_at_line_ends != clip {
 2552            self.display_map
 2553                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2554        }
 2555    }
 2556
 2557    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2558        self.input_enabled = input_enabled;
 2559    }
 2560
 2561    pub fn set_inline_completions_hidden_for_vim_mode(
 2562        &mut self,
 2563        hidden: bool,
 2564        window: &mut Window,
 2565        cx: &mut Context<Self>,
 2566    ) {
 2567        if hidden != self.inline_completions_hidden_for_vim_mode {
 2568            self.inline_completions_hidden_for_vim_mode = hidden;
 2569            if hidden {
 2570                self.update_visible_inline_completion(window, cx);
 2571            } else {
 2572                self.refresh_inline_completion(true, false, window, cx);
 2573            }
 2574        }
 2575    }
 2576
 2577    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2578        self.menu_inline_completions_policy = value;
 2579    }
 2580
 2581    pub fn set_autoindent(&mut self, autoindent: bool) {
 2582        if autoindent {
 2583            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2584        } else {
 2585            self.autoindent_mode = None;
 2586        }
 2587    }
 2588
 2589    pub fn read_only(&self, cx: &App) -> bool {
 2590        self.read_only || self.buffer.read(cx).read_only()
 2591    }
 2592
 2593    pub fn set_read_only(&mut self, read_only: bool) {
 2594        self.read_only = read_only;
 2595    }
 2596
 2597    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2598        self.use_autoclose = autoclose;
 2599    }
 2600
 2601    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2602        self.use_auto_surround = auto_surround;
 2603    }
 2604
 2605    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2606        self.auto_replace_emoji_shortcode = auto_replace;
 2607    }
 2608
 2609    pub fn toggle_edit_predictions(
 2610        &mut self,
 2611        _: &ToggleEditPrediction,
 2612        window: &mut Window,
 2613        cx: &mut Context<Self>,
 2614    ) {
 2615        if self.show_inline_completions_override.is_some() {
 2616            self.set_show_edit_predictions(None, window, cx);
 2617        } else {
 2618            let show_edit_predictions = !self.edit_predictions_enabled();
 2619            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2620        }
 2621    }
 2622
 2623    pub fn set_show_edit_predictions(
 2624        &mut self,
 2625        show_edit_predictions: Option<bool>,
 2626        window: &mut Window,
 2627        cx: &mut Context<Self>,
 2628    ) {
 2629        self.show_inline_completions_override = show_edit_predictions;
 2630        self.update_edit_prediction_settings(cx);
 2631
 2632        if let Some(false) = show_edit_predictions {
 2633            self.discard_inline_completion(false, cx);
 2634        } else {
 2635            self.refresh_inline_completion(false, true, window, cx);
 2636        }
 2637    }
 2638
 2639    fn inline_completions_disabled_in_scope(
 2640        &self,
 2641        buffer: &Entity<Buffer>,
 2642        buffer_position: language::Anchor,
 2643        cx: &App,
 2644    ) -> bool {
 2645        let snapshot = buffer.read(cx).snapshot();
 2646        let settings = snapshot.settings_at(buffer_position, cx);
 2647
 2648        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2649            return false;
 2650        };
 2651
 2652        scope.override_name().map_or(false, |scope_name| {
 2653            settings
 2654                .edit_predictions_disabled_in
 2655                .iter()
 2656                .any(|s| s == scope_name)
 2657        })
 2658    }
 2659
 2660    pub fn set_use_modal_editing(&mut self, to: bool) {
 2661        self.use_modal_editing = to;
 2662    }
 2663
 2664    pub fn use_modal_editing(&self) -> bool {
 2665        self.use_modal_editing
 2666    }
 2667
 2668    fn selections_did_change(
 2669        &mut self,
 2670        local: bool,
 2671        old_cursor_position: &Anchor,
 2672        should_update_completions: bool,
 2673        window: &mut Window,
 2674        cx: &mut Context<Self>,
 2675    ) {
 2676        window.invalidate_character_coordinates();
 2677
 2678        // Copy selections to primary selection buffer
 2679        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2680        if local {
 2681            let selections = self.selections.all::<usize>(cx);
 2682            let buffer_handle = self.buffer.read(cx).read(cx);
 2683
 2684            let mut text = String::new();
 2685            for (index, selection) in selections.iter().enumerate() {
 2686                let text_for_selection = buffer_handle
 2687                    .text_for_range(selection.start..selection.end)
 2688                    .collect::<String>();
 2689
 2690                text.push_str(&text_for_selection);
 2691                if index != selections.len() - 1 {
 2692                    text.push('\n');
 2693                }
 2694            }
 2695
 2696            if !text.is_empty() {
 2697                cx.write_to_primary(ClipboardItem::new_string(text));
 2698            }
 2699        }
 2700
 2701        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2702            self.buffer.update(cx, |buffer, cx| {
 2703                buffer.set_active_selections(
 2704                    &self.selections.disjoint_anchors(),
 2705                    self.selections.line_mode,
 2706                    self.cursor_shape,
 2707                    cx,
 2708                )
 2709            });
 2710        }
 2711        let display_map = self
 2712            .display_map
 2713            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2714        let buffer = &display_map.buffer_snapshot;
 2715        self.add_selections_state = None;
 2716        self.select_next_state = None;
 2717        self.select_prev_state = None;
 2718        self.select_syntax_node_history.try_clear();
 2719        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2720        self.snippet_stack
 2721            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2722        self.take_rename(false, window, cx);
 2723
 2724        let new_cursor_position = self.selections.newest_anchor().head();
 2725
 2726        self.push_to_nav_history(
 2727            *old_cursor_position,
 2728            Some(new_cursor_position.to_point(buffer)),
 2729            false,
 2730            cx,
 2731        );
 2732
 2733        if local {
 2734            let new_cursor_position = self.selections.newest_anchor().head();
 2735
 2736            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2737                if !self.registered_buffers.contains_key(&buffer_id) {
 2738                    if let Some(project) = self.project.as_ref() {
 2739                        project.update(cx, |project, cx| {
 2740                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2741                                return;
 2742                            };
 2743                            self.registered_buffers.insert(
 2744                                buffer_id,
 2745                                project.register_buffer_with_language_servers(&buffer, cx),
 2746                            );
 2747                        })
 2748                    }
 2749                }
 2750            }
 2751
 2752            let mut context_menu = self.context_menu.borrow_mut();
 2753            let completion_menu = match context_menu.as_ref() {
 2754                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2755                Some(CodeContextMenu::CodeActions(_)) => {
 2756                    *context_menu = None;
 2757                    None
 2758                }
 2759                None => None,
 2760            };
 2761            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2762            drop(context_menu);
 2763
 2764            if should_update_completions {
 2765                if let Some(completion_position) = completion_position {
 2766                    let new_cursor_offset = new_cursor_position.to_offset(buffer);
 2767                    let position_matches =
 2768                        new_cursor_offset == completion_position.to_offset(buffer);
 2769                    let continue_showing = if position_matches {
 2770                        let (word_range, kind) = buffer.surrounding_word(new_cursor_offset, true);
 2771                        if let Some(CharKind::Word) = kind {
 2772                            word_range.start < new_cursor_offset
 2773                        } else {
 2774                            false
 2775                        }
 2776                    } else {
 2777                        false
 2778                    };
 2779
 2780                    if continue_showing {
 2781                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2782                    } else {
 2783                        self.hide_context_menu(window, cx);
 2784                    }
 2785                }
 2786            }
 2787
 2788            hide_hover(self, cx);
 2789
 2790            if old_cursor_position.to_display_point(&display_map).row()
 2791                != new_cursor_position.to_display_point(&display_map).row()
 2792            {
 2793                self.available_code_actions.take();
 2794            }
 2795            self.refresh_code_actions(window, cx);
 2796            self.refresh_document_highlights(cx);
 2797            self.refresh_selected_text_highlights(false, window, cx);
 2798            refresh_matching_bracket_highlights(self, window, cx);
 2799            self.update_visible_inline_completion(window, cx);
 2800            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2801            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2802            self.inline_blame_popover.take();
 2803            if self.git_blame_inline_enabled {
 2804                self.start_inline_blame_timer(window, cx);
 2805            }
 2806        }
 2807
 2808        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2809        cx.emit(EditorEvent::SelectionsChanged { local });
 2810
 2811        let selections = &self.selections.disjoint;
 2812        if selections.len() == 1 {
 2813            cx.emit(SearchEvent::ActiveMatchChanged)
 2814        }
 2815        if local {
 2816            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2817                let inmemory_selections = selections
 2818                    .iter()
 2819                    .map(|s| {
 2820                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2821                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2822                    })
 2823                    .collect();
 2824                self.update_restoration_data(cx, |data| {
 2825                    data.selections = inmemory_selections;
 2826                });
 2827
 2828                if WorkspaceSettings::get(None, cx).restore_on_startup
 2829                    != RestoreOnStartupBehavior::None
 2830                {
 2831                    if let Some(workspace_id) =
 2832                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2833                    {
 2834                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2835                        let selections = selections.clone();
 2836                        let background_executor = cx.background_executor().clone();
 2837                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2838                        self.serialize_selections = cx.background_spawn(async move {
 2839                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2840                    let db_selections = selections
 2841                        .iter()
 2842                        .map(|selection| {
 2843                            (
 2844                                selection.start.to_offset(&snapshot),
 2845                                selection.end.to_offset(&snapshot),
 2846                            )
 2847                        })
 2848                        .collect();
 2849
 2850                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2851                        .await
 2852                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2853                        .log_err();
 2854                });
 2855                    }
 2856                }
 2857            }
 2858        }
 2859
 2860        cx.notify();
 2861    }
 2862
 2863    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2864        use text::ToOffset as _;
 2865        use text::ToPoint as _;
 2866
 2867        if self.mode.is_minimap()
 2868            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2869        {
 2870            return;
 2871        }
 2872
 2873        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2874            return;
 2875        };
 2876
 2877        let snapshot = singleton.read(cx).snapshot();
 2878        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2879            let display_snapshot = display_map.snapshot(cx);
 2880
 2881            display_snapshot
 2882                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2883                .map(|fold| {
 2884                    fold.range.start.text_anchor.to_point(&snapshot)
 2885                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2886                })
 2887                .collect()
 2888        });
 2889        self.update_restoration_data(cx, |data| {
 2890            data.folds = inmemory_folds;
 2891        });
 2892
 2893        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2894            return;
 2895        };
 2896        let background_executor = cx.background_executor().clone();
 2897        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2898        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2899            display_map
 2900                .snapshot(cx)
 2901                .folds_in_range(0..snapshot.len())
 2902                .map(|fold| {
 2903                    (
 2904                        fold.range.start.text_anchor.to_offset(&snapshot),
 2905                        fold.range.end.text_anchor.to_offset(&snapshot),
 2906                    )
 2907                })
 2908                .collect()
 2909        });
 2910        self.serialize_folds = cx.background_spawn(async move {
 2911            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2912            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2913                .await
 2914                .with_context(|| {
 2915                    format!(
 2916                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2917                    )
 2918                })
 2919                .log_err();
 2920        });
 2921    }
 2922
 2923    pub fn sync_selections(
 2924        &mut self,
 2925        other: Entity<Editor>,
 2926        cx: &mut Context<Self>,
 2927    ) -> gpui::Subscription {
 2928        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2929        self.selections.change_with(cx, |selections| {
 2930            selections.select_anchors(other_selections);
 2931        });
 2932
 2933        let other_subscription =
 2934            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2935                EditorEvent::SelectionsChanged { local: true } => {
 2936                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2937                    if other_selections.is_empty() {
 2938                        return;
 2939                    }
 2940                    this.selections.change_with(cx, |selections| {
 2941                        selections.select_anchors(other_selections);
 2942                    });
 2943                }
 2944                _ => {}
 2945            });
 2946
 2947        let this_subscription =
 2948            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2949                EditorEvent::SelectionsChanged { local: true } => {
 2950                    let these_selections = this.selections.disjoint.to_vec();
 2951                    if these_selections.is_empty() {
 2952                        return;
 2953                    }
 2954                    other.update(cx, |other_editor, cx| {
 2955                        other_editor.selections.change_with(cx, |selections| {
 2956                            selections.select_anchors(these_selections);
 2957                        })
 2958                    });
 2959                }
 2960                _ => {}
 2961            });
 2962
 2963        Subscription::join(other_subscription, this_subscription)
 2964    }
 2965
 2966    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 2967    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 2968    /// effects of selection change occur at the end of the transaction.
 2969    pub fn change_selections<R>(
 2970        &mut self,
 2971        autoscroll: Option<Autoscroll>,
 2972        window: &mut Window,
 2973        cx: &mut Context<Self>,
 2974        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2975    ) -> R {
 2976        self.change_selections_inner(true, autoscroll, window, cx, change)
 2977    }
 2978
 2979    pub(crate) fn change_selections_without_updating_completions<R>(
 2980        &mut self,
 2981        autoscroll: Option<Autoscroll>,
 2982        window: &mut Window,
 2983        cx: &mut Context<Self>,
 2984        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2985    ) -> R {
 2986        self.change_selections_inner(false, autoscroll, window, cx, change)
 2987    }
 2988
 2989    fn change_selections_inner<R>(
 2990        &mut self,
 2991        should_update_completions: bool,
 2992        autoscroll: Option<Autoscroll>,
 2993        window: &mut Window,
 2994        cx: &mut Context<Self>,
 2995        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2996    ) -> R {
 2997        if let Some(state) = &mut self.deferred_selection_effects_state {
 2998            state.autoscroll = autoscroll.or(state.autoscroll);
 2999            state.should_update_completions = should_update_completions;
 3000            let (changed, result) = self.selections.change_with(cx, change);
 3001            state.changed |= changed;
 3002            return result;
 3003        }
 3004        let mut state = DeferredSelectionEffectsState {
 3005            changed: false,
 3006            should_update_completions,
 3007            autoscroll,
 3008            old_cursor_position: self.selections.newest_anchor().head(),
 3009            history_entry: SelectionHistoryEntry {
 3010                selections: self.selections.disjoint_anchors(),
 3011                select_next_state: self.select_next_state.clone(),
 3012                select_prev_state: self.select_prev_state.clone(),
 3013                add_selections_state: self.add_selections_state.clone(),
 3014            },
 3015        };
 3016        let (changed, result) = self.selections.change_with(cx, change);
 3017        state.changed = state.changed || changed;
 3018        if self.defer_selection_effects {
 3019            self.deferred_selection_effects_state = Some(state);
 3020        } else {
 3021            self.apply_selection_effects(state, window, cx);
 3022        }
 3023        result
 3024    }
 3025
 3026    /// Defers the effects of selection change, so that the effects of multiple calls to
 3027    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3028    /// to selection history and the state of popovers based on selection position aren't
 3029    /// erroneously updated.
 3030    pub fn with_selection_effects_deferred<R>(
 3031        &mut self,
 3032        window: &mut Window,
 3033        cx: &mut Context<Self>,
 3034        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3035    ) -> R {
 3036        let already_deferred = self.defer_selection_effects;
 3037        self.defer_selection_effects = true;
 3038        let result = update(self, window, cx);
 3039        if !already_deferred {
 3040            self.defer_selection_effects = false;
 3041            if let Some(state) = self.deferred_selection_effects_state.take() {
 3042                self.apply_selection_effects(state, window, cx);
 3043            }
 3044        }
 3045        result
 3046    }
 3047
 3048    fn apply_selection_effects(
 3049        &mut self,
 3050        state: DeferredSelectionEffectsState,
 3051        window: &mut Window,
 3052        cx: &mut Context<Self>,
 3053    ) {
 3054        if state.changed {
 3055            self.selection_history.push(state.history_entry);
 3056
 3057            if let Some(autoscroll) = state.autoscroll {
 3058                self.request_autoscroll(autoscroll, cx);
 3059            }
 3060
 3061            let old_cursor_position = &state.old_cursor_position;
 3062
 3063            self.selections_did_change(
 3064                true,
 3065                &old_cursor_position,
 3066                state.should_update_completions,
 3067                window,
 3068                cx,
 3069            );
 3070
 3071            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3072                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3073            }
 3074        }
 3075    }
 3076
 3077    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3078    where
 3079        I: IntoIterator<Item = (Range<S>, T)>,
 3080        S: ToOffset,
 3081        T: Into<Arc<str>>,
 3082    {
 3083        if self.read_only(cx) {
 3084            return;
 3085        }
 3086
 3087        self.buffer
 3088            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3089    }
 3090
 3091    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3092    where
 3093        I: IntoIterator<Item = (Range<S>, T)>,
 3094        S: ToOffset,
 3095        T: Into<Arc<str>>,
 3096    {
 3097        if self.read_only(cx) {
 3098            return;
 3099        }
 3100
 3101        self.buffer.update(cx, |buffer, cx| {
 3102            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3103        });
 3104    }
 3105
 3106    pub fn edit_with_block_indent<I, S, T>(
 3107        &mut self,
 3108        edits: I,
 3109        original_indent_columns: Vec<Option<u32>>,
 3110        cx: &mut Context<Self>,
 3111    ) where
 3112        I: IntoIterator<Item = (Range<S>, T)>,
 3113        S: ToOffset,
 3114        T: Into<Arc<str>>,
 3115    {
 3116        if self.read_only(cx) {
 3117            return;
 3118        }
 3119
 3120        self.buffer.update(cx, |buffer, cx| {
 3121            buffer.edit(
 3122                edits,
 3123                Some(AutoindentMode::Block {
 3124                    original_indent_columns,
 3125                }),
 3126                cx,
 3127            )
 3128        });
 3129    }
 3130
 3131    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3132        self.hide_context_menu(window, cx);
 3133
 3134        match phase {
 3135            SelectPhase::Begin {
 3136                position,
 3137                add,
 3138                click_count,
 3139            } => self.begin_selection(position, add, click_count, window, cx),
 3140            SelectPhase::BeginColumnar {
 3141                position,
 3142                goal_column,
 3143                reset,
 3144            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3145            SelectPhase::Extend {
 3146                position,
 3147                click_count,
 3148            } => self.extend_selection(position, click_count, window, cx),
 3149            SelectPhase::Update {
 3150                position,
 3151                goal_column,
 3152                scroll_delta,
 3153            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3154            SelectPhase::End => self.end_selection(window, cx),
 3155        }
 3156    }
 3157
 3158    fn extend_selection(
 3159        &mut self,
 3160        position: DisplayPoint,
 3161        click_count: usize,
 3162        window: &mut Window,
 3163        cx: &mut Context<Self>,
 3164    ) {
 3165        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3166        let tail = self.selections.newest::<usize>(cx).tail();
 3167        self.begin_selection(position, false, click_count, window, cx);
 3168
 3169        let position = position.to_offset(&display_map, Bias::Left);
 3170        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3171
 3172        let mut pending_selection = self
 3173            .selections
 3174            .pending_anchor()
 3175            .expect("extend_selection not called with pending selection");
 3176        if position >= tail {
 3177            pending_selection.start = tail_anchor;
 3178        } else {
 3179            pending_selection.end = tail_anchor;
 3180            pending_selection.reversed = true;
 3181        }
 3182
 3183        let mut pending_mode = self.selections.pending_mode().unwrap();
 3184        match &mut pending_mode {
 3185            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3186            _ => {}
 3187        }
 3188
 3189        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3190
 3191        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3192            s.set_pending(pending_selection, pending_mode)
 3193        });
 3194    }
 3195
 3196    fn begin_selection(
 3197        &mut self,
 3198        position: DisplayPoint,
 3199        add: bool,
 3200        click_count: usize,
 3201        window: &mut Window,
 3202        cx: &mut Context<Self>,
 3203    ) {
 3204        if !self.focus_handle.is_focused(window) {
 3205            self.last_focused_descendant = None;
 3206            window.focus(&self.focus_handle);
 3207        }
 3208
 3209        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3210        let buffer = &display_map.buffer_snapshot;
 3211        let position = display_map.clip_point(position, Bias::Left);
 3212
 3213        let start;
 3214        let end;
 3215        let mode;
 3216        let mut auto_scroll;
 3217        match click_count {
 3218            1 => {
 3219                start = buffer.anchor_before(position.to_point(&display_map));
 3220                end = start;
 3221                mode = SelectMode::Character;
 3222                auto_scroll = true;
 3223            }
 3224            2 => {
 3225                let range = movement::surrounding_word(&display_map, position);
 3226                start = buffer.anchor_before(range.start.to_point(&display_map));
 3227                end = buffer.anchor_before(range.end.to_point(&display_map));
 3228                mode = SelectMode::Word(start..end);
 3229                auto_scroll = true;
 3230            }
 3231            3 => {
 3232                let position = display_map
 3233                    .clip_point(position, Bias::Left)
 3234                    .to_point(&display_map);
 3235                let line_start = display_map.prev_line_boundary(position).0;
 3236                let next_line_start = buffer.clip_point(
 3237                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3238                    Bias::Left,
 3239                );
 3240                start = buffer.anchor_before(line_start);
 3241                end = buffer.anchor_before(next_line_start);
 3242                mode = SelectMode::Line(start..end);
 3243                auto_scroll = true;
 3244            }
 3245            _ => {
 3246                start = buffer.anchor_before(0);
 3247                end = buffer.anchor_before(buffer.len());
 3248                mode = SelectMode::All;
 3249                auto_scroll = false;
 3250            }
 3251        }
 3252        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3253
 3254        let point_to_delete: Option<usize> = {
 3255            let selected_points: Vec<Selection<Point>> =
 3256                self.selections.disjoint_in_range(start..end, cx);
 3257
 3258            if !add || click_count > 1 {
 3259                None
 3260            } else if !selected_points.is_empty() {
 3261                Some(selected_points[0].id)
 3262            } else {
 3263                let clicked_point_already_selected =
 3264                    self.selections.disjoint.iter().find(|selection| {
 3265                        selection.start.to_point(buffer) == start.to_point(buffer)
 3266                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3267                    });
 3268
 3269                clicked_point_already_selected.map(|selection| selection.id)
 3270            }
 3271        };
 3272
 3273        let selections_count = self.selections.count();
 3274
 3275        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3276            if let Some(point_to_delete) = point_to_delete {
 3277                s.delete(point_to_delete);
 3278
 3279                if selections_count == 1 {
 3280                    s.set_pending_anchor_range(start..end, mode);
 3281                }
 3282            } else {
 3283                if !add {
 3284                    s.clear_disjoint();
 3285                }
 3286
 3287                s.set_pending_anchor_range(start..end, mode);
 3288            }
 3289        });
 3290    }
 3291
 3292    fn begin_columnar_selection(
 3293        &mut self,
 3294        position: DisplayPoint,
 3295        goal_column: u32,
 3296        reset: bool,
 3297        window: &mut Window,
 3298        cx: &mut Context<Self>,
 3299    ) {
 3300        if !self.focus_handle.is_focused(window) {
 3301            self.last_focused_descendant = None;
 3302            window.focus(&self.focus_handle);
 3303        }
 3304
 3305        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3306
 3307        if reset {
 3308            let pointer_position = display_map
 3309                .buffer_snapshot
 3310                .anchor_before(position.to_point(&display_map));
 3311
 3312            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3313                s.clear_disjoint();
 3314                s.set_pending_anchor_range(
 3315                    pointer_position..pointer_position,
 3316                    SelectMode::Character,
 3317                );
 3318            });
 3319            if position.column() != goal_column {
 3320                self.columnar_display_point = Some(DisplayPoint::new(position.row(), goal_column));
 3321            } else {
 3322                self.columnar_display_point = None;
 3323            }
 3324        }
 3325
 3326        let tail = self.selections.newest::<Point>(cx).tail();
 3327        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3328
 3329        if !reset {
 3330            self.columnar_display_point = None;
 3331            self.select_columns(
 3332                tail.to_display_point(&display_map),
 3333                position,
 3334                goal_column,
 3335                &display_map,
 3336                window,
 3337                cx,
 3338            );
 3339        }
 3340    }
 3341
 3342    fn update_selection(
 3343        &mut self,
 3344        position: DisplayPoint,
 3345        goal_column: u32,
 3346        scroll_delta: gpui::Point<f32>,
 3347        window: &mut Window,
 3348        cx: &mut Context<Self>,
 3349    ) {
 3350        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3351
 3352        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3353            let tail = self
 3354                .columnar_display_point
 3355                .unwrap_or_else(|| tail.to_display_point(&display_map));
 3356            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3357        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3358            let buffer = self.buffer.read(cx).snapshot(cx);
 3359            let head;
 3360            let tail;
 3361            let mode = self.selections.pending_mode().unwrap();
 3362            match &mode {
 3363                SelectMode::Character => {
 3364                    head = position.to_point(&display_map);
 3365                    tail = pending.tail().to_point(&buffer);
 3366                }
 3367                SelectMode::Word(original_range) => {
 3368                    let original_display_range = original_range.start.to_display_point(&display_map)
 3369                        ..original_range.end.to_display_point(&display_map);
 3370                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3371                        ..original_display_range.end.to_point(&display_map);
 3372                    if movement::is_inside_word(&display_map, position)
 3373                        || original_display_range.contains(&position)
 3374                    {
 3375                        let word_range = movement::surrounding_word(&display_map, position);
 3376                        if word_range.start < original_display_range.start {
 3377                            head = word_range.start.to_point(&display_map);
 3378                        } else {
 3379                            head = word_range.end.to_point(&display_map);
 3380                        }
 3381                    } else {
 3382                        head = position.to_point(&display_map);
 3383                    }
 3384
 3385                    if head <= original_buffer_range.start {
 3386                        tail = original_buffer_range.end;
 3387                    } else {
 3388                        tail = original_buffer_range.start;
 3389                    }
 3390                }
 3391                SelectMode::Line(original_range) => {
 3392                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3393
 3394                    let position = display_map
 3395                        .clip_point(position, Bias::Left)
 3396                        .to_point(&display_map);
 3397                    let line_start = display_map.prev_line_boundary(position).0;
 3398                    let next_line_start = buffer.clip_point(
 3399                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3400                        Bias::Left,
 3401                    );
 3402
 3403                    if line_start < original_range.start {
 3404                        head = line_start
 3405                    } else {
 3406                        head = next_line_start
 3407                    }
 3408
 3409                    if head <= original_range.start {
 3410                        tail = original_range.end;
 3411                    } else {
 3412                        tail = original_range.start;
 3413                    }
 3414                }
 3415                SelectMode::All => {
 3416                    return;
 3417                }
 3418            };
 3419
 3420            if head < tail {
 3421                pending.start = buffer.anchor_before(head);
 3422                pending.end = buffer.anchor_before(tail);
 3423                pending.reversed = true;
 3424            } else {
 3425                pending.start = buffer.anchor_before(tail);
 3426                pending.end = buffer.anchor_before(head);
 3427                pending.reversed = false;
 3428            }
 3429
 3430            self.change_selections(None, window, cx, |s| {
 3431                s.set_pending(pending, mode);
 3432            });
 3433        } else {
 3434            log::error!("update_selection dispatched with no pending selection");
 3435            return;
 3436        }
 3437
 3438        self.apply_scroll_delta(scroll_delta, window, cx);
 3439        cx.notify();
 3440    }
 3441
 3442    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3443        self.columnar_selection_tail.take();
 3444        if self.selections.pending_anchor().is_some() {
 3445            let selections = self.selections.all::<usize>(cx);
 3446            self.change_selections(None, window, cx, |s| {
 3447                s.select(selections);
 3448                s.clear_pending();
 3449            });
 3450        }
 3451    }
 3452
 3453    fn select_columns(
 3454        &mut self,
 3455        tail: DisplayPoint,
 3456        head: DisplayPoint,
 3457        goal_column: u32,
 3458        display_map: &DisplaySnapshot,
 3459        window: &mut Window,
 3460        cx: &mut Context<Self>,
 3461    ) {
 3462        let start_row = cmp::min(tail.row(), head.row());
 3463        let end_row = cmp::max(tail.row(), head.row());
 3464        let start_column = cmp::min(tail.column(), goal_column);
 3465        let end_column = cmp::max(tail.column(), goal_column);
 3466        let reversed = start_column < tail.column();
 3467
 3468        let selection_ranges = (start_row.0..=end_row.0)
 3469            .map(DisplayRow)
 3470            .filter_map(|row| {
 3471                if !display_map.is_block_line(row) {
 3472                    let start = display_map
 3473                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3474                        .to_point(display_map);
 3475                    let end = display_map
 3476                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3477                        .to_point(display_map);
 3478                    if reversed {
 3479                        Some(end..start)
 3480                    } else {
 3481                        Some(start..end)
 3482                    }
 3483                } else {
 3484                    None
 3485                }
 3486            })
 3487            .collect::<Vec<_>>();
 3488
 3489        let mut non_empty_ranges = selection_ranges
 3490            .iter()
 3491            .filter(|selection_range| selection_range.start != selection_range.end)
 3492            .peekable();
 3493
 3494        let ranges = if non_empty_ranges.peek().is_some() {
 3495            non_empty_ranges.cloned().collect()
 3496        } else {
 3497            selection_ranges
 3498        };
 3499
 3500        self.change_selections(None, window, cx, |s| {
 3501            s.select_ranges(ranges);
 3502        });
 3503        cx.notify();
 3504    }
 3505
 3506    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3507        self.selections
 3508            .all_adjusted(cx)
 3509            .iter()
 3510            .any(|selection| !selection.is_empty())
 3511    }
 3512
 3513    pub fn has_pending_nonempty_selection(&self) -> bool {
 3514        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3515            Some(Selection { start, end, .. }) => start != end,
 3516            None => false,
 3517        };
 3518
 3519        pending_nonempty_selection
 3520            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3521    }
 3522
 3523    pub fn has_pending_selection(&self) -> bool {
 3524        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3525    }
 3526
 3527    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3528        self.selection_mark_mode = false;
 3529
 3530        if self.clear_expanded_diff_hunks(cx) {
 3531            cx.notify();
 3532            return;
 3533        }
 3534        if self.dismiss_menus_and_popups(true, window, cx) {
 3535            return;
 3536        }
 3537
 3538        if self.mode.is_full()
 3539            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3540        {
 3541            return;
 3542        }
 3543
 3544        cx.propagate();
 3545    }
 3546
 3547    pub fn dismiss_menus_and_popups(
 3548        &mut self,
 3549        is_user_requested: bool,
 3550        window: &mut Window,
 3551        cx: &mut Context<Self>,
 3552    ) -> bool {
 3553        if self.take_rename(false, window, cx).is_some() {
 3554            return true;
 3555        }
 3556
 3557        if hide_hover(self, cx) {
 3558            return true;
 3559        }
 3560
 3561        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3562            return true;
 3563        }
 3564
 3565        if self.hide_context_menu(window, cx).is_some() {
 3566            return true;
 3567        }
 3568
 3569        if self.mouse_context_menu.take().is_some() {
 3570            return true;
 3571        }
 3572
 3573        if is_user_requested && self.discard_inline_completion(true, cx) {
 3574            return true;
 3575        }
 3576
 3577        if self.snippet_stack.pop().is_some() {
 3578            return true;
 3579        }
 3580
 3581        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3582            self.dismiss_diagnostics(cx);
 3583            return true;
 3584        }
 3585
 3586        false
 3587    }
 3588
 3589    fn linked_editing_ranges_for(
 3590        &self,
 3591        selection: Range<text::Anchor>,
 3592        cx: &App,
 3593    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3594        if self.linked_edit_ranges.is_empty() {
 3595            return None;
 3596        }
 3597        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3598            selection.end.buffer_id.and_then(|end_buffer_id| {
 3599                if selection.start.buffer_id != Some(end_buffer_id) {
 3600                    return None;
 3601                }
 3602                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3603                let snapshot = buffer.read(cx).snapshot();
 3604                self.linked_edit_ranges
 3605                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3606                    .map(|ranges| (ranges, snapshot, buffer))
 3607            })?;
 3608        use text::ToOffset as TO;
 3609        // find offset from the start of current range to current cursor position
 3610        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3611
 3612        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3613        let start_difference = start_offset - start_byte_offset;
 3614        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3615        let end_difference = end_offset - start_byte_offset;
 3616        // Current range has associated linked ranges.
 3617        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3618        for range in linked_ranges.iter() {
 3619            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3620            let end_offset = start_offset + end_difference;
 3621            let start_offset = start_offset + start_difference;
 3622            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3623                continue;
 3624            }
 3625            if self.selections.disjoint_anchor_ranges().any(|s| {
 3626                if s.start.buffer_id != selection.start.buffer_id
 3627                    || s.end.buffer_id != selection.end.buffer_id
 3628                {
 3629                    return false;
 3630                }
 3631                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3632                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3633            }) {
 3634                continue;
 3635            }
 3636            let start = buffer_snapshot.anchor_after(start_offset);
 3637            let end = buffer_snapshot.anchor_after(end_offset);
 3638            linked_edits
 3639                .entry(buffer.clone())
 3640                .or_default()
 3641                .push(start..end);
 3642        }
 3643        Some(linked_edits)
 3644    }
 3645
 3646    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3647        let text: Arc<str> = text.into();
 3648
 3649        if self.read_only(cx) {
 3650            return;
 3651        }
 3652
 3653        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3654
 3655        let selections = self.selections.all_adjusted(cx);
 3656        let mut bracket_inserted = false;
 3657        let mut edits = Vec::new();
 3658        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3659        let mut new_selections = Vec::with_capacity(selections.len());
 3660        let mut new_autoclose_regions = Vec::new();
 3661        let snapshot = self.buffer.read(cx).read(cx);
 3662        let mut clear_linked_edit_ranges = false;
 3663
 3664        for (selection, autoclose_region) in
 3665            self.selections_with_autoclose_regions(selections, &snapshot)
 3666        {
 3667            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3668                // Determine if the inserted text matches the opening or closing
 3669                // bracket of any of this language's bracket pairs.
 3670                let mut bracket_pair = None;
 3671                let mut is_bracket_pair_start = false;
 3672                let mut is_bracket_pair_end = false;
 3673                if !text.is_empty() {
 3674                    let mut bracket_pair_matching_end = None;
 3675                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3676                    //  and they are removing the character that triggered IME popup.
 3677                    for (pair, enabled) in scope.brackets() {
 3678                        if !pair.close && !pair.surround {
 3679                            continue;
 3680                        }
 3681
 3682                        if enabled && pair.start.ends_with(text.as_ref()) {
 3683                            let prefix_len = pair.start.len() - text.len();
 3684                            let preceding_text_matches_prefix = prefix_len == 0
 3685                                || (selection.start.column >= (prefix_len as u32)
 3686                                    && snapshot.contains_str_at(
 3687                                        Point::new(
 3688                                            selection.start.row,
 3689                                            selection.start.column - (prefix_len as u32),
 3690                                        ),
 3691                                        &pair.start[..prefix_len],
 3692                                    ));
 3693                            if preceding_text_matches_prefix {
 3694                                bracket_pair = Some(pair.clone());
 3695                                is_bracket_pair_start = true;
 3696                                break;
 3697                            }
 3698                        }
 3699                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3700                        {
 3701                            // take first bracket pair matching end, but don't break in case a later bracket
 3702                            // pair matches start
 3703                            bracket_pair_matching_end = Some(pair.clone());
 3704                        }
 3705                    }
 3706                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3707                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3708                        is_bracket_pair_end = true;
 3709                    }
 3710                }
 3711
 3712                if let Some(bracket_pair) = bracket_pair {
 3713                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3714                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3715                    let auto_surround =
 3716                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3717                    if selection.is_empty() {
 3718                        if is_bracket_pair_start {
 3719                            // If the inserted text is a suffix of an opening bracket and the
 3720                            // selection is preceded by the rest of the opening bracket, then
 3721                            // insert the closing bracket.
 3722                            let following_text_allows_autoclose = snapshot
 3723                                .chars_at(selection.start)
 3724                                .next()
 3725                                .map_or(true, |c| scope.should_autoclose_before(c));
 3726
 3727                            let preceding_text_allows_autoclose = selection.start.column == 0
 3728                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3729                                    true,
 3730                                    |c| {
 3731                                        bracket_pair.start != bracket_pair.end
 3732                                            || !snapshot
 3733                                                .char_classifier_at(selection.start)
 3734                                                .is_word(c)
 3735                                    },
 3736                                );
 3737
 3738                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3739                                && bracket_pair.start.len() == 1
 3740                            {
 3741                                let target = bracket_pair.start.chars().next().unwrap();
 3742                                let current_line_count = snapshot
 3743                                    .reversed_chars_at(selection.start)
 3744                                    .take_while(|&c| c != '\n')
 3745                                    .filter(|&c| c == target)
 3746                                    .count();
 3747                                current_line_count % 2 == 1
 3748                            } else {
 3749                                false
 3750                            };
 3751
 3752                            if autoclose
 3753                                && bracket_pair.close
 3754                                && following_text_allows_autoclose
 3755                                && preceding_text_allows_autoclose
 3756                                && !is_closing_quote
 3757                            {
 3758                                let anchor = snapshot.anchor_before(selection.end);
 3759                                new_selections.push((selection.map(|_| anchor), text.len()));
 3760                                new_autoclose_regions.push((
 3761                                    anchor,
 3762                                    text.len(),
 3763                                    selection.id,
 3764                                    bracket_pair.clone(),
 3765                                ));
 3766                                edits.push((
 3767                                    selection.range(),
 3768                                    format!("{}{}", text, bracket_pair.end).into(),
 3769                                ));
 3770                                bracket_inserted = true;
 3771                                continue;
 3772                            }
 3773                        }
 3774
 3775                        if let Some(region) = autoclose_region {
 3776                            // If the selection is followed by an auto-inserted closing bracket,
 3777                            // then don't insert that closing bracket again; just move the selection
 3778                            // past the closing bracket.
 3779                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3780                                && text.as_ref() == region.pair.end.as_str();
 3781                            if should_skip {
 3782                                let anchor = snapshot.anchor_after(selection.end);
 3783                                new_selections
 3784                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3785                                continue;
 3786                            }
 3787                        }
 3788
 3789                        let always_treat_brackets_as_autoclosed = snapshot
 3790                            .language_settings_at(selection.start, cx)
 3791                            .always_treat_brackets_as_autoclosed;
 3792                        if always_treat_brackets_as_autoclosed
 3793                            && is_bracket_pair_end
 3794                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3795                        {
 3796                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3797                            // and the inserted text is a closing bracket and the selection is followed
 3798                            // by the closing bracket then move the selection past the closing bracket.
 3799                            let anchor = snapshot.anchor_after(selection.end);
 3800                            new_selections.push((selection.map(|_| anchor), text.len()));
 3801                            continue;
 3802                        }
 3803                    }
 3804                    // If an opening bracket is 1 character long and is typed while
 3805                    // text is selected, then surround that text with the bracket pair.
 3806                    else if auto_surround
 3807                        && bracket_pair.surround
 3808                        && is_bracket_pair_start
 3809                        && bracket_pair.start.chars().count() == 1
 3810                    {
 3811                        edits.push((selection.start..selection.start, text.clone()));
 3812                        edits.push((
 3813                            selection.end..selection.end,
 3814                            bracket_pair.end.as_str().into(),
 3815                        ));
 3816                        bracket_inserted = true;
 3817                        new_selections.push((
 3818                            Selection {
 3819                                id: selection.id,
 3820                                start: snapshot.anchor_after(selection.start),
 3821                                end: snapshot.anchor_before(selection.end),
 3822                                reversed: selection.reversed,
 3823                                goal: selection.goal,
 3824                            },
 3825                            0,
 3826                        ));
 3827                        continue;
 3828                    }
 3829                }
 3830            }
 3831
 3832            if self.auto_replace_emoji_shortcode
 3833                && selection.is_empty()
 3834                && text.as_ref().ends_with(':')
 3835            {
 3836                if let Some(possible_emoji_short_code) =
 3837                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3838                {
 3839                    if !possible_emoji_short_code.is_empty() {
 3840                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3841                            let emoji_shortcode_start = Point::new(
 3842                                selection.start.row,
 3843                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3844                            );
 3845
 3846                            // Remove shortcode from buffer
 3847                            edits.push((
 3848                                emoji_shortcode_start..selection.start,
 3849                                "".to_string().into(),
 3850                            ));
 3851                            new_selections.push((
 3852                                Selection {
 3853                                    id: selection.id,
 3854                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3855                                    end: snapshot.anchor_before(selection.start),
 3856                                    reversed: selection.reversed,
 3857                                    goal: selection.goal,
 3858                                },
 3859                                0,
 3860                            ));
 3861
 3862                            // Insert emoji
 3863                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3864                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3865                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3866
 3867                            continue;
 3868                        }
 3869                    }
 3870                }
 3871            }
 3872
 3873            // If not handling any auto-close operation, then just replace the selected
 3874            // text with the given input and move the selection to the end of the
 3875            // newly inserted text.
 3876            let anchor = snapshot.anchor_after(selection.end);
 3877            if !self.linked_edit_ranges.is_empty() {
 3878                let start_anchor = snapshot.anchor_before(selection.start);
 3879
 3880                let is_word_char = text.chars().next().map_or(true, |char| {
 3881                    let classifier = snapshot
 3882                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3883                        .ignore_punctuation(true);
 3884                    classifier.is_word(char)
 3885                });
 3886
 3887                if is_word_char {
 3888                    if let Some(ranges) = self
 3889                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3890                    {
 3891                        for (buffer, edits) in ranges {
 3892                            linked_edits
 3893                                .entry(buffer.clone())
 3894                                .or_default()
 3895                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3896                        }
 3897                    }
 3898                } else {
 3899                    clear_linked_edit_ranges = true;
 3900                }
 3901            }
 3902
 3903            new_selections.push((selection.map(|_| anchor), 0));
 3904            edits.push((selection.start..selection.end, text.clone()));
 3905        }
 3906
 3907        drop(snapshot);
 3908
 3909        self.transact(window, cx, |this, window, cx| {
 3910            if clear_linked_edit_ranges {
 3911                this.linked_edit_ranges.clear();
 3912            }
 3913            let initial_buffer_versions =
 3914                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3915
 3916            this.buffer.update(cx, |buffer, cx| {
 3917                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3918            });
 3919            for (buffer, edits) in linked_edits {
 3920                buffer.update(cx, |buffer, cx| {
 3921                    let snapshot = buffer.snapshot();
 3922                    let edits = edits
 3923                        .into_iter()
 3924                        .map(|(range, text)| {
 3925                            use text::ToPoint as TP;
 3926                            let end_point = TP::to_point(&range.end, &snapshot);
 3927                            let start_point = TP::to_point(&range.start, &snapshot);
 3928                            (start_point..end_point, text)
 3929                        })
 3930                        .sorted_by_key(|(range, _)| range.start);
 3931                    buffer.edit(edits, None, cx);
 3932                })
 3933            }
 3934            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3935            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3936            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3937            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3938                .zip(new_selection_deltas)
 3939                .map(|(selection, delta)| Selection {
 3940                    id: selection.id,
 3941                    start: selection.start + delta,
 3942                    end: selection.end + delta,
 3943                    reversed: selection.reversed,
 3944                    goal: SelectionGoal::None,
 3945                })
 3946                .collect::<Vec<_>>();
 3947
 3948            let mut i = 0;
 3949            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3950                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3951                let start = map.buffer_snapshot.anchor_before(position);
 3952                let end = map.buffer_snapshot.anchor_after(position);
 3953                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3954                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3955                        Ordering::Less => i += 1,
 3956                        Ordering::Greater => break,
 3957                        Ordering::Equal => {
 3958                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3959                                Ordering::Less => i += 1,
 3960                                Ordering::Equal => break,
 3961                                Ordering::Greater => break,
 3962                            }
 3963                        }
 3964                    }
 3965                }
 3966                this.autoclose_regions.insert(
 3967                    i,
 3968                    AutocloseRegion {
 3969                        selection_id,
 3970                        range: start..end,
 3971                        pair,
 3972                    },
 3973                );
 3974            }
 3975
 3976            let had_active_inline_completion = this.has_active_inline_completion();
 3977            this.change_selections_without_updating_completions(
 3978                Some(Autoscroll::fit()),
 3979                window,
 3980                cx,
 3981                |s| s.select(new_selections),
 3982            );
 3983
 3984            if !bracket_inserted {
 3985                if let Some(on_type_format_task) =
 3986                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3987                {
 3988                    on_type_format_task.detach_and_log_err(cx);
 3989                }
 3990            }
 3991
 3992            let editor_settings = EditorSettings::get_global(cx);
 3993            if bracket_inserted
 3994                && (editor_settings.auto_signature_help
 3995                    || editor_settings.show_signature_help_after_edits)
 3996            {
 3997                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3998            }
 3999
 4000            let trigger_in_words =
 4001                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 4002            if this.hard_wrap.is_some() {
 4003                let latest: Range<Point> = this.selections.newest(cx).range();
 4004                if latest.is_empty()
 4005                    && this
 4006                        .buffer()
 4007                        .read(cx)
 4008                        .snapshot(cx)
 4009                        .line_len(MultiBufferRow(latest.start.row))
 4010                        == latest.start.column
 4011                {
 4012                    this.rewrap_impl(
 4013                        RewrapOptions {
 4014                            override_language_settings: true,
 4015                            preserve_existing_whitespace: true,
 4016                        },
 4017                        cx,
 4018                    )
 4019                }
 4020            }
 4021            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4022            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4023            this.refresh_inline_completion(true, false, window, cx);
 4024            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4025        });
 4026    }
 4027
 4028    fn find_possible_emoji_shortcode_at_position(
 4029        snapshot: &MultiBufferSnapshot,
 4030        position: Point,
 4031    ) -> Option<String> {
 4032        let mut chars = Vec::new();
 4033        let mut found_colon = false;
 4034        for char in snapshot.reversed_chars_at(position).take(100) {
 4035            // Found a possible emoji shortcode in the middle of the buffer
 4036            if found_colon {
 4037                if char.is_whitespace() {
 4038                    chars.reverse();
 4039                    return Some(chars.iter().collect());
 4040                }
 4041                // If the previous character is not a whitespace, we are in the middle of a word
 4042                // and we only want to complete the shortcode if the word is made up of other emojis
 4043                let mut containing_word = String::new();
 4044                for ch in snapshot
 4045                    .reversed_chars_at(position)
 4046                    .skip(chars.len() + 1)
 4047                    .take(100)
 4048                {
 4049                    if ch.is_whitespace() {
 4050                        break;
 4051                    }
 4052                    containing_word.push(ch);
 4053                }
 4054                let containing_word = containing_word.chars().rev().collect::<String>();
 4055                if util::word_consists_of_emojis(containing_word.as_str()) {
 4056                    chars.reverse();
 4057                    return Some(chars.iter().collect());
 4058                }
 4059            }
 4060
 4061            if char.is_whitespace() || !char.is_ascii() {
 4062                return None;
 4063            }
 4064            if char == ':' {
 4065                found_colon = true;
 4066            } else {
 4067                chars.push(char);
 4068            }
 4069        }
 4070        // Found a possible emoji shortcode at the beginning of the buffer
 4071        chars.reverse();
 4072        Some(chars.iter().collect())
 4073    }
 4074
 4075    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4076        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4077        self.transact(window, cx, |this, window, cx| {
 4078            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4079                let selections = this.selections.all::<usize>(cx);
 4080                let multi_buffer = this.buffer.read(cx);
 4081                let buffer = multi_buffer.snapshot(cx);
 4082                selections
 4083                    .iter()
 4084                    .map(|selection| {
 4085                        let start_point = selection.start.to_point(&buffer);
 4086                        let mut existing_indent =
 4087                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4088                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4089                        let start = selection.start;
 4090                        let end = selection.end;
 4091                        let selection_is_empty = start == end;
 4092                        let language_scope = buffer.language_scope_at(start);
 4093                        let (
 4094                            comment_delimiter,
 4095                            doc_delimiter,
 4096                            insert_extra_newline,
 4097                            indent_on_newline,
 4098                            indent_on_extra_newline,
 4099                        ) = if let Some(language) = &language_scope {
 4100                            let mut insert_extra_newline =
 4101                                insert_extra_newline_brackets(&buffer, start..end, language)
 4102                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4103
 4104                            // Comment extension on newline is allowed only for cursor selections
 4105                            let comment_delimiter = maybe!({
 4106                                if !selection_is_empty {
 4107                                    return None;
 4108                                }
 4109
 4110                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4111                                    return None;
 4112                                }
 4113
 4114                                let delimiters = language.line_comment_prefixes();
 4115                                let max_len_of_delimiter =
 4116                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4117                                let (snapshot, range) =
 4118                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4119
 4120                                let num_of_whitespaces = snapshot
 4121                                    .chars_for_range(range.clone())
 4122                                    .take_while(|c| c.is_whitespace())
 4123                                    .count();
 4124                                let comment_candidate = snapshot
 4125                                    .chars_for_range(range)
 4126                                    .skip(num_of_whitespaces)
 4127                                    .take(max_len_of_delimiter)
 4128                                    .collect::<String>();
 4129                                let (delimiter, trimmed_len) = delimiters
 4130                                    .iter()
 4131                                    .filter_map(|delimiter| {
 4132                                        let prefix = delimiter.trim_end();
 4133                                        if comment_candidate.starts_with(prefix) {
 4134                                            Some((delimiter, prefix.len()))
 4135                                        } else {
 4136                                            None
 4137                                        }
 4138                                    })
 4139                                    .max_by_key(|(_, len)| *len)?;
 4140
 4141                                let cursor_is_placed_after_comment_marker =
 4142                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4143                                if cursor_is_placed_after_comment_marker {
 4144                                    Some(delimiter.clone())
 4145                                } else {
 4146                                    None
 4147                                }
 4148                            });
 4149
 4150                            let mut indent_on_newline = IndentSize::spaces(0);
 4151                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4152
 4153                            let doc_delimiter = maybe!({
 4154                                if !selection_is_empty {
 4155                                    return None;
 4156                                }
 4157
 4158                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4159                                    return None;
 4160                                }
 4161
 4162                                let DocumentationConfig {
 4163                                    start: start_tag,
 4164                                    end: end_tag,
 4165                                    prefix: delimiter,
 4166                                    tab_size: len,
 4167                                } = language.documentation()?;
 4168
 4169                                let is_within_block_comment = buffer
 4170                                    .language_scope_at(start_point)
 4171                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4172                                if !is_within_block_comment {
 4173                                    return None;
 4174                                }
 4175
 4176                                let (snapshot, range) =
 4177                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4178
 4179                                let num_of_whitespaces = snapshot
 4180                                    .chars_for_range(range.clone())
 4181                                    .take_while(|c| c.is_whitespace())
 4182                                    .count();
 4183
 4184                                // 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.
 4185                                let column = start_point.column;
 4186                                let cursor_is_after_start_tag = {
 4187                                    let start_tag_len = start_tag.len();
 4188                                    let start_tag_line = snapshot
 4189                                        .chars_for_range(range.clone())
 4190                                        .skip(num_of_whitespaces)
 4191                                        .take(start_tag_len)
 4192                                        .collect::<String>();
 4193                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4194                                        num_of_whitespaces + start_tag_len <= column as usize
 4195                                    } else {
 4196                                        false
 4197                                    }
 4198                                };
 4199
 4200                                let cursor_is_after_delimiter = {
 4201                                    let delimiter_trim = delimiter.trim_end();
 4202                                    let delimiter_line = snapshot
 4203                                        .chars_for_range(range.clone())
 4204                                        .skip(num_of_whitespaces)
 4205                                        .take(delimiter_trim.len())
 4206                                        .collect::<String>();
 4207                                    if delimiter_line.starts_with(delimiter_trim) {
 4208                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4209                                    } else {
 4210                                        false
 4211                                    }
 4212                                };
 4213
 4214                                let cursor_is_before_end_tag_if_exists = {
 4215                                    let mut char_position = 0u32;
 4216                                    let mut end_tag_offset = None;
 4217
 4218                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4219                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4220                                            let chars_before_match =
 4221                                                chunk[..byte_pos].chars().count() as u32;
 4222                                            end_tag_offset =
 4223                                                Some(char_position + chars_before_match);
 4224                                            break 'outer;
 4225                                        }
 4226                                        char_position += chunk.chars().count() as u32;
 4227                                    }
 4228
 4229                                    if let Some(end_tag_offset) = end_tag_offset {
 4230                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4231                                        if cursor_is_after_start_tag {
 4232                                            if cursor_is_before_end_tag {
 4233                                                insert_extra_newline = true;
 4234                                            }
 4235                                            let cursor_is_at_start_of_end_tag =
 4236                                                column == end_tag_offset;
 4237                                            if cursor_is_at_start_of_end_tag {
 4238                                                indent_on_extra_newline.len = (*len).into();
 4239                                            }
 4240                                        }
 4241                                        cursor_is_before_end_tag
 4242                                    } else {
 4243                                        true
 4244                                    }
 4245                                };
 4246
 4247                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4248                                    && cursor_is_before_end_tag_if_exists
 4249                                {
 4250                                    if cursor_is_after_start_tag {
 4251                                        indent_on_newline.len = (*len).into();
 4252                                    }
 4253                                    Some(delimiter.clone())
 4254                                } else {
 4255                                    None
 4256                                }
 4257                            });
 4258
 4259                            (
 4260                                comment_delimiter,
 4261                                doc_delimiter,
 4262                                insert_extra_newline,
 4263                                indent_on_newline,
 4264                                indent_on_extra_newline,
 4265                            )
 4266                        } else {
 4267                            (
 4268                                None,
 4269                                None,
 4270                                false,
 4271                                IndentSize::default(),
 4272                                IndentSize::default(),
 4273                            )
 4274                        };
 4275
 4276                        let prevent_auto_indent = doc_delimiter.is_some();
 4277                        let delimiter = comment_delimiter.or(doc_delimiter);
 4278
 4279                        let capacity_for_delimiter =
 4280                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4281                        let mut new_text = String::with_capacity(
 4282                            1 + capacity_for_delimiter
 4283                                + existing_indent.len as usize
 4284                                + indent_on_newline.len as usize
 4285                                + indent_on_extra_newline.len as usize,
 4286                        );
 4287                        new_text.push('\n');
 4288                        new_text.extend(existing_indent.chars());
 4289                        new_text.extend(indent_on_newline.chars());
 4290
 4291                        if let Some(delimiter) = &delimiter {
 4292                            new_text.push_str(delimiter);
 4293                        }
 4294
 4295                        if insert_extra_newline {
 4296                            new_text.push('\n');
 4297                            new_text.extend(existing_indent.chars());
 4298                            new_text.extend(indent_on_extra_newline.chars());
 4299                        }
 4300
 4301                        let anchor = buffer.anchor_after(end);
 4302                        let new_selection = selection.map(|_| anchor);
 4303                        (
 4304                            ((start..end, new_text), prevent_auto_indent),
 4305                            (insert_extra_newline, new_selection),
 4306                        )
 4307                    })
 4308                    .unzip()
 4309            };
 4310
 4311            let mut auto_indent_edits = Vec::new();
 4312            let mut edits = Vec::new();
 4313            for (edit, prevent_auto_indent) in edits_with_flags {
 4314                if prevent_auto_indent {
 4315                    edits.push(edit);
 4316                } else {
 4317                    auto_indent_edits.push(edit);
 4318                }
 4319            }
 4320            if !edits.is_empty() {
 4321                this.edit(edits, cx);
 4322            }
 4323            if !auto_indent_edits.is_empty() {
 4324                this.edit_with_autoindent(auto_indent_edits, cx);
 4325            }
 4326
 4327            let buffer = this.buffer.read(cx).snapshot(cx);
 4328            let new_selections = selection_info
 4329                .into_iter()
 4330                .map(|(extra_newline_inserted, new_selection)| {
 4331                    let mut cursor = new_selection.end.to_point(&buffer);
 4332                    if extra_newline_inserted {
 4333                        cursor.row -= 1;
 4334                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4335                    }
 4336                    new_selection.map(|_| cursor)
 4337                })
 4338                .collect();
 4339
 4340            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4341                s.select(new_selections)
 4342            });
 4343            this.refresh_inline_completion(true, false, window, cx);
 4344        });
 4345    }
 4346
 4347    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4348        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4349
 4350        let buffer = self.buffer.read(cx);
 4351        let snapshot = buffer.snapshot(cx);
 4352
 4353        let mut edits = Vec::new();
 4354        let mut rows = Vec::new();
 4355
 4356        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4357            let cursor = selection.head();
 4358            let row = cursor.row;
 4359
 4360            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4361
 4362            let newline = "\n".to_string();
 4363            edits.push((start_of_line..start_of_line, newline));
 4364
 4365            rows.push(row + rows_inserted as u32);
 4366        }
 4367
 4368        self.transact(window, cx, |editor, window, cx| {
 4369            editor.edit(edits, cx);
 4370
 4371            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4372                let mut index = 0;
 4373                s.move_cursors_with(|map, _, _| {
 4374                    let row = rows[index];
 4375                    index += 1;
 4376
 4377                    let point = Point::new(row, 0);
 4378                    let boundary = map.next_line_boundary(point).1;
 4379                    let clipped = map.clip_point(boundary, Bias::Left);
 4380
 4381                    (clipped, SelectionGoal::None)
 4382                });
 4383            });
 4384
 4385            let mut indent_edits = Vec::new();
 4386            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4387            for row in rows {
 4388                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4389                for (row, indent) in indents {
 4390                    if indent.len == 0 {
 4391                        continue;
 4392                    }
 4393
 4394                    let text = match indent.kind {
 4395                        IndentKind::Space => " ".repeat(indent.len as usize),
 4396                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4397                    };
 4398                    let point = Point::new(row.0, 0);
 4399                    indent_edits.push((point..point, text));
 4400                }
 4401            }
 4402            editor.edit(indent_edits, cx);
 4403        });
 4404    }
 4405
 4406    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4407        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4408
 4409        let buffer = self.buffer.read(cx);
 4410        let snapshot = buffer.snapshot(cx);
 4411
 4412        let mut edits = Vec::new();
 4413        let mut rows = Vec::new();
 4414        let mut rows_inserted = 0;
 4415
 4416        for selection in self.selections.all_adjusted(cx) {
 4417            let cursor = selection.head();
 4418            let row = cursor.row;
 4419
 4420            let point = Point::new(row + 1, 0);
 4421            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4422
 4423            let newline = "\n".to_string();
 4424            edits.push((start_of_line..start_of_line, newline));
 4425
 4426            rows_inserted += 1;
 4427            rows.push(row + rows_inserted);
 4428        }
 4429
 4430        self.transact(window, cx, |editor, window, cx| {
 4431            editor.edit(edits, cx);
 4432
 4433            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4434                let mut index = 0;
 4435                s.move_cursors_with(|map, _, _| {
 4436                    let row = rows[index];
 4437                    index += 1;
 4438
 4439                    let point = Point::new(row, 0);
 4440                    let boundary = map.next_line_boundary(point).1;
 4441                    let clipped = map.clip_point(boundary, Bias::Left);
 4442
 4443                    (clipped, SelectionGoal::None)
 4444                });
 4445            });
 4446
 4447            let mut indent_edits = Vec::new();
 4448            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4449            for row in rows {
 4450                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4451                for (row, indent) in indents {
 4452                    if indent.len == 0 {
 4453                        continue;
 4454                    }
 4455
 4456                    let text = match indent.kind {
 4457                        IndentKind::Space => " ".repeat(indent.len as usize),
 4458                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4459                    };
 4460                    let point = Point::new(row.0, 0);
 4461                    indent_edits.push((point..point, text));
 4462                }
 4463            }
 4464            editor.edit(indent_edits, cx);
 4465        });
 4466    }
 4467
 4468    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4469        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4470            original_indent_columns: Vec::new(),
 4471        });
 4472        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4473    }
 4474
 4475    fn insert_with_autoindent_mode(
 4476        &mut self,
 4477        text: &str,
 4478        autoindent_mode: Option<AutoindentMode>,
 4479        window: &mut Window,
 4480        cx: &mut Context<Self>,
 4481    ) {
 4482        if self.read_only(cx) {
 4483            return;
 4484        }
 4485
 4486        let text: Arc<str> = text.into();
 4487        self.transact(window, cx, |this, window, cx| {
 4488            let old_selections = this.selections.all_adjusted(cx);
 4489            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4490                let anchors = {
 4491                    let snapshot = buffer.read(cx);
 4492                    old_selections
 4493                        .iter()
 4494                        .map(|s| {
 4495                            let anchor = snapshot.anchor_after(s.head());
 4496                            s.map(|_| anchor)
 4497                        })
 4498                        .collect::<Vec<_>>()
 4499                };
 4500                buffer.edit(
 4501                    old_selections
 4502                        .iter()
 4503                        .map(|s| (s.start..s.end, text.clone())),
 4504                    autoindent_mode,
 4505                    cx,
 4506                );
 4507                anchors
 4508            });
 4509
 4510            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4511                s.select_anchors(selection_anchors);
 4512            });
 4513
 4514            cx.notify();
 4515        });
 4516    }
 4517
 4518    fn trigger_completion_on_input(
 4519        &mut self,
 4520        text: &str,
 4521        trigger_in_words: bool,
 4522        window: &mut Window,
 4523        cx: &mut Context<Self>,
 4524    ) {
 4525        let completions_source = self
 4526            .context_menu
 4527            .borrow()
 4528            .as_ref()
 4529            .and_then(|menu| match menu {
 4530                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4531                CodeContextMenu::CodeActions(_) => None,
 4532            });
 4533
 4534        match completions_source {
 4535            Some(CompletionsMenuSource::Words) => {
 4536                self.show_word_completions(&ShowWordCompletions, window, cx)
 4537            }
 4538            Some(CompletionsMenuSource::Normal)
 4539            | Some(CompletionsMenuSource::SnippetChoices)
 4540            | None
 4541                if self.is_completion_trigger(
 4542                    text,
 4543                    trigger_in_words,
 4544                    completions_source.is_some(),
 4545                    cx,
 4546                ) =>
 4547            {
 4548                self.show_completions(
 4549                    &ShowCompletions {
 4550                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4551                    },
 4552                    window,
 4553                    cx,
 4554                )
 4555            }
 4556            _ => {
 4557                self.hide_context_menu(window, cx);
 4558            }
 4559        }
 4560    }
 4561
 4562    fn is_completion_trigger(
 4563        &self,
 4564        text: &str,
 4565        trigger_in_words: bool,
 4566        menu_is_open: bool,
 4567        cx: &mut Context<Self>,
 4568    ) -> bool {
 4569        let position = self.selections.newest_anchor().head();
 4570        let multibuffer = self.buffer.read(cx);
 4571        let Some(buffer) = position
 4572            .buffer_id
 4573            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4574        else {
 4575            return false;
 4576        };
 4577
 4578        if let Some(completion_provider) = &self.completion_provider {
 4579            completion_provider.is_completion_trigger(
 4580                &buffer,
 4581                position.text_anchor,
 4582                text,
 4583                trigger_in_words,
 4584                menu_is_open,
 4585                cx,
 4586            )
 4587        } else {
 4588            false
 4589        }
 4590    }
 4591
 4592    /// If any empty selections is touching the start of its innermost containing autoclose
 4593    /// region, expand it to select the brackets.
 4594    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4595        let selections = self.selections.all::<usize>(cx);
 4596        let buffer = self.buffer.read(cx).read(cx);
 4597        let new_selections = self
 4598            .selections_with_autoclose_regions(selections, &buffer)
 4599            .map(|(mut selection, region)| {
 4600                if !selection.is_empty() {
 4601                    return selection;
 4602                }
 4603
 4604                if let Some(region) = region {
 4605                    let mut range = region.range.to_offset(&buffer);
 4606                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4607                        range.start -= region.pair.start.len();
 4608                        if buffer.contains_str_at(range.start, &region.pair.start)
 4609                            && buffer.contains_str_at(range.end, &region.pair.end)
 4610                        {
 4611                            range.end += region.pair.end.len();
 4612                            selection.start = range.start;
 4613                            selection.end = range.end;
 4614
 4615                            return selection;
 4616                        }
 4617                    }
 4618                }
 4619
 4620                let always_treat_brackets_as_autoclosed = buffer
 4621                    .language_settings_at(selection.start, cx)
 4622                    .always_treat_brackets_as_autoclosed;
 4623
 4624                if !always_treat_brackets_as_autoclosed {
 4625                    return selection;
 4626                }
 4627
 4628                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4629                    for (pair, enabled) in scope.brackets() {
 4630                        if !enabled || !pair.close {
 4631                            continue;
 4632                        }
 4633
 4634                        if buffer.contains_str_at(selection.start, &pair.end) {
 4635                            let pair_start_len = pair.start.len();
 4636                            if buffer.contains_str_at(
 4637                                selection.start.saturating_sub(pair_start_len),
 4638                                &pair.start,
 4639                            ) {
 4640                                selection.start -= pair_start_len;
 4641                                selection.end += pair.end.len();
 4642
 4643                                return selection;
 4644                            }
 4645                        }
 4646                    }
 4647                }
 4648
 4649                selection
 4650            })
 4651            .collect();
 4652
 4653        drop(buffer);
 4654        self.change_selections(None, window, cx, |selections| {
 4655            selections.select(new_selections)
 4656        });
 4657    }
 4658
 4659    /// Iterate the given selections, and for each one, find the smallest surrounding
 4660    /// autoclose region. This uses the ordering of the selections and the autoclose
 4661    /// regions to avoid repeated comparisons.
 4662    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4663        &'a self,
 4664        selections: impl IntoIterator<Item = Selection<D>>,
 4665        buffer: &'a MultiBufferSnapshot,
 4666    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4667        let mut i = 0;
 4668        let mut regions = self.autoclose_regions.as_slice();
 4669        selections.into_iter().map(move |selection| {
 4670            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4671
 4672            let mut enclosing = None;
 4673            while let Some(pair_state) = regions.get(i) {
 4674                if pair_state.range.end.to_offset(buffer) < range.start {
 4675                    regions = &regions[i + 1..];
 4676                    i = 0;
 4677                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4678                    break;
 4679                } else {
 4680                    if pair_state.selection_id == selection.id {
 4681                        enclosing = Some(pair_state);
 4682                    }
 4683                    i += 1;
 4684                }
 4685            }
 4686
 4687            (selection, enclosing)
 4688        })
 4689    }
 4690
 4691    /// Remove any autoclose regions that no longer contain their selection.
 4692    fn invalidate_autoclose_regions(
 4693        &mut self,
 4694        mut selections: &[Selection<Anchor>],
 4695        buffer: &MultiBufferSnapshot,
 4696    ) {
 4697        self.autoclose_regions.retain(|state| {
 4698            let mut i = 0;
 4699            while let Some(selection) = selections.get(i) {
 4700                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4701                    selections = &selections[1..];
 4702                    continue;
 4703                }
 4704                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4705                    break;
 4706                }
 4707                if selection.id == state.selection_id {
 4708                    return true;
 4709                } else {
 4710                    i += 1;
 4711                }
 4712            }
 4713            false
 4714        });
 4715    }
 4716
 4717    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4718        let offset = position.to_offset(buffer);
 4719        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4720        if offset > word_range.start && kind == Some(CharKind::Word) {
 4721            Some(
 4722                buffer
 4723                    .text_for_range(word_range.start..offset)
 4724                    .collect::<String>(),
 4725            )
 4726        } else {
 4727            None
 4728        }
 4729    }
 4730
 4731    pub fn toggle_inline_values(
 4732        &mut self,
 4733        _: &ToggleInlineValues,
 4734        _: &mut Window,
 4735        cx: &mut Context<Self>,
 4736    ) {
 4737        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4738
 4739        self.refresh_inline_values(cx);
 4740    }
 4741
 4742    pub fn toggle_inlay_hints(
 4743        &mut self,
 4744        _: &ToggleInlayHints,
 4745        _: &mut Window,
 4746        cx: &mut Context<Self>,
 4747    ) {
 4748        self.refresh_inlay_hints(
 4749            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4750            cx,
 4751        );
 4752    }
 4753
 4754    pub fn inlay_hints_enabled(&self) -> bool {
 4755        self.inlay_hint_cache.enabled
 4756    }
 4757
 4758    pub fn inline_values_enabled(&self) -> bool {
 4759        self.inline_value_cache.enabled
 4760    }
 4761
 4762    #[cfg(any(test, feature = "test-support"))]
 4763    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4764        self.display_map
 4765            .read(cx)
 4766            .current_inlays()
 4767            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4768            .cloned()
 4769            .collect()
 4770    }
 4771
 4772    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4773        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4774            return;
 4775        }
 4776
 4777        let reason_description = reason.description();
 4778        let ignore_debounce = matches!(
 4779            reason,
 4780            InlayHintRefreshReason::SettingsChange(_)
 4781                | InlayHintRefreshReason::Toggle(_)
 4782                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4783                | InlayHintRefreshReason::ModifiersChanged(_)
 4784        );
 4785        let (invalidate_cache, required_languages) = match reason {
 4786            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4787                match self.inlay_hint_cache.modifiers_override(enabled) {
 4788                    Some(enabled) => {
 4789                        if enabled {
 4790                            (InvalidationStrategy::RefreshRequested, None)
 4791                        } else {
 4792                            self.splice_inlays(
 4793                                &self
 4794                                    .visible_inlay_hints(cx)
 4795                                    .iter()
 4796                                    .map(|inlay| inlay.id)
 4797                                    .collect::<Vec<InlayId>>(),
 4798                                Vec::new(),
 4799                                cx,
 4800                            );
 4801                            return;
 4802                        }
 4803                    }
 4804                    None => return,
 4805                }
 4806            }
 4807            InlayHintRefreshReason::Toggle(enabled) => {
 4808                if self.inlay_hint_cache.toggle(enabled) {
 4809                    if enabled {
 4810                        (InvalidationStrategy::RefreshRequested, None)
 4811                    } else {
 4812                        self.splice_inlays(
 4813                            &self
 4814                                .visible_inlay_hints(cx)
 4815                                .iter()
 4816                                .map(|inlay| inlay.id)
 4817                                .collect::<Vec<InlayId>>(),
 4818                            Vec::new(),
 4819                            cx,
 4820                        );
 4821                        return;
 4822                    }
 4823                } else {
 4824                    return;
 4825                }
 4826            }
 4827            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4828                match self.inlay_hint_cache.update_settings(
 4829                    &self.buffer,
 4830                    new_settings,
 4831                    self.visible_inlay_hints(cx),
 4832                    cx,
 4833                ) {
 4834                    ControlFlow::Break(Some(InlaySplice {
 4835                        to_remove,
 4836                        to_insert,
 4837                    })) => {
 4838                        self.splice_inlays(&to_remove, to_insert, cx);
 4839                        return;
 4840                    }
 4841                    ControlFlow::Break(None) => return,
 4842                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4843                }
 4844            }
 4845            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4846                if let Some(InlaySplice {
 4847                    to_remove,
 4848                    to_insert,
 4849                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4850                {
 4851                    self.splice_inlays(&to_remove, to_insert, cx);
 4852                }
 4853                self.display_map.update(cx, |display_map, _| {
 4854                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4855                });
 4856                return;
 4857            }
 4858            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4859            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4860                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4861            }
 4862            InlayHintRefreshReason::RefreshRequested => {
 4863                (InvalidationStrategy::RefreshRequested, None)
 4864            }
 4865        };
 4866
 4867        if let Some(InlaySplice {
 4868            to_remove,
 4869            to_insert,
 4870        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4871            reason_description,
 4872            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4873            invalidate_cache,
 4874            ignore_debounce,
 4875            cx,
 4876        ) {
 4877            self.splice_inlays(&to_remove, to_insert, cx);
 4878        }
 4879    }
 4880
 4881    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4882        self.display_map
 4883            .read(cx)
 4884            .current_inlays()
 4885            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4886            .cloned()
 4887            .collect()
 4888    }
 4889
 4890    pub fn excerpts_for_inlay_hints_query(
 4891        &self,
 4892        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4893        cx: &mut Context<Editor>,
 4894    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4895        let Some(project) = self.project.as_ref() else {
 4896            return HashMap::default();
 4897        };
 4898        let project = project.read(cx);
 4899        let multi_buffer = self.buffer().read(cx);
 4900        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4901        let multi_buffer_visible_start = self
 4902            .scroll_manager
 4903            .anchor()
 4904            .anchor
 4905            .to_point(&multi_buffer_snapshot);
 4906        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4907            multi_buffer_visible_start
 4908                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4909            Bias::Left,
 4910        );
 4911        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4912        multi_buffer_snapshot
 4913            .range_to_buffer_ranges(multi_buffer_visible_range)
 4914            .into_iter()
 4915            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4916            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4917                let buffer_file = project::File::from_dyn(buffer.file())?;
 4918                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4919                let worktree_entry = buffer_worktree
 4920                    .read(cx)
 4921                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4922                if worktree_entry.is_ignored {
 4923                    return None;
 4924                }
 4925
 4926                let language = buffer.language()?;
 4927                if let Some(restrict_to_languages) = restrict_to_languages {
 4928                    if !restrict_to_languages.contains(language) {
 4929                        return None;
 4930                    }
 4931                }
 4932                Some((
 4933                    excerpt_id,
 4934                    (
 4935                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4936                        buffer.version().clone(),
 4937                        excerpt_visible_range,
 4938                    ),
 4939                ))
 4940            })
 4941            .collect()
 4942    }
 4943
 4944    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4945        TextLayoutDetails {
 4946            text_system: window.text_system().clone(),
 4947            editor_style: self.style.clone().unwrap(),
 4948            rem_size: window.rem_size(),
 4949            scroll_anchor: self.scroll_manager.anchor(),
 4950            visible_rows: self.visible_line_count(),
 4951            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4952        }
 4953    }
 4954
 4955    pub fn splice_inlays(
 4956        &self,
 4957        to_remove: &[InlayId],
 4958        to_insert: Vec<Inlay>,
 4959        cx: &mut Context<Self>,
 4960    ) {
 4961        self.display_map.update(cx, |display_map, cx| {
 4962            display_map.splice_inlays(to_remove, to_insert, cx)
 4963        });
 4964        cx.notify();
 4965    }
 4966
 4967    fn trigger_on_type_formatting(
 4968        &self,
 4969        input: String,
 4970        window: &mut Window,
 4971        cx: &mut Context<Self>,
 4972    ) -> Option<Task<Result<()>>> {
 4973        if input.len() != 1 {
 4974            return None;
 4975        }
 4976
 4977        let project = self.project.as_ref()?;
 4978        let position = self.selections.newest_anchor().head();
 4979        let (buffer, buffer_position) = self
 4980            .buffer
 4981            .read(cx)
 4982            .text_anchor_for_position(position, cx)?;
 4983
 4984        let settings = language_settings::language_settings(
 4985            buffer
 4986                .read(cx)
 4987                .language_at(buffer_position)
 4988                .map(|l| l.name()),
 4989            buffer.read(cx).file(),
 4990            cx,
 4991        );
 4992        if !settings.use_on_type_format {
 4993            return None;
 4994        }
 4995
 4996        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4997        // hence we do LSP request & edit on host side only — add formats to host's history.
 4998        let push_to_lsp_host_history = true;
 4999        // If this is not the host, append its history with new edits.
 5000        let push_to_client_history = project.read(cx).is_via_collab();
 5001
 5002        let on_type_formatting = project.update(cx, |project, cx| {
 5003            project.on_type_format(
 5004                buffer.clone(),
 5005                buffer_position,
 5006                input,
 5007                push_to_lsp_host_history,
 5008                cx,
 5009            )
 5010        });
 5011        Some(cx.spawn_in(window, async move |editor, cx| {
 5012            if let Some(transaction) = on_type_formatting.await? {
 5013                if push_to_client_history {
 5014                    buffer
 5015                        .update(cx, |buffer, _| {
 5016                            buffer.push_transaction(transaction, Instant::now());
 5017                            buffer.finalize_last_transaction();
 5018                        })
 5019                        .ok();
 5020                }
 5021                editor.update(cx, |editor, cx| {
 5022                    editor.refresh_document_highlights(cx);
 5023                })?;
 5024            }
 5025            Ok(())
 5026        }))
 5027    }
 5028
 5029    pub fn show_word_completions(
 5030        &mut self,
 5031        _: &ShowWordCompletions,
 5032        window: &mut Window,
 5033        cx: &mut Context<Self>,
 5034    ) {
 5035        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5036    }
 5037
 5038    pub fn show_completions(
 5039        &mut self,
 5040        options: &ShowCompletions,
 5041        window: &mut Window,
 5042        cx: &mut Context<Self>,
 5043    ) {
 5044        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5045    }
 5046
 5047    fn open_or_update_completions_menu(
 5048        &mut self,
 5049        requested_source: Option<CompletionsMenuSource>,
 5050        trigger: Option<&str>,
 5051        window: &mut Window,
 5052        cx: &mut Context<Self>,
 5053    ) {
 5054        if self.pending_rename.is_some() {
 5055            return;
 5056        }
 5057
 5058        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5059
 5060        let position = self
 5061            .selections
 5062            .newest_anchor()
 5063            .head()
 5064            .bias_right(&multibuffer_snapshot);
 5065        if position.diff_base_anchor.is_some() {
 5066            return;
 5067        }
 5068        let (buffer, buffer_position) =
 5069            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5070                output
 5071            } else {
 5072                return;
 5073            };
 5074        let buffer_snapshot = buffer.read(cx).snapshot();
 5075
 5076        let query: Option<Arc<String>> =
 5077            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5078
 5079        drop(multibuffer_snapshot);
 5080
 5081        let provider = match requested_source {
 5082            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5083            Some(CompletionsMenuSource::Words) => None,
 5084            Some(CompletionsMenuSource::SnippetChoices) => {
 5085                log::error!("bug: SnippetChoices requested_source is not handled");
 5086                None
 5087            }
 5088        };
 5089
 5090        let sort_completions = provider
 5091            .as_ref()
 5092            .map_or(false, |provider| provider.sort_completions());
 5093
 5094        let filter_completions = provider
 5095            .as_ref()
 5096            .map_or(true, |provider| provider.filter_completions());
 5097
 5098        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5099            if filter_completions {
 5100                menu.filter(query.clone(), provider.clone(), window, cx);
 5101            }
 5102            // When `is_incomplete` is false, no need to re-query completions when the current query
 5103            // is a suffix of the initial query.
 5104            if !menu.is_incomplete {
 5105                // If the new query is a suffix of the old query (typing more characters) and
 5106                // the previous result was complete, the existing completions can be filtered.
 5107                //
 5108                // Note that this is always true for snippet completions.
 5109                let query_matches = match (&menu.initial_query, &query) {
 5110                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5111                    (None, _) => true,
 5112                    _ => false,
 5113                };
 5114                if query_matches {
 5115                    let position_matches = if menu.initial_position == position {
 5116                        true
 5117                    } else {
 5118                        let snapshot = self.buffer.read(cx).read(cx);
 5119                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5120                    };
 5121                    if position_matches {
 5122                        return;
 5123                    }
 5124                }
 5125            }
 5126        };
 5127
 5128        let trigger_kind = match trigger {
 5129            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5130                CompletionTriggerKind::TRIGGER_CHARACTER
 5131            }
 5132            _ => CompletionTriggerKind::INVOKED,
 5133        };
 5134        let completion_context = CompletionContext {
 5135            trigger_character: trigger.and_then(|trigger| {
 5136                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5137                    Some(String::from(trigger))
 5138                } else {
 5139                    None
 5140                }
 5141            }),
 5142            trigger_kind,
 5143        };
 5144
 5145        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5146            buffer_snapshot.surrounding_word(buffer_position)
 5147        {
 5148            let word_to_exclude = buffer_snapshot
 5149                .text_for_range(word_range.clone())
 5150                .collect::<String>();
 5151            (
 5152                buffer_snapshot.anchor_before(word_range.start)
 5153                    ..buffer_snapshot.anchor_after(buffer_position),
 5154                Some(word_to_exclude),
 5155            )
 5156        } else {
 5157            (buffer_position..buffer_position, None)
 5158        };
 5159
 5160        let language = buffer_snapshot
 5161            .language_at(buffer_position)
 5162            .map(|language| language.name());
 5163
 5164        let completion_settings =
 5165            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5166
 5167        let show_completion_documentation = buffer_snapshot
 5168            .settings_at(buffer_position, cx)
 5169            .show_completion_documentation;
 5170
 5171        // The document can be large, so stay in reasonable bounds when searching for words,
 5172        // otherwise completion pop-up might be slow to appear.
 5173        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5174        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5175        let min_word_search = buffer_snapshot.clip_point(
 5176            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5177            Bias::Left,
 5178        );
 5179        let max_word_search = buffer_snapshot.clip_point(
 5180            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5181            Bias::Right,
 5182        );
 5183        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5184            ..buffer_snapshot.point_to_offset(max_word_search);
 5185
 5186        let skip_digits = query
 5187            .as_ref()
 5188            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5189
 5190        let (mut words, provider_responses) = match &provider {
 5191            Some(provider) => {
 5192                let provider_responses = provider.completions(
 5193                    position.excerpt_id,
 5194                    &buffer,
 5195                    buffer_position,
 5196                    completion_context,
 5197                    window,
 5198                    cx,
 5199                );
 5200
 5201                let words = match completion_settings.words {
 5202                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5203                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5204                        .background_spawn(async move {
 5205                            buffer_snapshot.words_in_range(WordsQuery {
 5206                                fuzzy_contents: None,
 5207                                range: word_search_range,
 5208                                skip_digits,
 5209                            })
 5210                        }),
 5211                };
 5212
 5213                (words, provider_responses)
 5214            }
 5215            None => (
 5216                cx.background_spawn(async move {
 5217                    buffer_snapshot.words_in_range(WordsQuery {
 5218                        fuzzy_contents: None,
 5219                        range: word_search_range,
 5220                        skip_digits,
 5221                    })
 5222                }),
 5223                Task::ready(Ok(Vec::new())),
 5224            ),
 5225        };
 5226
 5227        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5228
 5229        let id = post_inc(&mut self.next_completion_id);
 5230        let task = cx.spawn_in(window, async move |editor, cx| {
 5231            let Ok(()) = editor.update(cx, |this, _| {
 5232                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5233            }) else {
 5234                return;
 5235            };
 5236
 5237            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5238            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5239            let mut completions = Vec::new();
 5240            let mut is_incomplete = false;
 5241            if let Some(provider_responses) = provider_responses.await.log_err() {
 5242                if !provider_responses.is_empty() {
 5243                    for response in provider_responses {
 5244                        completions.extend(response.completions);
 5245                        is_incomplete = is_incomplete || response.is_incomplete;
 5246                    }
 5247                    if completion_settings.words == WordsCompletionMode::Fallback {
 5248                        words = Task::ready(BTreeMap::default());
 5249                    }
 5250                }
 5251            }
 5252
 5253            let mut words = words.await;
 5254            if let Some(word_to_exclude) = &word_to_exclude {
 5255                words.remove(word_to_exclude);
 5256            }
 5257            for lsp_completion in &completions {
 5258                words.remove(&lsp_completion.new_text);
 5259            }
 5260            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5261                replace_range: word_replace_range.clone(),
 5262                new_text: word.clone(),
 5263                label: CodeLabel::plain(word, None),
 5264                icon_path: None,
 5265                documentation: None,
 5266                source: CompletionSource::BufferWord {
 5267                    word_range,
 5268                    resolved: false,
 5269                },
 5270                insert_text_mode: Some(InsertTextMode::AS_IS),
 5271                confirm: None,
 5272            }));
 5273
 5274            let menu = if completions.is_empty() {
 5275                None
 5276            } else {
 5277                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5278                    let languages = editor
 5279                        .workspace
 5280                        .as_ref()
 5281                        .and_then(|(workspace, _)| workspace.upgrade())
 5282                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5283                    let menu = CompletionsMenu::new(
 5284                        id,
 5285                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5286                        sort_completions,
 5287                        show_completion_documentation,
 5288                        position,
 5289                        query.clone(),
 5290                        is_incomplete,
 5291                        buffer.clone(),
 5292                        completions.into(),
 5293                        snippet_sort_order,
 5294                        languages,
 5295                        language,
 5296                        cx,
 5297                    );
 5298
 5299                    let query = if filter_completions { query } else { None };
 5300                    let matches_task = if let Some(query) = query {
 5301                        menu.do_async_filtering(query, cx)
 5302                    } else {
 5303                        Task::ready(menu.unfiltered_matches())
 5304                    };
 5305                    (menu, matches_task)
 5306                }) else {
 5307                    return;
 5308                };
 5309
 5310                let matches = matches_task.await;
 5311
 5312                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5313                    // Newer menu already set, so exit.
 5314                    match editor.context_menu.borrow().as_ref() {
 5315                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5316                            if prev_menu.id > id {
 5317                                return;
 5318                            }
 5319                        }
 5320                        _ => {}
 5321                    };
 5322
 5323                    // Only valid to take prev_menu because it the new menu is immediately set
 5324                    // below, or the menu is hidden.
 5325                    match editor.context_menu.borrow_mut().take() {
 5326                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5327                            let position_matches =
 5328                                if prev_menu.initial_position == menu.initial_position {
 5329                                    true
 5330                                } else {
 5331                                    let snapshot = editor.buffer.read(cx).read(cx);
 5332                                    prev_menu.initial_position.to_offset(&snapshot)
 5333                                        == menu.initial_position.to_offset(&snapshot)
 5334                                };
 5335                            if position_matches {
 5336                                // Preserve markdown cache before `set_filter_results` because it will
 5337                                // try to populate the documentation cache.
 5338                                menu.preserve_markdown_cache(prev_menu);
 5339                            }
 5340                        }
 5341                        _ => {}
 5342                    };
 5343
 5344                    menu.set_filter_results(matches, provider, window, cx);
 5345                }) else {
 5346                    return;
 5347                };
 5348
 5349                menu.visible().then_some(menu)
 5350            };
 5351
 5352            editor
 5353                .update_in(cx, |editor, window, cx| {
 5354                    if editor.focus_handle.is_focused(window) {
 5355                        if let Some(menu) = menu {
 5356                            *editor.context_menu.borrow_mut() =
 5357                                Some(CodeContextMenu::Completions(menu));
 5358
 5359                            crate::hover_popover::hide_hover(editor, cx);
 5360                            if editor.show_edit_predictions_in_menu() {
 5361                                editor.update_visible_inline_completion(window, cx);
 5362                            } else {
 5363                                editor.discard_inline_completion(false, cx);
 5364                            }
 5365
 5366                            cx.notify();
 5367                            return;
 5368                        }
 5369                    }
 5370
 5371                    if editor.completion_tasks.len() <= 1 {
 5372                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5373                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5374                        // If it was already hidden and we don't show inline completions in the menu, we should
 5375                        // also show the inline-completion when available.
 5376                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5377                            editor.update_visible_inline_completion(window, cx);
 5378                        }
 5379                    }
 5380                })
 5381                .ok();
 5382        });
 5383
 5384        self.completion_tasks.push((id, task));
 5385    }
 5386
 5387    #[cfg(feature = "test-support")]
 5388    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5389        let menu = self.context_menu.borrow();
 5390        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5391            let completions = menu.completions.borrow();
 5392            Some(completions.to_vec())
 5393        } else {
 5394            None
 5395        }
 5396    }
 5397
 5398    pub fn with_completions_menu_matching_id<R>(
 5399        &self,
 5400        id: CompletionId,
 5401        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5402    ) -> R {
 5403        let mut context_menu = self.context_menu.borrow_mut();
 5404        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5405            return f(None);
 5406        };
 5407        if completions_menu.id != id {
 5408            return f(None);
 5409        }
 5410        f(Some(completions_menu))
 5411    }
 5412
 5413    pub fn confirm_completion(
 5414        &mut self,
 5415        action: &ConfirmCompletion,
 5416        window: &mut Window,
 5417        cx: &mut Context<Self>,
 5418    ) -> Option<Task<Result<()>>> {
 5419        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5420        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5421    }
 5422
 5423    pub fn confirm_completion_insert(
 5424        &mut self,
 5425        _: &ConfirmCompletionInsert,
 5426        window: &mut Window,
 5427        cx: &mut Context<Self>,
 5428    ) -> Option<Task<Result<()>>> {
 5429        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5430        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5431    }
 5432
 5433    pub fn confirm_completion_replace(
 5434        &mut self,
 5435        _: &ConfirmCompletionReplace,
 5436        window: &mut Window,
 5437        cx: &mut Context<Self>,
 5438    ) -> Option<Task<Result<()>>> {
 5439        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5440        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5441    }
 5442
 5443    pub fn compose_completion(
 5444        &mut self,
 5445        action: &ComposeCompletion,
 5446        window: &mut Window,
 5447        cx: &mut Context<Self>,
 5448    ) -> Option<Task<Result<()>>> {
 5449        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5450        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5451    }
 5452
 5453    fn do_completion(
 5454        &mut self,
 5455        item_ix: Option<usize>,
 5456        intent: CompletionIntent,
 5457        window: &mut Window,
 5458        cx: &mut Context<Editor>,
 5459    ) -> Option<Task<Result<()>>> {
 5460        use language::ToOffset as _;
 5461
 5462        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5463        else {
 5464            return None;
 5465        };
 5466
 5467        let candidate_id = {
 5468            let entries = completions_menu.entries.borrow();
 5469            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5470            if self.show_edit_predictions_in_menu() {
 5471                self.discard_inline_completion(true, cx);
 5472            }
 5473            mat.candidate_id
 5474        };
 5475
 5476        let completion = completions_menu
 5477            .completions
 5478            .borrow()
 5479            .get(candidate_id)?
 5480            .clone();
 5481        cx.stop_propagation();
 5482
 5483        let buffer_handle = completions_menu.buffer.clone();
 5484
 5485        let CompletionEdit {
 5486            new_text,
 5487            snippet,
 5488            replace_range,
 5489        } = process_completion_for_edit(
 5490            &completion,
 5491            intent,
 5492            &buffer_handle,
 5493            &completions_menu.initial_position.text_anchor,
 5494            cx,
 5495        );
 5496
 5497        let buffer = buffer_handle.read(cx);
 5498        let snapshot = self.buffer.read(cx).snapshot(cx);
 5499        let newest_anchor = self.selections.newest_anchor();
 5500        let replace_range_multibuffer = {
 5501            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5502            let multibuffer_anchor = snapshot
 5503                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5504                .unwrap()
 5505                ..snapshot
 5506                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5507                    .unwrap();
 5508            multibuffer_anchor.start.to_offset(&snapshot)
 5509                ..multibuffer_anchor.end.to_offset(&snapshot)
 5510        };
 5511        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5512            return None;
 5513        }
 5514
 5515        let old_text = buffer
 5516            .text_for_range(replace_range.clone())
 5517            .collect::<String>();
 5518        let lookbehind = newest_anchor
 5519            .start
 5520            .text_anchor
 5521            .to_offset(buffer)
 5522            .saturating_sub(replace_range.start);
 5523        let lookahead = replace_range
 5524            .end
 5525            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5526        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5527        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5528
 5529        let selections = self.selections.all::<usize>(cx);
 5530        let mut ranges = Vec::new();
 5531        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5532
 5533        for selection in &selections {
 5534            let range = if selection.id == newest_anchor.id {
 5535                replace_range_multibuffer.clone()
 5536            } else {
 5537                let mut range = selection.range();
 5538
 5539                // if prefix is present, don't duplicate it
 5540                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5541                    range.start = range.start.saturating_sub(lookbehind);
 5542
 5543                    // if suffix is also present, mimic the newest cursor and replace it
 5544                    if selection.id != newest_anchor.id
 5545                        && snapshot.contains_str_at(range.end, suffix)
 5546                    {
 5547                        range.end += lookahead;
 5548                    }
 5549                }
 5550                range
 5551            };
 5552
 5553            ranges.push(range.clone());
 5554
 5555            if !self.linked_edit_ranges.is_empty() {
 5556                let start_anchor = snapshot.anchor_before(range.start);
 5557                let end_anchor = snapshot.anchor_after(range.end);
 5558                if let Some(ranges) = self
 5559                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5560                {
 5561                    for (buffer, edits) in ranges {
 5562                        linked_edits
 5563                            .entry(buffer.clone())
 5564                            .or_default()
 5565                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5566                    }
 5567                }
 5568            }
 5569        }
 5570
 5571        let common_prefix_len = old_text
 5572            .chars()
 5573            .zip(new_text.chars())
 5574            .take_while(|(a, b)| a == b)
 5575            .map(|(a, _)| a.len_utf8())
 5576            .sum::<usize>();
 5577
 5578        cx.emit(EditorEvent::InputHandled {
 5579            utf16_range_to_replace: None,
 5580            text: new_text[common_prefix_len..].into(),
 5581        });
 5582
 5583        self.transact(window, cx, |this, window, cx| {
 5584            if let Some(mut snippet) = snippet {
 5585                snippet.text = new_text.to_string();
 5586                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5587            } else {
 5588                this.buffer.update(cx, |buffer, cx| {
 5589                    let auto_indent = match completion.insert_text_mode {
 5590                        Some(InsertTextMode::AS_IS) => None,
 5591                        _ => this.autoindent_mode.clone(),
 5592                    };
 5593                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5594                    buffer.edit(edits, auto_indent, cx);
 5595                });
 5596            }
 5597            for (buffer, edits) in linked_edits {
 5598                buffer.update(cx, |buffer, cx| {
 5599                    let snapshot = buffer.snapshot();
 5600                    let edits = edits
 5601                        .into_iter()
 5602                        .map(|(range, text)| {
 5603                            use text::ToPoint as TP;
 5604                            let end_point = TP::to_point(&range.end, &snapshot);
 5605                            let start_point = TP::to_point(&range.start, &snapshot);
 5606                            (start_point..end_point, text)
 5607                        })
 5608                        .sorted_by_key(|(range, _)| range.start);
 5609                    buffer.edit(edits, None, cx);
 5610                })
 5611            }
 5612
 5613            this.refresh_inline_completion(true, false, window, cx);
 5614        });
 5615
 5616        let show_new_completions_on_confirm = completion
 5617            .confirm
 5618            .as_ref()
 5619            .map_or(false, |confirm| confirm(intent, window, cx));
 5620        if show_new_completions_on_confirm {
 5621            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5622        }
 5623
 5624        let provider = self.completion_provider.as_ref()?;
 5625        drop(completion);
 5626        let apply_edits = provider.apply_additional_edits_for_completion(
 5627            buffer_handle,
 5628            completions_menu.completions.clone(),
 5629            candidate_id,
 5630            true,
 5631            cx,
 5632        );
 5633
 5634        let editor_settings = EditorSettings::get_global(cx);
 5635        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5636            // After the code completion is finished, users often want to know what signatures are needed.
 5637            // so we should automatically call signature_help
 5638            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5639        }
 5640
 5641        Some(cx.foreground_executor().spawn(async move {
 5642            apply_edits.await?;
 5643            Ok(())
 5644        }))
 5645    }
 5646
 5647    pub fn toggle_code_actions(
 5648        &mut self,
 5649        action: &ToggleCodeActions,
 5650        window: &mut Window,
 5651        cx: &mut Context<Self>,
 5652    ) {
 5653        let quick_launch = action.quick_launch;
 5654        let mut context_menu = self.context_menu.borrow_mut();
 5655        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5656            if code_actions.deployed_from == action.deployed_from {
 5657                // Toggle if we're selecting the same one
 5658                *context_menu = None;
 5659                cx.notify();
 5660                return;
 5661            } else {
 5662                // Otherwise, clear it and start a new one
 5663                *context_menu = None;
 5664                cx.notify();
 5665            }
 5666        }
 5667        drop(context_menu);
 5668        let snapshot = self.snapshot(window, cx);
 5669        let deployed_from = action.deployed_from.clone();
 5670        let mut task = self.code_actions_task.take();
 5671        let action = action.clone();
 5672        cx.spawn_in(window, async move |editor, cx| {
 5673            while let Some(prev_task) = task {
 5674                prev_task.await.log_err();
 5675                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5676            }
 5677
 5678            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5679                if editor.focus_handle.is_focused(window) {
 5680                    let multibuffer_point = match &action.deployed_from {
 5681                        Some(CodeActionSource::Indicator(row)) => {
 5682                            DisplayPoint::new(*row, 0).to_point(&snapshot)
 5683                        }
 5684                        _ => editor.selections.newest::<Point>(cx).head(),
 5685                    };
 5686                    let (buffer, buffer_row) = snapshot
 5687                        .buffer_snapshot
 5688                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5689                        .and_then(|(buffer_snapshot, range)| {
 5690                            editor
 5691                                .buffer
 5692                                .read(cx)
 5693                                .buffer(buffer_snapshot.remote_id())
 5694                                .map(|buffer| (buffer, range.start.row))
 5695                        })?;
 5696                    let (_, code_actions) = editor
 5697                        .available_code_actions
 5698                        .clone()
 5699                        .and_then(|(location, code_actions)| {
 5700                            let snapshot = location.buffer.read(cx).snapshot();
 5701                            let point_range = location.range.to_point(&snapshot);
 5702                            let point_range = point_range.start.row..=point_range.end.row;
 5703                            if point_range.contains(&buffer_row) {
 5704                                Some((location, code_actions))
 5705                            } else {
 5706                                None
 5707                            }
 5708                        })
 5709                        .unzip();
 5710                    let buffer_id = buffer.read(cx).remote_id();
 5711                    let tasks = editor
 5712                        .tasks
 5713                        .get(&(buffer_id, buffer_row))
 5714                        .map(|t| Arc::new(t.to_owned()));
 5715                    if tasks.is_none() && code_actions.is_none() {
 5716                        return None;
 5717                    }
 5718
 5719                    editor.completion_tasks.clear();
 5720                    editor.discard_inline_completion(false, cx);
 5721                    let task_context =
 5722                        tasks
 5723                            .as_ref()
 5724                            .zip(editor.project.clone())
 5725                            .map(|(tasks, project)| {
 5726                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5727                            });
 5728
 5729                    Some(cx.spawn_in(window, async move |editor, cx| {
 5730                        let task_context = match task_context {
 5731                            Some(task_context) => task_context.await,
 5732                            None => None,
 5733                        };
 5734                        let resolved_tasks =
 5735                            tasks
 5736                                .zip(task_context.clone())
 5737                                .map(|(tasks, task_context)| ResolvedTasks {
 5738                                    templates: tasks.resolve(&task_context).collect(),
 5739                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5740                                        multibuffer_point.row,
 5741                                        tasks.column,
 5742                                    )),
 5743                                });
 5744                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5745                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5746                                maybe!({
 5747                                    let project = editor.project.as_ref()?;
 5748                                    let dap_store = project.read(cx).dap_store();
 5749                                    let mut scenarios = vec![];
 5750                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5751                                    let buffer = buffer.read(cx);
 5752                                    let language = buffer.language()?;
 5753                                    let file = buffer.file();
 5754                                    let debug_adapter =
 5755                                        language_settings(language.name().into(), file, cx)
 5756                                            .debuggers
 5757                                            .first()
 5758                                            .map(SharedString::from)
 5759                                            .or_else(|| {
 5760                                                language
 5761                                                    .config()
 5762                                                    .debuggers
 5763                                                    .first()
 5764                                                    .map(SharedString::from)
 5765                                            })?;
 5766
 5767                                    dap_store.update(cx, |dap_store, cx| {
 5768                                        for (_, task) in &resolved_tasks.templates {
 5769                                            if let Some(scenario) = dap_store
 5770                                                .debug_scenario_for_build_task(
 5771                                                    task.original_task().clone(),
 5772                                                    debug_adapter.clone().into(),
 5773                                                    task.display_label().to_owned().into(),
 5774                                                    cx,
 5775                                                )
 5776                                            {
 5777                                                scenarios.push(scenario);
 5778                                            }
 5779                                        }
 5780                                    });
 5781                                    Some(scenarios)
 5782                                })
 5783                                .unwrap_or_default()
 5784                            } else {
 5785                                vec![]
 5786                            }
 5787                        })?;
 5788                        let spawn_straight_away = quick_launch
 5789                            && resolved_tasks
 5790                                .as_ref()
 5791                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5792                            && code_actions
 5793                                .as_ref()
 5794                                .map_or(true, |actions| actions.is_empty())
 5795                            && debug_scenarios.is_empty();
 5796                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5797                            crate::hover_popover::hide_hover(editor, cx);
 5798                            *editor.context_menu.borrow_mut() =
 5799                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5800                                    buffer,
 5801                                    actions: CodeActionContents::new(
 5802                                        resolved_tasks,
 5803                                        code_actions,
 5804                                        debug_scenarios,
 5805                                        task_context.unwrap_or_default(),
 5806                                    ),
 5807                                    selected_item: Default::default(),
 5808                                    scroll_handle: UniformListScrollHandle::default(),
 5809                                    deployed_from,
 5810                                }));
 5811                            if spawn_straight_away {
 5812                                if let Some(task) = editor.confirm_code_action(
 5813                                    &ConfirmCodeAction { item_ix: Some(0) },
 5814                                    window,
 5815                                    cx,
 5816                                ) {
 5817                                    cx.notify();
 5818                                    return task;
 5819                                }
 5820                            }
 5821                            cx.notify();
 5822                            Task::ready(Ok(()))
 5823                        }) {
 5824                            task.await
 5825                        } else {
 5826                            Ok(())
 5827                        }
 5828                    }))
 5829                } else {
 5830                    Some(Task::ready(Ok(())))
 5831                }
 5832            })?;
 5833            if let Some(task) = spawned_test_task {
 5834                task.await?;
 5835            }
 5836
 5837            anyhow::Ok(())
 5838        })
 5839        .detach_and_log_err(cx);
 5840    }
 5841
 5842    pub fn confirm_code_action(
 5843        &mut self,
 5844        action: &ConfirmCodeAction,
 5845        window: &mut Window,
 5846        cx: &mut Context<Self>,
 5847    ) -> Option<Task<Result<()>>> {
 5848        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5849
 5850        let actions_menu =
 5851            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5852                menu
 5853            } else {
 5854                return None;
 5855            };
 5856
 5857        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5858        let action = actions_menu.actions.get(action_ix)?;
 5859        let title = action.label();
 5860        let buffer = actions_menu.buffer;
 5861        let workspace = self.workspace()?;
 5862
 5863        match action {
 5864            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5865                workspace.update(cx, |workspace, cx| {
 5866                    workspace.schedule_resolved_task(
 5867                        task_source_kind,
 5868                        resolved_task,
 5869                        false,
 5870                        window,
 5871                        cx,
 5872                    );
 5873
 5874                    Some(Task::ready(Ok(())))
 5875                })
 5876            }
 5877            CodeActionsItem::CodeAction {
 5878                excerpt_id,
 5879                action,
 5880                provider,
 5881            } => {
 5882                let apply_code_action =
 5883                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5884                let workspace = workspace.downgrade();
 5885                Some(cx.spawn_in(window, async move |editor, cx| {
 5886                    let project_transaction = apply_code_action.await?;
 5887                    Self::open_project_transaction(
 5888                        &editor,
 5889                        workspace,
 5890                        project_transaction,
 5891                        title,
 5892                        cx,
 5893                    )
 5894                    .await
 5895                }))
 5896            }
 5897            CodeActionsItem::DebugScenario(scenario) => {
 5898                let context = actions_menu.actions.context.clone();
 5899
 5900                workspace.update(cx, |workspace, cx| {
 5901                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5902                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5903                });
 5904                Some(Task::ready(Ok(())))
 5905            }
 5906        }
 5907    }
 5908
 5909    pub async fn open_project_transaction(
 5910        this: &WeakEntity<Editor>,
 5911        workspace: WeakEntity<Workspace>,
 5912        transaction: ProjectTransaction,
 5913        title: String,
 5914        cx: &mut AsyncWindowContext,
 5915    ) -> Result<()> {
 5916        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5917        cx.update(|_, cx| {
 5918            entries.sort_unstable_by_key(|(buffer, _)| {
 5919                buffer.read(cx).file().map(|f| f.path().clone())
 5920            });
 5921        })?;
 5922
 5923        // If the project transaction's edits are all contained within this editor, then
 5924        // avoid opening a new editor to display them.
 5925
 5926        if let Some((buffer, transaction)) = entries.first() {
 5927            if entries.len() == 1 {
 5928                let excerpt = this.update(cx, |editor, cx| {
 5929                    editor
 5930                        .buffer()
 5931                        .read(cx)
 5932                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5933                })?;
 5934                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5935                    if excerpted_buffer == *buffer {
 5936                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5937                            let excerpt_range = excerpt_range.to_offset(buffer);
 5938                            buffer
 5939                                .edited_ranges_for_transaction::<usize>(transaction)
 5940                                .all(|range| {
 5941                                    excerpt_range.start <= range.start
 5942                                        && excerpt_range.end >= range.end
 5943                                })
 5944                        })?;
 5945
 5946                        if all_edits_within_excerpt {
 5947                            return Ok(());
 5948                        }
 5949                    }
 5950                }
 5951            }
 5952        } else {
 5953            return Ok(());
 5954        }
 5955
 5956        let mut ranges_to_highlight = Vec::new();
 5957        let excerpt_buffer = cx.new(|cx| {
 5958            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5959            for (buffer_handle, transaction) in &entries {
 5960                let edited_ranges = buffer_handle
 5961                    .read(cx)
 5962                    .edited_ranges_for_transaction::<Point>(transaction)
 5963                    .collect::<Vec<_>>();
 5964                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5965                    PathKey::for_buffer(buffer_handle, cx),
 5966                    buffer_handle.clone(),
 5967                    edited_ranges,
 5968                    DEFAULT_MULTIBUFFER_CONTEXT,
 5969                    cx,
 5970                );
 5971
 5972                ranges_to_highlight.extend(ranges);
 5973            }
 5974            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5975            multibuffer
 5976        })?;
 5977
 5978        workspace.update_in(cx, |workspace, window, cx| {
 5979            let project = workspace.project().clone();
 5980            let editor =
 5981                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5982            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5983            editor.update(cx, |editor, cx| {
 5984                editor.highlight_background::<Self>(
 5985                    &ranges_to_highlight,
 5986                    |theme| theme.editor_highlighted_line_background,
 5987                    cx,
 5988                );
 5989            });
 5990        })?;
 5991
 5992        Ok(())
 5993    }
 5994
 5995    pub fn clear_code_action_providers(&mut self) {
 5996        self.code_action_providers.clear();
 5997        self.available_code_actions.take();
 5998    }
 5999
 6000    pub fn add_code_action_provider(
 6001        &mut self,
 6002        provider: Rc<dyn CodeActionProvider>,
 6003        window: &mut Window,
 6004        cx: &mut Context<Self>,
 6005    ) {
 6006        if self
 6007            .code_action_providers
 6008            .iter()
 6009            .any(|existing_provider| existing_provider.id() == provider.id())
 6010        {
 6011            return;
 6012        }
 6013
 6014        self.code_action_providers.push(provider);
 6015        self.refresh_code_actions(window, cx);
 6016    }
 6017
 6018    pub fn remove_code_action_provider(
 6019        &mut self,
 6020        id: Arc<str>,
 6021        window: &mut Window,
 6022        cx: &mut Context<Self>,
 6023    ) {
 6024        self.code_action_providers
 6025            .retain(|provider| provider.id() != id);
 6026        self.refresh_code_actions(window, cx);
 6027    }
 6028
 6029    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6030        !self.code_action_providers.is_empty()
 6031            && EditorSettings::get_global(cx).toolbar.code_actions
 6032    }
 6033
 6034    pub fn has_available_code_actions(&self) -> bool {
 6035        self.available_code_actions
 6036            .as_ref()
 6037            .is_some_and(|(_, actions)| !actions.is_empty())
 6038    }
 6039
 6040    fn render_inline_code_actions(
 6041        &self,
 6042        icon_size: ui::IconSize,
 6043        display_row: DisplayRow,
 6044        is_active: bool,
 6045        cx: &mut Context<Self>,
 6046    ) -> AnyElement {
 6047        let show_tooltip = !self.context_menu_visible();
 6048        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6049            .icon_size(icon_size)
 6050            .shape(ui::IconButtonShape::Square)
 6051            .style(ButtonStyle::Transparent)
 6052            .icon_color(ui::Color::Hidden)
 6053            .toggle_state(is_active)
 6054            .when(show_tooltip, |this| {
 6055                this.tooltip({
 6056                    let focus_handle = self.focus_handle.clone();
 6057                    move |window, cx| {
 6058                        Tooltip::for_action_in(
 6059                            "Toggle Code Actions",
 6060                            &ToggleCodeActions {
 6061                                deployed_from: None,
 6062                                quick_launch: false,
 6063                            },
 6064                            &focus_handle,
 6065                            window,
 6066                            cx,
 6067                        )
 6068                    }
 6069                })
 6070            })
 6071            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6072                window.focus(&editor.focus_handle(cx));
 6073                editor.toggle_code_actions(
 6074                    &crate::actions::ToggleCodeActions {
 6075                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6076                            display_row,
 6077                        )),
 6078                        quick_launch: false,
 6079                    },
 6080                    window,
 6081                    cx,
 6082                );
 6083            }))
 6084            .into_any_element()
 6085    }
 6086
 6087    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6088        &self.context_menu
 6089    }
 6090
 6091    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6092        let newest_selection = self.selections.newest_anchor().clone();
 6093        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6094        let buffer = self.buffer.read(cx);
 6095        if newest_selection.head().diff_base_anchor.is_some() {
 6096            return None;
 6097        }
 6098        let (start_buffer, start) =
 6099            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6100        let (end_buffer, end) =
 6101            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6102        if start_buffer != end_buffer {
 6103            return None;
 6104        }
 6105
 6106        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6107            cx.background_executor()
 6108                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6109                .await;
 6110
 6111            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6112                let providers = this.code_action_providers.clone();
 6113                let tasks = this
 6114                    .code_action_providers
 6115                    .iter()
 6116                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6117                    .collect::<Vec<_>>();
 6118                (providers, tasks)
 6119            })?;
 6120
 6121            let mut actions = Vec::new();
 6122            for (provider, provider_actions) in
 6123                providers.into_iter().zip(future::join_all(tasks).await)
 6124            {
 6125                if let Some(provider_actions) = provider_actions.log_err() {
 6126                    actions.extend(provider_actions.into_iter().map(|action| {
 6127                        AvailableCodeAction {
 6128                            excerpt_id: newest_selection.start.excerpt_id,
 6129                            action,
 6130                            provider: provider.clone(),
 6131                        }
 6132                    }));
 6133                }
 6134            }
 6135
 6136            this.update(cx, |this, cx| {
 6137                this.available_code_actions = if actions.is_empty() {
 6138                    None
 6139                } else {
 6140                    Some((
 6141                        Location {
 6142                            buffer: start_buffer,
 6143                            range: start..end,
 6144                        },
 6145                        actions.into(),
 6146                    ))
 6147                };
 6148                cx.notify();
 6149            })
 6150        }));
 6151        None
 6152    }
 6153
 6154    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6155        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6156            self.show_git_blame_inline = false;
 6157
 6158            self.show_git_blame_inline_delay_task =
 6159                Some(cx.spawn_in(window, async move |this, cx| {
 6160                    cx.background_executor().timer(delay).await;
 6161
 6162                    this.update(cx, |this, cx| {
 6163                        this.show_git_blame_inline = true;
 6164                        cx.notify();
 6165                    })
 6166                    .log_err();
 6167                }));
 6168        }
 6169    }
 6170
 6171    fn show_blame_popover(
 6172        &mut self,
 6173        blame_entry: &BlameEntry,
 6174        position: gpui::Point<Pixels>,
 6175        cx: &mut Context<Self>,
 6176    ) {
 6177        if let Some(state) = &mut self.inline_blame_popover {
 6178            state.hide_task.take();
 6179            cx.notify();
 6180        } else {
 6181            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6182            let show_task = cx.spawn(async move |editor, cx| {
 6183                cx.background_executor()
 6184                    .timer(std::time::Duration::from_millis(delay))
 6185                    .await;
 6186                editor
 6187                    .update(cx, |editor, cx| {
 6188                        if let Some(state) = &mut editor.inline_blame_popover {
 6189                            state.show_task = None;
 6190                            cx.notify();
 6191                        }
 6192                    })
 6193                    .ok();
 6194            });
 6195            let Some(blame) = self.blame.as_ref() else {
 6196                return;
 6197            };
 6198            let blame = blame.read(cx);
 6199            let details = blame.details_for_entry(&blame_entry);
 6200            let markdown = cx.new(|cx| {
 6201                Markdown::new(
 6202                    details
 6203                        .as_ref()
 6204                        .map(|message| message.message.clone())
 6205                        .unwrap_or_default(),
 6206                    None,
 6207                    None,
 6208                    cx,
 6209                )
 6210            });
 6211            self.inline_blame_popover = Some(InlineBlamePopover {
 6212                position,
 6213                show_task: Some(show_task),
 6214                hide_task: None,
 6215                popover_bounds: None,
 6216                popover_state: InlineBlamePopoverState {
 6217                    scroll_handle: ScrollHandle::new(),
 6218                    commit_message: details,
 6219                    markdown,
 6220                },
 6221            });
 6222        }
 6223    }
 6224
 6225    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6226        if let Some(state) = &mut self.inline_blame_popover {
 6227            if state.show_task.is_some() {
 6228                self.inline_blame_popover.take();
 6229                cx.notify();
 6230            } else {
 6231                let hide_task = cx.spawn(async move |editor, cx| {
 6232                    cx.background_executor()
 6233                        .timer(std::time::Duration::from_millis(100))
 6234                        .await;
 6235                    editor
 6236                        .update(cx, |editor, cx| {
 6237                            editor.inline_blame_popover.take();
 6238                            cx.notify();
 6239                        })
 6240                        .ok();
 6241                });
 6242                state.hide_task = Some(hide_task);
 6243            }
 6244        }
 6245    }
 6246
 6247    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6248        if self.pending_rename.is_some() {
 6249            return None;
 6250        }
 6251
 6252        let provider = self.semantics_provider.clone()?;
 6253        let buffer = self.buffer.read(cx);
 6254        let newest_selection = self.selections.newest_anchor().clone();
 6255        let cursor_position = newest_selection.head();
 6256        let (cursor_buffer, cursor_buffer_position) =
 6257            buffer.text_anchor_for_position(cursor_position, cx)?;
 6258        let (tail_buffer, tail_buffer_position) =
 6259            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6260        if cursor_buffer != tail_buffer {
 6261            return None;
 6262        }
 6263
 6264        let snapshot = cursor_buffer.read(cx).snapshot();
 6265        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6266        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6267        if start_word_range != end_word_range {
 6268            self.document_highlights_task.take();
 6269            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6270            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6271            return None;
 6272        }
 6273
 6274        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6275        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6276            cx.background_executor()
 6277                .timer(Duration::from_millis(debounce))
 6278                .await;
 6279
 6280            let highlights = if let Some(highlights) = cx
 6281                .update(|cx| {
 6282                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6283                })
 6284                .ok()
 6285                .flatten()
 6286            {
 6287                highlights.await.log_err()
 6288            } else {
 6289                None
 6290            };
 6291
 6292            if let Some(highlights) = highlights {
 6293                this.update(cx, |this, cx| {
 6294                    if this.pending_rename.is_some() {
 6295                        return;
 6296                    }
 6297
 6298                    let buffer_id = cursor_position.buffer_id;
 6299                    let buffer = this.buffer.read(cx);
 6300                    if !buffer
 6301                        .text_anchor_for_position(cursor_position, cx)
 6302                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6303                    {
 6304                        return;
 6305                    }
 6306
 6307                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6308                    let mut write_ranges = Vec::new();
 6309                    let mut read_ranges = Vec::new();
 6310                    for highlight in highlights {
 6311                        for (excerpt_id, excerpt_range) in
 6312                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6313                        {
 6314                            let start = highlight
 6315                                .range
 6316                                .start
 6317                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6318                            let end = highlight
 6319                                .range
 6320                                .end
 6321                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6322                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6323                                continue;
 6324                            }
 6325
 6326                            let range = Anchor {
 6327                                buffer_id,
 6328                                excerpt_id,
 6329                                text_anchor: start,
 6330                                diff_base_anchor: None,
 6331                            }..Anchor {
 6332                                buffer_id,
 6333                                excerpt_id,
 6334                                text_anchor: end,
 6335                                diff_base_anchor: None,
 6336                            };
 6337                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6338                                write_ranges.push(range);
 6339                            } else {
 6340                                read_ranges.push(range);
 6341                            }
 6342                        }
 6343                    }
 6344
 6345                    this.highlight_background::<DocumentHighlightRead>(
 6346                        &read_ranges,
 6347                        |theme| theme.editor_document_highlight_read_background,
 6348                        cx,
 6349                    );
 6350                    this.highlight_background::<DocumentHighlightWrite>(
 6351                        &write_ranges,
 6352                        |theme| theme.editor_document_highlight_write_background,
 6353                        cx,
 6354                    );
 6355                    cx.notify();
 6356                })
 6357                .log_err();
 6358            }
 6359        }));
 6360        None
 6361    }
 6362
 6363    fn prepare_highlight_query_from_selection(
 6364        &mut self,
 6365        cx: &mut Context<Editor>,
 6366    ) -> Option<(String, Range<Anchor>)> {
 6367        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6368            return None;
 6369        }
 6370        if !EditorSettings::get_global(cx).selection_highlight {
 6371            return None;
 6372        }
 6373        if self.selections.count() != 1 || self.selections.line_mode {
 6374            return None;
 6375        }
 6376        let selection = self.selections.newest::<Point>(cx);
 6377        if selection.is_empty() || selection.start.row != selection.end.row {
 6378            return None;
 6379        }
 6380        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6381        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6382        let query = multi_buffer_snapshot
 6383            .text_for_range(selection_anchor_range.clone())
 6384            .collect::<String>();
 6385        if query.trim().is_empty() {
 6386            return None;
 6387        }
 6388        Some((query, selection_anchor_range))
 6389    }
 6390
 6391    fn update_selection_occurrence_highlights(
 6392        &mut self,
 6393        query_text: String,
 6394        query_range: Range<Anchor>,
 6395        multi_buffer_range_to_query: Range<Point>,
 6396        use_debounce: bool,
 6397        window: &mut Window,
 6398        cx: &mut Context<Editor>,
 6399    ) -> Task<()> {
 6400        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6401        cx.spawn_in(window, async move |editor, cx| {
 6402            if use_debounce {
 6403                cx.background_executor()
 6404                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6405                    .await;
 6406            }
 6407            let match_task = cx.background_spawn(async move {
 6408                let buffer_ranges = multi_buffer_snapshot
 6409                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6410                    .into_iter()
 6411                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6412                let mut match_ranges = Vec::new();
 6413                let Ok(regex) = project::search::SearchQuery::text(
 6414                    query_text.clone(),
 6415                    false,
 6416                    false,
 6417                    false,
 6418                    Default::default(),
 6419                    Default::default(),
 6420                    false,
 6421                    None,
 6422                ) else {
 6423                    return Vec::default();
 6424                };
 6425                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6426                    match_ranges.extend(
 6427                        regex
 6428                            .search(&buffer_snapshot, Some(search_range.clone()))
 6429                            .await
 6430                            .into_iter()
 6431                            .filter_map(|match_range| {
 6432                                let match_start = buffer_snapshot
 6433                                    .anchor_after(search_range.start + match_range.start);
 6434                                let match_end = buffer_snapshot
 6435                                    .anchor_before(search_range.start + match_range.end);
 6436                                let match_anchor_range = Anchor::range_in_buffer(
 6437                                    excerpt_id,
 6438                                    buffer_snapshot.remote_id(),
 6439                                    match_start..match_end,
 6440                                );
 6441                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6442                            }),
 6443                    );
 6444                }
 6445                match_ranges
 6446            });
 6447            let match_ranges = match_task.await;
 6448            editor
 6449                .update_in(cx, |editor, _, cx| {
 6450                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6451                    if !match_ranges.is_empty() {
 6452                        editor.highlight_background::<SelectedTextHighlight>(
 6453                            &match_ranges,
 6454                            |theme| theme.editor_document_highlight_bracket_background,
 6455                            cx,
 6456                        )
 6457                    }
 6458                })
 6459                .log_err();
 6460        })
 6461    }
 6462
 6463    fn refresh_selected_text_highlights(
 6464        &mut self,
 6465        on_buffer_edit: bool,
 6466        window: &mut Window,
 6467        cx: &mut Context<Editor>,
 6468    ) {
 6469        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6470        else {
 6471            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6472            self.quick_selection_highlight_task.take();
 6473            self.debounced_selection_highlight_task.take();
 6474            return;
 6475        };
 6476        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6477        if on_buffer_edit
 6478            || self
 6479                .quick_selection_highlight_task
 6480                .as_ref()
 6481                .map_or(true, |(prev_anchor_range, _)| {
 6482                    prev_anchor_range != &query_range
 6483                })
 6484        {
 6485            let multi_buffer_visible_start = self
 6486                .scroll_manager
 6487                .anchor()
 6488                .anchor
 6489                .to_point(&multi_buffer_snapshot);
 6490            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6491                multi_buffer_visible_start
 6492                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6493                Bias::Left,
 6494            );
 6495            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6496            self.quick_selection_highlight_task = Some((
 6497                query_range.clone(),
 6498                self.update_selection_occurrence_highlights(
 6499                    query_text.clone(),
 6500                    query_range.clone(),
 6501                    multi_buffer_visible_range,
 6502                    false,
 6503                    window,
 6504                    cx,
 6505                ),
 6506            ));
 6507        }
 6508        if on_buffer_edit
 6509            || self
 6510                .debounced_selection_highlight_task
 6511                .as_ref()
 6512                .map_or(true, |(prev_anchor_range, _)| {
 6513                    prev_anchor_range != &query_range
 6514                })
 6515        {
 6516            let multi_buffer_start = multi_buffer_snapshot
 6517                .anchor_before(0)
 6518                .to_point(&multi_buffer_snapshot);
 6519            let multi_buffer_end = multi_buffer_snapshot
 6520                .anchor_after(multi_buffer_snapshot.len())
 6521                .to_point(&multi_buffer_snapshot);
 6522            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6523            self.debounced_selection_highlight_task = Some((
 6524                query_range.clone(),
 6525                self.update_selection_occurrence_highlights(
 6526                    query_text,
 6527                    query_range,
 6528                    multi_buffer_full_range,
 6529                    true,
 6530                    window,
 6531                    cx,
 6532                ),
 6533            ));
 6534        }
 6535    }
 6536
 6537    pub fn refresh_inline_completion(
 6538        &mut self,
 6539        debounce: bool,
 6540        user_requested: bool,
 6541        window: &mut Window,
 6542        cx: &mut Context<Self>,
 6543    ) -> Option<()> {
 6544        let provider = self.edit_prediction_provider()?;
 6545        let cursor = self.selections.newest_anchor().head();
 6546        let (buffer, cursor_buffer_position) =
 6547            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6548
 6549        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6550            self.discard_inline_completion(false, cx);
 6551            return None;
 6552        }
 6553
 6554        if !user_requested
 6555            && (!self.should_show_edit_predictions()
 6556                || !self.is_focused(window)
 6557                || buffer.read(cx).is_empty())
 6558        {
 6559            self.discard_inline_completion(false, cx);
 6560            return None;
 6561        }
 6562
 6563        self.update_visible_inline_completion(window, cx);
 6564        provider.refresh(
 6565            self.project.clone(),
 6566            buffer,
 6567            cursor_buffer_position,
 6568            debounce,
 6569            cx,
 6570        );
 6571        Some(())
 6572    }
 6573
 6574    fn show_edit_predictions_in_menu(&self) -> bool {
 6575        match self.edit_prediction_settings {
 6576            EditPredictionSettings::Disabled => false,
 6577            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6578        }
 6579    }
 6580
 6581    pub fn edit_predictions_enabled(&self) -> bool {
 6582        match self.edit_prediction_settings {
 6583            EditPredictionSettings::Disabled => false,
 6584            EditPredictionSettings::Enabled { .. } => true,
 6585        }
 6586    }
 6587
 6588    fn edit_prediction_requires_modifier(&self) -> bool {
 6589        match self.edit_prediction_settings {
 6590            EditPredictionSettings::Disabled => false,
 6591            EditPredictionSettings::Enabled {
 6592                preview_requires_modifier,
 6593                ..
 6594            } => preview_requires_modifier,
 6595        }
 6596    }
 6597
 6598    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6599        if self.edit_prediction_provider.is_none() {
 6600            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6601        } else {
 6602            let selection = self.selections.newest_anchor();
 6603            let cursor = selection.head();
 6604
 6605            if let Some((buffer, cursor_buffer_position)) =
 6606                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6607            {
 6608                self.edit_prediction_settings =
 6609                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6610            }
 6611        }
 6612    }
 6613
 6614    fn edit_prediction_settings_at_position(
 6615        &self,
 6616        buffer: &Entity<Buffer>,
 6617        buffer_position: language::Anchor,
 6618        cx: &App,
 6619    ) -> EditPredictionSettings {
 6620        if !self.mode.is_full()
 6621            || !self.show_inline_completions_override.unwrap_or(true)
 6622            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6623        {
 6624            return EditPredictionSettings::Disabled;
 6625        }
 6626
 6627        let buffer = buffer.read(cx);
 6628
 6629        let file = buffer.file();
 6630
 6631        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6632            return EditPredictionSettings::Disabled;
 6633        };
 6634
 6635        let by_provider = matches!(
 6636            self.menu_inline_completions_policy,
 6637            MenuInlineCompletionsPolicy::ByProvider
 6638        );
 6639
 6640        let show_in_menu = by_provider
 6641            && self
 6642                .edit_prediction_provider
 6643                .as_ref()
 6644                .map_or(false, |provider| {
 6645                    provider.provider.show_completions_in_menu()
 6646                });
 6647
 6648        let preview_requires_modifier =
 6649            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6650
 6651        EditPredictionSettings::Enabled {
 6652            show_in_menu,
 6653            preview_requires_modifier,
 6654        }
 6655    }
 6656
 6657    fn should_show_edit_predictions(&self) -> bool {
 6658        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6659    }
 6660
 6661    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6662        matches!(
 6663            self.edit_prediction_preview,
 6664            EditPredictionPreview::Active { .. }
 6665        )
 6666    }
 6667
 6668    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6669        let cursor = self.selections.newest_anchor().head();
 6670        if let Some((buffer, cursor_position)) =
 6671            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6672        {
 6673            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6674        } else {
 6675            false
 6676        }
 6677    }
 6678
 6679    pub fn supports_minimap(&self, cx: &App) -> bool {
 6680        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6681    }
 6682
 6683    fn edit_predictions_enabled_in_buffer(
 6684        &self,
 6685        buffer: &Entity<Buffer>,
 6686        buffer_position: language::Anchor,
 6687        cx: &App,
 6688    ) -> bool {
 6689        maybe!({
 6690            if self.read_only(cx) {
 6691                return Some(false);
 6692            }
 6693            let provider = self.edit_prediction_provider()?;
 6694            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6695                return Some(false);
 6696            }
 6697            let buffer = buffer.read(cx);
 6698            let Some(file) = buffer.file() else {
 6699                return Some(true);
 6700            };
 6701            let settings = all_language_settings(Some(file), cx);
 6702            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6703        })
 6704        .unwrap_or(false)
 6705    }
 6706
 6707    fn cycle_inline_completion(
 6708        &mut self,
 6709        direction: Direction,
 6710        window: &mut Window,
 6711        cx: &mut Context<Self>,
 6712    ) -> Option<()> {
 6713        let provider = self.edit_prediction_provider()?;
 6714        let cursor = self.selections.newest_anchor().head();
 6715        let (buffer, cursor_buffer_position) =
 6716            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6717        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6718            return None;
 6719        }
 6720
 6721        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6722        self.update_visible_inline_completion(window, cx);
 6723
 6724        Some(())
 6725    }
 6726
 6727    pub fn show_inline_completion(
 6728        &mut self,
 6729        _: &ShowEditPrediction,
 6730        window: &mut Window,
 6731        cx: &mut Context<Self>,
 6732    ) {
 6733        if !self.has_active_inline_completion() {
 6734            self.refresh_inline_completion(false, true, window, cx);
 6735            return;
 6736        }
 6737
 6738        self.update_visible_inline_completion(window, cx);
 6739    }
 6740
 6741    pub fn display_cursor_names(
 6742        &mut self,
 6743        _: &DisplayCursorNames,
 6744        window: &mut Window,
 6745        cx: &mut Context<Self>,
 6746    ) {
 6747        self.show_cursor_names(window, cx);
 6748    }
 6749
 6750    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6751        self.show_cursor_names = true;
 6752        cx.notify();
 6753        cx.spawn_in(window, async move |this, cx| {
 6754            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6755            this.update(cx, |this, cx| {
 6756                this.show_cursor_names = false;
 6757                cx.notify()
 6758            })
 6759            .ok()
 6760        })
 6761        .detach();
 6762    }
 6763
 6764    pub fn next_edit_prediction(
 6765        &mut self,
 6766        _: &NextEditPrediction,
 6767        window: &mut Window,
 6768        cx: &mut Context<Self>,
 6769    ) {
 6770        if self.has_active_inline_completion() {
 6771            self.cycle_inline_completion(Direction::Next, window, cx);
 6772        } else {
 6773            let is_copilot_disabled = self
 6774                .refresh_inline_completion(false, true, window, cx)
 6775                .is_none();
 6776            if is_copilot_disabled {
 6777                cx.propagate();
 6778            }
 6779        }
 6780    }
 6781
 6782    pub fn previous_edit_prediction(
 6783        &mut self,
 6784        _: &PreviousEditPrediction,
 6785        window: &mut Window,
 6786        cx: &mut Context<Self>,
 6787    ) {
 6788        if self.has_active_inline_completion() {
 6789            self.cycle_inline_completion(Direction::Prev, window, cx);
 6790        } else {
 6791            let is_copilot_disabled = self
 6792                .refresh_inline_completion(false, true, window, cx)
 6793                .is_none();
 6794            if is_copilot_disabled {
 6795                cx.propagate();
 6796            }
 6797        }
 6798    }
 6799
 6800    pub fn accept_edit_prediction(
 6801        &mut self,
 6802        _: &AcceptEditPrediction,
 6803        window: &mut Window,
 6804        cx: &mut Context<Self>,
 6805    ) {
 6806        if self.show_edit_predictions_in_menu() {
 6807            self.hide_context_menu(window, cx);
 6808        }
 6809
 6810        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6811            return;
 6812        };
 6813
 6814        self.report_inline_completion_event(
 6815            active_inline_completion.completion_id.clone(),
 6816            true,
 6817            cx,
 6818        );
 6819
 6820        match &active_inline_completion.completion {
 6821            InlineCompletion::Move { target, .. } => {
 6822                let target = *target;
 6823
 6824                if let Some(position_map) = &self.last_position_map {
 6825                    if position_map
 6826                        .visible_row_range
 6827                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6828                        || !self.edit_prediction_requires_modifier()
 6829                    {
 6830                        self.unfold_ranges(&[target..target], true, false, cx);
 6831                        // Note that this is also done in vim's handler of the Tab action.
 6832                        self.change_selections(
 6833                            Some(Autoscroll::newest()),
 6834                            window,
 6835                            cx,
 6836                            |selections| {
 6837                                selections.select_anchor_ranges([target..target]);
 6838                            },
 6839                        );
 6840                        self.clear_row_highlights::<EditPredictionPreview>();
 6841
 6842                        self.edit_prediction_preview
 6843                            .set_previous_scroll_position(None);
 6844                    } else {
 6845                        self.edit_prediction_preview
 6846                            .set_previous_scroll_position(Some(
 6847                                position_map.snapshot.scroll_anchor,
 6848                            ));
 6849
 6850                        self.highlight_rows::<EditPredictionPreview>(
 6851                            target..target,
 6852                            cx.theme().colors().editor_highlighted_line_background,
 6853                            RowHighlightOptions {
 6854                                autoscroll: true,
 6855                                ..Default::default()
 6856                            },
 6857                            cx,
 6858                        );
 6859                        self.request_autoscroll(Autoscroll::fit(), cx);
 6860                    }
 6861                }
 6862            }
 6863            InlineCompletion::Edit { edits, .. } => {
 6864                if let Some(provider) = self.edit_prediction_provider() {
 6865                    provider.accept(cx);
 6866                }
 6867
 6868                // Store the transaction ID and selections before applying the edit
 6869                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 6870
 6871                let snapshot = self.buffer.read(cx).snapshot(cx);
 6872                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6873
 6874                self.buffer.update(cx, |buffer, cx| {
 6875                    buffer.edit(edits.iter().cloned(), None, cx)
 6876                });
 6877
 6878                self.change_selections(None, window, cx, |s| {
 6879                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6880                });
 6881
 6882                let selections = self.selections.disjoint_anchors();
 6883                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 6884                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6885                    if has_new_transaction {
 6886                        self.selection_history
 6887                            .insert_transaction(transaction_id_now, selections);
 6888                    }
 6889                }
 6890
 6891                self.update_visible_inline_completion(window, cx);
 6892                if self.active_inline_completion.is_none() {
 6893                    self.refresh_inline_completion(true, true, window, cx);
 6894                }
 6895
 6896                cx.notify();
 6897            }
 6898        }
 6899
 6900        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6901    }
 6902
 6903    pub fn accept_partial_inline_completion(
 6904        &mut self,
 6905        _: &AcceptPartialEditPrediction,
 6906        window: &mut Window,
 6907        cx: &mut Context<Self>,
 6908    ) {
 6909        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6910            return;
 6911        };
 6912        if self.selections.count() != 1 {
 6913            return;
 6914        }
 6915
 6916        self.report_inline_completion_event(
 6917            active_inline_completion.completion_id.clone(),
 6918            true,
 6919            cx,
 6920        );
 6921
 6922        match &active_inline_completion.completion {
 6923            InlineCompletion::Move { target, .. } => {
 6924                let target = *target;
 6925                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6926                    selections.select_anchor_ranges([target..target]);
 6927                });
 6928            }
 6929            InlineCompletion::Edit { edits, .. } => {
 6930                // Find an insertion that starts at the cursor position.
 6931                let snapshot = self.buffer.read(cx).snapshot(cx);
 6932                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6933                let insertion = edits.iter().find_map(|(range, text)| {
 6934                    let range = range.to_offset(&snapshot);
 6935                    if range.is_empty() && range.start == cursor_offset {
 6936                        Some(text)
 6937                    } else {
 6938                        None
 6939                    }
 6940                });
 6941
 6942                if let Some(text) = insertion {
 6943                    let mut partial_completion = text
 6944                        .chars()
 6945                        .by_ref()
 6946                        .take_while(|c| c.is_alphabetic())
 6947                        .collect::<String>();
 6948                    if partial_completion.is_empty() {
 6949                        partial_completion = text
 6950                            .chars()
 6951                            .by_ref()
 6952                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6953                            .collect::<String>();
 6954                    }
 6955
 6956                    cx.emit(EditorEvent::InputHandled {
 6957                        utf16_range_to_replace: None,
 6958                        text: partial_completion.clone().into(),
 6959                    });
 6960
 6961                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6962
 6963                    self.refresh_inline_completion(true, true, window, cx);
 6964                    cx.notify();
 6965                } else {
 6966                    self.accept_edit_prediction(&Default::default(), window, cx);
 6967                }
 6968            }
 6969        }
 6970    }
 6971
 6972    fn discard_inline_completion(
 6973        &mut self,
 6974        should_report_inline_completion_event: bool,
 6975        cx: &mut Context<Self>,
 6976    ) -> bool {
 6977        if should_report_inline_completion_event {
 6978            let completion_id = self
 6979                .active_inline_completion
 6980                .as_ref()
 6981                .and_then(|active_completion| active_completion.completion_id.clone());
 6982
 6983            self.report_inline_completion_event(completion_id, false, cx);
 6984        }
 6985
 6986        if let Some(provider) = self.edit_prediction_provider() {
 6987            provider.discard(cx);
 6988        }
 6989
 6990        self.take_active_inline_completion(cx)
 6991    }
 6992
 6993    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6994        let Some(provider) = self.edit_prediction_provider() else {
 6995            return;
 6996        };
 6997
 6998        let Some((_, buffer, _)) = self
 6999            .buffer
 7000            .read(cx)
 7001            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7002        else {
 7003            return;
 7004        };
 7005
 7006        let extension = buffer
 7007            .read(cx)
 7008            .file()
 7009            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7010
 7011        let event_type = match accepted {
 7012            true => "Edit Prediction Accepted",
 7013            false => "Edit Prediction Discarded",
 7014        };
 7015        telemetry::event!(
 7016            event_type,
 7017            provider = provider.name(),
 7018            prediction_id = id,
 7019            suggestion_accepted = accepted,
 7020            file_extension = extension,
 7021        );
 7022    }
 7023
 7024    pub fn has_active_inline_completion(&self) -> bool {
 7025        self.active_inline_completion.is_some()
 7026    }
 7027
 7028    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7029        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7030            return false;
 7031        };
 7032
 7033        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7034        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7035        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7036        true
 7037    }
 7038
 7039    /// Returns true when we're displaying the edit prediction popover below the cursor
 7040    /// like we are not previewing and the LSP autocomplete menu is visible
 7041    /// or we are in `when_holding_modifier` mode.
 7042    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7043        if self.edit_prediction_preview_is_active()
 7044            || !self.show_edit_predictions_in_menu()
 7045            || !self.edit_predictions_enabled()
 7046        {
 7047            return false;
 7048        }
 7049
 7050        if self.has_visible_completions_menu() {
 7051            return true;
 7052        }
 7053
 7054        has_completion && self.edit_prediction_requires_modifier()
 7055    }
 7056
 7057    fn handle_modifiers_changed(
 7058        &mut self,
 7059        modifiers: Modifiers,
 7060        position_map: &PositionMap,
 7061        window: &mut Window,
 7062        cx: &mut Context<Self>,
 7063    ) {
 7064        if self.show_edit_predictions_in_menu() {
 7065            self.update_edit_prediction_preview(&modifiers, window, cx);
 7066        }
 7067
 7068        self.update_selection_mode(&modifiers, position_map, window, cx);
 7069
 7070        let mouse_position = window.mouse_position();
 7071        if !position_map.text_hitbox.is_hovered(window) {
 7072            return;
 7073        }
 7074
 7075        self.update_hovered_link(
 7076            position_map.point_for_position(mouse_position),
 7077            &position_map.snapshot,
 7078            modifiers,
 7079            window,
 7080            cx,
 7081        )
 7082    }
 7083
 7084    fn update_selection_mode(
 7085        &mut self,
 7086        modifiers: &Modifiers,
 7087        position_map: &PositionMap,
 7088        window: &mut Window,
 7089        cx: &mut Context<Self>,
 7090    ) {
 7091        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 7092            return;
 7093        }
 7094
 7095        let mouse_position = window.mouse_position();
 7096        let point_for_position = position_map.point_for_position(mouse_position);
 7097        let position = point_for_position.previous_valid;
 7098
 7099        self.select(
 7100            SelectPhase::BeginColumnar {
 7101                position,
 7102                reset: false,
 7103                goal_column: point_for_position.exact_unclipped.column(),
 7104            },
 7105            window,
 7106            cx,
 7107        );
 7108    }
 7109
 7110    fn update_edit_prediction_preview(
 7111        &mut self,
 7112        modifiers: &Modifiers,
 7113        window: &mut Window,
 7114        cx: &mut Context<Self>,
 7115    ) {
 7116        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 7117        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 7118            return;
 7119        };
 7120
 7121        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 7122            if matches!(
 7123                self.edit_prediction_preview,
 7124                EditPredictionPreview::Inactive { .. }
 7125            ) {
 7126                self.edit_prediction_preview = EditPredictionPreview::Active {
 7127                    previous_scroll_position: None,
 7128                    since: Instant::now(),
 7129                };
 7130
 7131                self.update_visible_inline_completion(window, cx);
 7132                cx.notify();
 7133            }
 7134        } else if let EditPredictionPreview::Active {
 7135            previous_scroll_position,
 7136            since,
 7137        } = self.edit_prediction_preview
 7138        {
 7139            if let (Some(previous_scroll_position), Some(position_map)) =
 7140                (previous_scroll_position, self.last_position_map.as_ref())
 7141            {
 7142                self.set_scroll_position(
 7143                    previous_scroll_position
 7144                        .scroll_position(&position_map.snapshot.display_snapshot),
 7145                    window,
 7146                    cx,
 7147                );
 7148            }
 7149
 7150            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7151                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7152            };
 7153            self.clear_row_highlights::<EditPredictionPreview>();
 7154            self.update_visible_inline_completion(window, cx);
 7155            cx.notify();
 7156        }
 7157    }
 7158
 7159    fn update_visible_inline_completion(
 7160        &mut self,
 7161        _window: &mut Window,
 7162        cx: &mut Context<Self>,
 7163    ) -> Option<()> {
 7164        let selection = self.selections.newest_anchor();
 7165        let cursor = selection.head();
 7166        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7167        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7168        let excerpt_id = cursor.excerpt_id;
 7169
 7170        let show_in_menu = self.show_edit_predictions_in_menu();
 7171        let completions_menu_has_precedence = !show_in_menu
 7172            && (self.context_menu.borrow().is_some()
 7173                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7174
 7175        if completions_menu_has_precedence
 7176            || !offset_selection.is_empty()
 7177            || self
 7178                .active_inline_completion
 7179                .as_ref()
 7180                .map_or(false, |completion| {
 7181                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7182                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7183                    !invalidation_range.contains(&offset_selection.head())
 7184                })
 7185        {
 7186            self.discard_inline_completion(false, cx);
 7187            return None;
 7188        }
 7189
 7190        self.take_active_inline_completion(cx);
 7191        let Some(provider) = self.edit_prediction_provider() else {
 7192            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7193            return None;
 7194        };
 7195
 7196        let (buffer, cursor_buffer_position) =
 7197            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7198
 7199        self.edit_prediction_settings =
 7200            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7201
 7202        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7203
 7204        if self.edit_prediction_indent_conflict {
 7205            let cursor_point = cursor.to_point(&multibuffer);
 7206
 7207            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7208
 7209            if let Some((_, indent)) = indents.iter().next() {
 7210                if indent.len == cursor_point.column {
 7211                    self.edit_prediction_indent_conflict = false;
 7212                }
 7213            }
 7214        }
 7215
 7216        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7217        let edits = inline_completion
 7218            .edits
 7219            .into_iter()
 7220            .flat_map(|(range, new_text)| {
 7221                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7222                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7223                Some((start..end, new_text))
 7224            })
 7225            .collect::<Vec<_>>();
 7226        if edits.is_empty() {
 7227            return None;
 7228        }
 7229
 7230        let first_edit_start = edits.first().unwrap().0.start;
 7231        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7232        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7233
 7234        let last_edit_end = edits.last().unwrap().0.end;
 7235        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7236        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7237
 7238        let cursor_row = cursor.to_point(&multibuffer).row;
 7239
 7240        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7241
 7242        let mut inlay_ids = Vec::new();
 7243        let invalidation_row_range;
 7244        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7245            Some(cursor_row..edit_end_row)
 7246        } else if cursor_row > edit_end_row {
 7247            Some(edit_start_row..cursor_row)
 7248        } else {
 7249            None
 7250        };
 7251        let is_move =
 7252            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7253        let completion = if is_move {
 7254            invalidation_row_range =
 7255                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7256            let target = first_edit_start;
 7257            InlineCompletion::Move { target, snapshot }
 7258        } else {
 7259            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7260                && !self.inline_completions_hidden_for_vim_mode;
 7261
 7262            if show_completions_in_buffer {
 7263                if edits
 7264                    .iter()
 7265                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7266                {
 7267                    let mut inlays = Vec::new();
 7268                    for (range, new_text) in &edits {
 7269                        let inlay = Inlay::inline_completion(
 7270                            post_inc(&mut self.next_inlay_id),
 7271                            range.start,
 7272                            new_text.as_str(),
 7273                        );
 7274                        inlay_ids.push(inlay.id);
 7275                        inlays.push(inlay);
 7276                    }
 7277
 7278                    self.splice_inlays(&[], inlays, cx);
 7279                } else {
 7280                    let background_color = cx.theme().status().deleted_background;
 7281                    self.highlight_text::<InlineCompletionHighlight>(
 7282                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7283                        HighlightStyle {
 7284                            background_color: Some(background_color),
 7285                            ..Default::default()
 7286                        },
 7287                        cx,
 7288                    );
 7289                }
 7290            }
 7291
 7292            invalidation_row_range = edit_start_row..edit_end_row;
 7293
 7294            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7295                if provider.show_tab_accept_marker() {
 7296                    EditDisplayMode::TabAccept
 7297                } else {
 7298                    EditDisplayMode::Inline
 7299                }
 7300            } else {
 7301                EditDisplayMode::DiffPopover
 7302            };
 7303
 7304            InlineCompletion::Edit {
 7305                edits,
 7306                edit_preview: inline_completion.edit_preview,
 7307                display_mode,
 7308                snapshot,
 7309            }
 7310        };
 7311
 7312        let invalidation_range = multibuffer
 7313            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7314            ..multibuffer.anchor_after(Point::new(
 7315                invalidation_row_range.end,
 7316                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7317            ));
 7318
 7319        self.stale_inline_completion_in_menu = None;
 7320        self.active_inline_completion = Some(InlineCompletionState {
 7321            inlay_ids,
 7322            completion,
 7323            completion_id: inline_completion.id,
 7324            invalidation_range,
 7325        });
 7326
 7327        cx.notify();
 7328
 7329        Some(())
 7330    }
 7331
 7332    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7333        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7334    }
 7335
 7336    fn clear_tasks(&mut self) {
 7337        self.tasks.clear()
 7338    }
 7339
 7340    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7341        if self.tasks.insert(key, value).is_some() {
 7342            // This case should hopefully be rare, but just in case...
 7343            log::error!(
 7344                "multiple different run targets found on a single line, only the last target will be rendered"
 7345            )
 7346        }
 7347    }
 7348
 7349    /// Get all display points of breakpoints that will be rendered within editor
 7350    ///
 7351    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7352    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7353    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7354    fn active_breakpoints(
 7355        &self,
 7356        range: Range<DisplayRow>,
 7357        window: &mut Window,
 7358        cx: &mut Context<Self>,
 7359    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7360        let mut breakpoint_display_points = HashMap::default();
 7361
 7362        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7363            return breakpoint_display_points;
 7364        };
 7365
 7366        let snapshot = self.snapshot(window, cx);
 7367
 7368        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7369        let Some(project) = self.project.as_ref() else {
 7370            return breakpoint_display_points;
 7371        };
 7372
 7373        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7374            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7375
 7376        for (buffer_snapshot, range, excerpt_id) in
 7377            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7378        {
 7379            let Some(buffer) = project
 7380                .read(cx)
 7381                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7382            else {
 7383                continue;
 7384            };
 7385            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7386                &buffer,
 7387                Some(
 7388                    buffer_snapshot.anchor_before(range.start)
 7389                        ..buffer_snapshot.anchor_after(range.end),
 7390                ),
 7391                buffer_snapshot,
 7392                cx,
 7393            );
 7394            for (breakpoint, state) in breakpoints {
 7395                let multi_buffer_anchor =
 7396                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7397                let position = multi_buffer_anchor
 7398                    .to_point(&multi_buffer_snapshot)
 7399                    .to_display_point(&snapshot);
 7400
 7401                breakpoint_display_points.insert(
 7402                    position.row(),
 7403                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7404                );
 7405            }
 7406        }
 7407
 7408        breakpoint_display_points
 7409    }
 7410
 7411    fn breakpoint_context_menu(
 7412        &self,
 7413        anchor: Anchor,
 7414        window: &mut Window,
 7415        cx: &mut Context<Self>,
 7416    ) -> Entity<ui::ContextMenu> {
 7417        let weak_editor = cx.weak_entity();
 7418        let focus_handle = self.focus_handle(cx);
 7419
 7420        let row = self
 7421            .buffer
 7422            .read(cx)
 7423            .snapshot(cx)
 7424            .summary_for_anchor::<Point>(&anchor)
 7425            .row;
 7426
 7427        let breakpoint = self
 7428            .breakpoint_at_row(row, window, cx)
 7429            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7430
 7431        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7432            "Edit Log Breakpoint"
 7433        } else {
 7434            "Set Log Breakpoint"
 7435        };
 7436
 7437        let condition_breakpoint_msg = if breakpoint
 7438            .as_ref()
 7439            .is_some_and(|bp| bp.1.condition.is_some())
 7440        {
 7441            "Edit Condition Breakpoint"
 7442        } else {
 7443            "Set Condition Breakpoint"
 7444        };
 7445
 7446        let hit_condition_breakpoint_msg = if breakpoint
 7447            .as_ref()
 7448            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7449        {
 7450            "Edit Hit Condition Breakpoint"
 7451        } else {
 7452            "Set Hit Condition Breakpoint"
 7453        };
 7454
 7455        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7456            "Unset Breakpoint"
 7457        } else {
 7458            "Set Breakpoint"
 7459        };
 7460
 7461        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7462            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7463
 7464        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7465            BreakpointState::Enabled => Some("Disable"),
 7466            BreakpointState::Disabled => Some("Enable"),
 7467        });
 7468
 7469        let (anchor, breakpoint) =
 7470            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7471
 7472        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7473            menu.on_blur_subscription(Subscription::new(|| {}))
 7474                .context(focus_handle)
 7475                .when(run_to_cursor, |this| {
 7476                    let weak_editor = weak_editor.clone();
 7477                    this.entry("Run to cursor", None, move |window, cx| {
 7478                        weak_editor
 7479                            .update(cx, |editor, cx| {
 7480                                editor.change_selections(None, window, cx, |s| {
 7481                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7482                                });
 7483                            })
 7484                            .ok();
 7485
 7486                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7487                    })
 7488                    .separator()
 7489                })
 7490                .when_some(toggle_state_msg, |this, msg| {
 7491                    this.entry(msg, None, {
 7492                        let weak_editor = weak_editor.clone();
 7493                        let breakpoint = breakpoint.clone();
 7494                        move |_window, cx| {
 7495                            weak_editor
 7496                                .update(cx, |this, cx| {
 7497                                    this.edit_breakpoint_at_anchor(
 7498                                        anchor,
 7499                                        breakpoint.as_ref().clone(),
 7500                                        BreakpointEditAction::InvertState,
 7501                                        cx,
 7502                                    );
 7503                                })
 7504                                .log_err();
 7505                        }
 7506                    })
 7507                })
 7508                .entry(set_breakpoint_msg, None, {
 7509                    let weak_editor = weak_editor.clone();
 7510                    let breakpoint = breakpoint.clone();
 7511                    move |_window, cx| {
 7512                        weak_editor
 7513                            .update(cx, |this, cx| {
 7514                                this.edit_breakpoint_at_anchor(
 7515                                    anchor,
 7516                                    breakpoint.as_ref().clone(),
 7517                                    BreakpointEditAction::Toggle,
 7518                                    cx,
 7519                                );
 7520                            })
 7521                            .log_err();
 7522                    }
 7523                })
 7524                .entry(log_breakpoint_msg, None, {
 7525                    let breakpoint = breakpoint.clone();
 7526                    let weak_editor = weak_editor.clone();
 7527                    move |window, cx| {
 7528                        weak_editor
 7529                            .update(cx, |this, cx| {
 7530                                this.add_edit_breakpoint_block(
 7531                                    anchor,
 7532                                    breakpoint.as_ref(),
 7533                                    BreakpointPromptEditAction::Log,
 7534                                    window,
 7535                                    cx,
 7536                                );
 7537                            })
 7538                            .log_err();
 7539                    }
 7540                })
 7541                .entry(condition_breakpoint_msg, None, {
 7542                    let breakpoint = breakpoint.clone();
 7543                    let weak_editor = weak_editor.clone();
 7544                    move |window, cx| {
 7545                        weak_editor
 7546                            .update(cx, |this, cx| {
 7547                                this.add_edit_breakpoint_block(
 7548                                    anchor,
 7549                                    breakpoint.as_ref(),
 7550                                    BreakpointPromptEditAction::Condition,
 7551                                    window,
 7552                                    cx,
 7553                                );
 7554                            })
 7555                            .log_err();
 7556                    }
 7557                })
 7558                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7559                    weak_editor
 7560                        .update(cx, |this, cx| {
 7561                            this.add_edit_breakpoint_block(
 7562                                anchor,
 7563                                breakpoint.as_ref(),
 7564                                BreakpointPromptEditAction::HitCondition,
 7565                                window,
 7566                                cx,
 7567                            );
 7568                        })
 7569                        .log_err();
 7570                })
 7571        })
 7572    }
 7573
 7574    fn render_breakpoint(
 7575        &self,
 7576        position: Anchor,
 7577        row: DisplayRow,
 7578        breakpoint: &Breakpoint,
 7579        state: Option<BreakpointSessionState>,
 7580        cx: &mut Context<Self>,
 7581    ) -> IconButton {
 7582        let is_rejected = state.is_some_and(|s| !s.verified);
 7583        // Is it a breakpoint that shows up when hovering over gutter?
 7584        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7585            (false, false),
 7586            |PhantomBreakpointIndicator {
 7587                 is_active,
 7588                 display_row,
 7589                 collides_with_existing_breakpoint,
 7590             }| {
 7591                (
 7592                    is_active && display_row == row,
 7593                    collides_with_existing_breakpoint,
 7594                )
 7595            },
 7596        );
 7597
 7598        let (color, icon) = {
 7599            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7600                (false, false) => ui::IconName::DebugBreakpoint,
 7601                (true, false) => ui::IconName::DebugLogBreakpoint,
 7602                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7603                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7604            };
 7605
 7606            let color = if is_phantom {
 7607                Color::Hint
 7608            } else if is_rejected {
 7609                Color::Disabled
 7610            } else {
 7611                Color::Debugger
 7612            };
 7613
 7614            (color, icon)
 7615        };
 7616
 7617        let breakpoint = Arc::from(breakpoint.clone());
 7618
 7619        let alt_as_text = gpui::Keystroke {
 7620            modifiers: Modifiers::secondary_key(),
 7621            ..Default::default()
 7622        };
 7623        let primary_action_text = if breakpoint.is_disabled() {
 7624            "Enable breakpoint"
 7625        } else if is_phantom && !collides_with_existing {
 7626            "Set breakpoint"
 7627        } else {
 7628            "Unset breakpoint"
 7629        };
 7630        let focus_handle = self.focus_handle.clone();
 7631
 7632        let meta = if is_rejected {
 7633            SharedString::from("No executable code is associated with this line.")
 7634        } else if collides_with_existing && !breakpoint.is_disabled() {
 7635            SharedString::from(format!(
 7636                "{alt_as_text}-click to disable,\nright-click for more options."
 7637            ))
 7638        } else {
 7639            SharedString::from("Right-click for more options.")
 7640        };
 7641        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7642            .icon_size(IconSize::XSmall)
 7643            .size(ui::ButtonSize::None)
 7644            .when(is_rejected, |this| {
 7645                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7646            })
 7647            .icon_color(color)
 7648            .style(ButtonStyle::Transparent)
 7649            .on_click(cx.listener({
 7650                let breakpoint = breakpoint.clone();
 7651
 7652                move |editor, event: &ClickEvent, window, cx| {
 7653                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7654                        BreakpointEditAction::InvertState
 7655                    } else {
 7656                        BreakpointEditAction::Toggle
 7657                    };
 7658
 7659                    window.focus(&editor.focus_handle(cx));
 7660                    editor.edit_breakpoint_at_anchor(
 7661                        position,
 7662                        breakpoint.as_ref().clone(),
 7663                        edit_action,
 7664                        cx,
 7665                    );
 7666                }
 7667            }))
 7668            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7669                editor.set_breakpoint_context_menu(
 7670                    row,
 7671                    Some(position),
 7672                    event.down.position,
 7673                    window,
 7674                    cx,
 7675                );
 7676            }))
 7677            .tooltip(move |window, cx| {
 7678                Tooltip::with_meta_in(
 7679                    primary_action_text,
 7680                    Some(&ToggleBreakpoint),
 7681                    meta.clone(),
 7682                    &focus_handle,
 7683                    window,
 7684                    cx,
 7685                )
 7686            })
 7687    }
 7688
 7689    fn build_tasks_context(
 7690        project: &Entity<Project>,
 7691        buffer: &Entity<Buffer>,
 7692        buffer_row: u32,
 7693        tasks: &Arc<RunnableTasks>,
 7694        cx: &mut Context<Self>,
 7695    ) -> Task<Option<task::TaskContext>> {
 7696        let position = Point::new(buffer_row, tasks.column);
 7697        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7698        let location = Location {
 7699            buffer: buffer.clone(),
 7700            range: range_start..range_start,
 7701        };
 7702        // Fill in the environmental variables from the tree-sitter captures
 7703        let mut captured_task_variables = TaskVariables::default();
 7704        for (capture_name, value) in tasks.extra_variables.clone() {
 7705            captured_task_variables.insert(
 7706                task::VariableName::Custom(capture_name.into()),
 7707                value.clone(),
 7708            );
 7709        }
 7710        project.update(cx, |project, cx| {
 7711            project.task_store().update(cx, |task_store, cx| {
 7712                task_store.task_context_for_location(captured_task_variables, location, cx)
 7713            })
 7714        })
 7715    }
 7716
 7717    pub fn spawn_nearest_task(
 7718        &mut self,
 7719        action: &SpawnNearestTask,
 7720        window: &mut Window,
 7721        cx: &mut Context<Self>,
 7722    ) {
 7723        let Some((workspace, _)) = self.workspace.clone() else {
 7724            return;
 7725        };
 7726        let Some(project) = self.project.clone() else {
 7727            return;
 7728        };
 7729
 7730        // Try to find a closest, enclosing node using tree-sitter that has a
 7731        // task
 7732        let Some((buffer, buffer_row, tasks)) = self
 7733            .find_enclosing_node_task(cx)
 7734            // Or find the task that's closest in row-distance.
 7735            .or_else(|| self.find_closest_task(cx))
 7736        else {
 7737            return;
 7738        };
 7739
 7740        let reveal_strategy = action.reveal;
 7741        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7742        cx.spawn_in(window, async move |_, cx| {
 7743            let context = task_context.await?;
 7744            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7745
 7746            let resolved = &mut resolved_task.resolved;
 7747            resolved.reveal = reveal_strategy;
 7748
 7749            workspace
 7750                .update_in(cx, |workspace, window, cx| {
 7751                    workspace.schedule_resolved_task(
 7752                        task_source_kind,
 7753                        resolved_task,
 7754                        false,
 7755                        window,
 7756                        cx,
 7757                    );
 7758                })
 7759                .ok()
 7760        })
 7761        .detach();
 7762    }
 7763
 7764    fn find_closest_task(
 7765        &mut self,
 7766        cx: &mut Context<Self>,
 7767    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7768        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7769
 7770        let ((buffer_id, row), tasks) = self
 7771            .tasks
 7772            .iter()
 7773            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7774
 7775        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7776        let tasks = Arc::new(tasks.to_owned());
 7777        Some((buffer, *row, tasks))
 7778    }
 7779
 7780    fn find_enclosing_node_task(
 7781        &mut self,
 7782        cx: &mut Context<Self>,
 7783    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7784        let snapshot = self.buffer.read(cx).snapshot(cx);
 7785        let offset = self.selections.newest::<usize>(cx).head();
 7786        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7787        let buffer_id = excerpt.buffer().remote_id();
 7788
 7789        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7790        let mut cursor = layer.node().walk();
 7791
 7792        while cursor.goto_first_child_for_byte(offset).is_some() {
 7793            if cursor.node().end_byte() == offset {
 7794                cursor.goto_next_sibling();
 7795            }
 7796        }
 7797
 7798        // Ascend to the smallest ancestor that contains the range and has a task.
 7799        loop {
 7800            let node = cursor.node();
 7801            let node_range = node.byte_range();
 7802            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7803
 7804            // Check if this node contains our offset
 7805            if node_range.start <= offset && node_range.end >= offset {
 7806                // If it contains offset, check for task
 7807                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7808                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7809                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7810                }
 7811            }
 7812
 7813            if !cursor.goto_parent() {
 7814                break;
 7815            }
 7816        }
 7817        None
 7818    }
 7819
 7820    fn render_run_indicator(
 7821        &self,
 7822        _style: &EditorStyle,
 7823        is_active: bool,
 7824        row: DisplayRow,
 7825        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7826        cx: &mut Context<Self>,
 7827    ) -> IconButton {
 7828        let color = Color::Muted;
 7829        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7830
 7831        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7832            .shape(ui::IconButtonShape::Square)
 7833            .icon_size(IconSize::XSmall)
 7834            .icon_color(color)
 7835            .toggle_state(is_active)
 7836            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7837                let quick_launch = e.down.button == MouseButton::Left;
 7838                window.focus(&editor.focus_handle(cx));
 7839                editor.toggle_code_actions(
 7840                    &ToggleCodeActions {
 7841                        deployed_from: Some(CodeActionSource::Indicator(row)),
 7842                        quick_launch,
 7843                    },
 7844                    window,
 7845                    cx,
 7846                );
 7847            }))
 7848            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7849                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7850            }))
 7851    }
 7852
 7853    pub fn context_menu_visible(&self) -> bool {
 7854        !self.edit_prediction_preview_is_active()
 7855            && self
 7856                .context_menu
 7857                .borrow()
 7858                .as_ref()
 7859                .map_or(false, |menu| menu.visible())
 7860    }
 7861
 7862    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7863        self.context_menu
 7864            .borrow()
 7865            .as_ref()
 7866            .map(|menu| menu.origin())
 7867    }
 7868
 7869    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7870        self.context_menu_options = Some(options);
 7871    }
 7872
 7873    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7874    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7875
 7876    fn render_edit_prediction_popover(
 7877        &mut self,
 7878        text_bounds: &Bounds<Pixels>,
 7879        content_origin: gpui::Point<Pixels>,
 7880        right_margin: Pixels,
 7881        editor_snapshot: &EditorSnapshot,
 7882        visible_row_range: Range<DisplayRow>,
 7883        scroll_top: f32,
 7884        scroll_bottom: f32,
 7885        line_layouts: &[LineWithInvisibles],
 7886        line_height: Pixels,
 7887        scroll_pixel_position: gpui::Point<Pixels>,
 7888        newest_selection_head: Option<DisplayPoint>,
 7889        editor_width: Pixels,
 7890        style: &EditorStyle,
 7891        window: &mut Window,
 7892        cx: &mut App,
 7893    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7894        if self.mode().is_minimap() {
 7895            return None;
 7896        }
 7897        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7898
 7899        if self.edit_prediction_visible_in_cursor_popover(true) {
 7900            return None;
 7901        }
 7902
 7903        match &active_inline_completion.completion {
 7904            InlineCompletion::Move { target, .. } => {
 7905                let target_display_point = target.to_display_point(editor_snapshot);
 7906
 7907                if self.edit_prediction_requires_modifier() {
 7908                    if !self.edit_prediction_preview_is_active() {
 7909                        return None;
 7910                    }
 7911
 7912                    self.render_edit_prediction_modifier_jump_popover(
 7913                        text_bounds,
 7914                        content_origin,
 7915                        visible_row_range,
 7916                        line_layouts,
 7917                        line_height,
 7918                        scroll_pixel_position,
 7919                        newest_selection_head,
 7920                        target_display_point,
 7921                        window,
 7922                        cx,
 7923                    )
 7924                } else {
 7925                    self.render_edit_prediction_eager_jump_popover(
 7926                        text_bounds,
 7927                        content_origin,
 7928                        editor_snapshot,
 7929                        visible_row_range,
 7930                        scroll_top,
 7931                        scroll_bottom,
 7932                        line_height,
 7933                        scroll_pixel_position,
 7934                        target_display_point,
 7935                        editor_width,
 7936                        window,
 7937                        cx,
 7938                    )
 7939                }
 7940            }
 7941            InlineCompletion::Edit {
 7942                display_mode: EditDisplayMode::Inline,
 7943                ..
 7944            } => None,
 7945            InlineCompletion::Edit {
 7946                display_mode: EditDisplayMode::TabAccept,
 7947                edits,
 7948                ..
 7949            } => {
 7950                let range = &edits.first()?.0;
 7951                let target_display_point = range.end.to_display_point(editor_snapshot);
 7952
 7953                self.render_edit_prediction_end_of_line_popover(
 7954                    "Accept",
 7955                    editor_snapshot,
 7956                    visible_row_range,
 7957                    target_display_point,
 7958                    line_height,
 7959                    scroll_pixel_position,
 7960                    content_origin,
 7961                    editor_width,
 7962                    window,
 7963                    cx,
 7964                )
 7965            }
 7966            InlineCompletion::Edit {
 7967                edits,
 7968                edit_preview,
 7969                display_mode: EditDisplayMode::DiffPopover,
 7970                snapshot,
 7971            } => self.render_edit_prediction_diff_popover(
 7972                text_bounds,
 7973                content_origin,
 7974                right_margin,
 7975                editor_snapshot,
 7976                visible_row_range,
 7977                line_layouts,
 7978                line_height,
 7979                scroll_pixel_position,
 7980                newest_selection_head,
 7981                editor_width,
 7982                style,
 7983                edits,
 7984                edit_preview,
 7985                snapshot,
 7986                window,
 7987                cx,
 7988            ),
 7989        }
 7990    }
 7991
 7992    fn render_edit_prediction_modifier_jump_popover(
 7993        &mut self,
 7994        text_bounds: &Bounds<Pixels>,
 7995        content_origin: gpui::Point<Pixels>,
 7996        visible_row_range: Range<DisplayRow>,
 7997        line_layouts: &[LineWithInvisibles],
 7998        line_height: Pixels,
 7999        scroll_pixel_position: gpui::Point<Pixels>,
 8000        newest_selection_head: Option<DisplayPoint>,
 8001        target_display_point: DisplayPoint,
 8002        window: &mut Window,
 8003        cx: &mut App,
 8004    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8005        let scrolled_content_origin =
 8006            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8007
 8008        const SCROLL_PADDING_Y: Pixels = px(12.);
 8009
 8010        if target_display_point.row() < visible_row_range.start {
 8011            return self.render_edit_prediction_scroll_popover(
 8012                |_| SCROLL_PADDING_Y,
 8013                IconName::ArrowUp,
 8014                visible_row_range,
 8015                line_layouts,
 8016                newest_selection_head,
 8017                scrolled_content_origin,
 8018                window,
 8019                cx,
 8020            );
 8021        } else if target_display_point.row() >= visible_row_range.end {
 8022            return self.render_edit_prediction_scroll_popover(
 8023                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8024                IconName::ArrowDown,
 8025                visible_row_range,
 8026                line_layouts,
 8027                newest_selection_head,
 8028                scrolled_content_origin,
 8029                window,
 8030                cx,
 8031            );
 8032        }
 8033
 8034        const POLE_WIDTH: Pixels = px(2.);
 8035
 8036        let line_layout =
 8037            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8038        let target_column = target_display_point.column() as usize;
 8039
 8040        let target_x = line_layout.x_for_index(target_column);
 8041        let target_y =
 8042            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8043
 8044        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8045
 8046        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8047        border_color.l += 0.001;
 8048
 8049        let mut element = v_flex()
 8050            .items_end()
 8051            .when(flag_on_right, |el| el.items_start())
 8052            .child(if flag_on_right {
 8053                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8054                    .rounded_bl(px(0.))
 8055                    .rounded_tl(px(0.))
 8056                    .border_l_2()
 8057                    .border_color(border_color)
 8058            } else {
 8059                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8060                    .rounded_br(px(0.))
 8061                    .rounded_tr(px(0.))
 8062                    .border_r_2()
 8063                    .border_color(border_color)
 8064            })
 8065            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8066            .into_any();
 8067
 8068        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8069
 8070        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8071            - point(
 8072                if flag_on_right {
 8073                    POLE_WIDTH
 8074                } else {
 8075                    size.width - POLE_WIDTH
 8076                },
 8077                size.height - line_height,
 8078            );
 8079
 8080        origin.x = origin.x.max(content_origin.x);
 8081
 8082        element.prepaint_at(origin, window, cx);
 8083
 8084        Some((element, origin))
 8085    }
 8086
 8087    fn render_edit_prediction_scroll_popover(
 8088        &mut self,
 8089        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8090        scroll_icon: IconName,
 8091        visible_row_range: Range<DisplayRow>,
 8092        line_layouts: &[LineWithInvisibles],
 8093        newest_selection_head: Option<DisplayPoint>,
 8094        scrolled_content_origin: gpui::Point<Pixels>,
 8095        window: &mut Window,
 8096        cx: &mut App,
 8097    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8098        let mut element = self
 8099            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8100            .into_any();
 8101
 8102        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8103
 8104        let cursor = newest_selection_head?;
 8105        let cursor_row_layout =
 8106            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8107        let cursor_column = cursor.column() as usize;
 8108
 8109        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8110
 8111        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8112
 8113        element.prepaint_at(origin, window, cx);
 8114        Some((element, origin))
 8115    }
 8116
 8117    fn render_edit_prediction_eager_jump_popover(
 8118        &mut self,
 8119        text_bounds: &Bounds<Pixels>,
 8120        content_origin: gpui::Point<Pixels>,
 8121        editor_snapshot: &EditorSnapshot,
 8122        visible_row_range: Range<DisplayRow>,
 8123        scroll_top: f32,
 8124        scroll_bottom: f32,
 8125        line_height: Pixels,
 8126        scroll_pixel_position: gpui::Point<Pixels>,
 8127        target_display_point: DisplayPoint,
 8128        editor_width: Pixels,
 8129        window: &mut Window,
 8130        cx: &mut App,
 8131    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8132        if target_display_point.row().as_f32() < scroll_top {
 8133            let mut element = self
 8134                .render_edit_prediction_line_popover(
 8135                    "Jump to Edit",
 8136                    Some(IconName::ArrowUp),
 8137                    window,
 8138                    cx,
 8139                )?
 8140                .into_any();
 8141
 8142            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8143            let offset = point(
 8144                (text_bounds.size.width - size.width) / 2.,
 8145                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8146            );
 8147
 8148            let origin = text_bounds.origin + offset;
 8149            element.prepaint_at(origin, window, cx);
 8150            Some((element, origin))
 8151        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8152            let mut element = self
 8153                .render_edit_prediction_line_popover(
 8154                    "Jump to Edit",
 8155                    Some(IconName::ArrowDown),
 8156                    window,
 8157                    cx,
 8158                )?
 8159                .into_any();
 8160
 8161            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8162            let offset = point(
 8163                (text_bounds.size.width - size.width) / 2.,
 8164                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8165            );
 8166
 8167            let origin = text_bounds.origin + offset;
 8168            element.prepaint_at(origin, window, cx);
 8169            Some((element, origin))
 8170        } else {
 8171            self.render_edit_prediction_end_of_line_popover(
 8172                "Jump to Edit",
 8173                editor_snapshot,
 8174                visible_row_range,
 8175                target_display_point,
 8176                line_height,
 8177                scroll_pixel_position,
 8178                content_origin,
 8179                editor_width,
 8180                window,
 8181                cx,
 8182            )
 8183        }
 8184    }
 8185
 8186    fn render_edit_prediction_end_of_line_popover(
 8187        self: &mut Editor,
 8188        label: &'static str,
 8189        editor_snapshot: &EditorSnapshot,
 8190        visible_row_range: Range<DisplayRow>,
 8191        target_display_point: DisplayPoint,
 8192        line_height: Pixels,
 8193        scroll_pixel_position: gpui::Point<Pixels>,
 8194        content_origin: gpui::Point<Pixels>,
 8195        editor_width: Pixels,
 8196        window: &mut Window,
 8197        cx: &mut App,
 8198    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8199        let target_line_end = DisplayPoint::new(
 8200            target_display_point.row(),
 8201            editor_snapshot.line_len(target_display_point.row()),
 8202        );
 8203
 8204        let mut element = self
 8205            .render_edit_prediction_line_popover(label, None, window, cx)?
 8206            .into_any();
 8207
 8208        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8209
 8210        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8211
 8212        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8213        let mut origin = start_point
 8214            + line_origin
 8215            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8216        origin.x = origin.x.max(content_origin.x);
 8217
 8218        let max_x = content_origin.x + editor_width - size.width;
 8219
 8220        if origin.x > max_x {
 8221            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8222
 8223            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8224                origin.y += offset;
 8225                IconName::ArrowUp
 8226            } else {
 8227                origin.y -= offset;
 8228                IconName::ArrowDown
 8229            };
 8230
 8231            element = self
 8232                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8233                .into_any();
 8234
 8235            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8236
 8237            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8238        }
 8239
 8240        element.prepaint_at(origin, window, cx);
 8241        Some((element, origin))
 8242    }
 8243
 8244    fn render_edit_prediction_diff_popover(
 8245        self: &Editor,
 8246        text_bounds: &Bounds<Pixels>,
 8247        content_origin: gpui::Point<Pixels>,
 8248        right_margin: Pixels,
 8249        editor_snapshot: &EditorSnapshot,
 8250        visible_row_range: Range<DisplayRow>,
 8251        line_layouts: &[LineWithInvisibles],
 8252        line_height: Pixels,
 8253        scroll_pixel_position: gpui::Point<Pixels>,
 8254        newest_selection_head: Option<DisplayPoint>,
 8255        editor_width: Pixels,
 8256        style: &EditorStyle,
 8257        edits: &Vec<(Range<Anchor>, String)>,
 8258        edit_preview: &Option<language::EditPreview>,
 8259        snapshot: &language::BufferSnapshot,
 8260        window: &mut Window,
 8261        cx: &mut App,
 8262    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8263        let edit_start = edits
 8264            .first()
 8265            .unwrap()
 8266            .0
 8267            .start
 8268            .to_display_point(editor_snapshot);
 8269        let edit_end = edits
 8270            .last()
 8271            .unwrap()
 8272            .0
 8273            .end
 8274            .to_display_point(editor_snapshot);
 8275
 8276        let is_visible = visible_row_range.contains(&edit_start.row())
 8277            || visible_row_range.contains(&edit_end.row());
 8278        if !is_visible {
 8279            return None;
 8280        }
 8281
 8282        let highlighted_edits =
 8283            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8284
 8285        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8286        let line_count = highlighted_edits.text.lines().count();
 8287
 8288        const BORDER_WIDTH: Pixels = px(1.);
 8289
 8290        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8291        let has_keybind = keybind.is_some();
 8292
 8293        let mut element = h_flex()
 8294            .items_start()
 8295            .child(
 8296                h_flex()
 8297                    .bg(cx.theme().colors().editor_background)
 8298                    .border(BORDER_WIDTH)
 8299                    .shadow_sm()
 8300                    .border_color(cx.theme().colors().border)
 8301                    .rounded_l_lg()
 8302                    .when(line_count > 1, |el| el.rounded_br_lg())
 8303                    .pr_1()
 8304                    .child(styled_text),
 8305            )
 8306            .child(
 8307                h_flex()
 8308                    .h(line_height + BORDER_WIDTH * 2.)
 8309                    .px_1p5()
 8310                    .gap_1()
 8311                    // Workaround: For some reason, there's a gap if we don't do this
 8312                    .ml(-BORDER_WIDTH)
 8313                    .shadow(vec![gpui::BoxShadow {
 8314                        color: gpui::black().opacity(0.05),
 8315                        offset: point(px(1.), px(1.)),
 8316                        blur_radius: px(2.),
 8317                        spread_radius: px(0.),
 8318                    }])
 8319                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8320                    .border(BORDER_WIDTH)
 8321                    .border_color(cx.theme().colors().border)
 8322                    .rounded_r_lg()
 8323                    .id("edit_prediction_diff_popover_keybind")
 8324                    .when(!has_keybind, |el| {
 8325                        let status_colors = cx.theme().status();
 8326
 8327                        el.bg(status_colors.error_background)
 8328                            .border_color(status_colors.error.opacity(0.6))
 8329                            .child(Icon::new(IconName::Info).color(Color::Error))
 8330                            .cursor_default()
 8331                            .hoverable_tooltip(move |_window, cx| {
 8332                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8333                            })
 8334                    })
 8335                    .children(keybind),
 8336            )
 8337            .into_any();
 8338
 8339        let longest_row =
 8340            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8341        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8342            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8343        } else {
 8344            layout_line(
 8345                longest_row,
 8346                editor_snapshot,
 8347                style,
 8348                editor_width,
 8349                |_| false,
 8350                window,
 8351                cx,
 8352            )
 8353            .width
 8354        };
 8355
 8356        let viewport_bounds =
 8357            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8358                right: -right_margin,
 8359                ..Default::default()
 8360            });
 8361
 8362        let x_after_longest =
 8363            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8364                - scroll_pixel_position.x;
 8365
 8366        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8367
 8368        // Fully visible if it can be displayed within the window (allow overlapping other
 8369        // panes). However, this is only allowed if the popover starts within text_bounds.
 8370        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8371            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8372
 8373        let mut origin = if can_position_to_the_right {
 8374            point(
 8375                x_after_longest,
 8376                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8377                    - scroll_pixel_position.y,
 8378            )
 8379        } else {
 8380            let cursor_row = newest_selection_head.map(|head| head.row());
 8381            let above_edit = edit_start
 8382                .row()
 8383                .0
 8384                .checked_sub(line_count as u32)
 8385                .map(DisplayRow);
 8386            let below_edit = Some(edit_end.row() + 1);
 8387            let above_cursor =
 8388                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8389            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8390
 8391            // Place the edit popover adjacent to the edit if there is a location
 8392            // available that is onscreen and does not obscure the cursor. Otherwise,
 8393            // place it adjacent to the cursor.
 8394            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8395                .into_iter()
 8396                .flatten()
 8397                .find(|&start_row| {
 8398                    let end_row = start_row + line_count as u32;
 8399                    visible_row_range.contains(&start_row)
 8400                        && visible_row_range.contains(&end_row)
 8401                        && cursor_row.map_or(true, |cursor_row| {
 8402                            !((start_row..end_row).contains(&cursor_row))
 8403                        })
 8404                })?;
 8405
 8406            content_origin
 8407                + point(
 8408                    -scroll_pixel_position.x,
 8409                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8410                )
 8411        };
 8412
 8413        origin.x -= BORDER_WIDTH;
 8414
 8415        window.defer_draw(element, origin, 1);
 8416
 8417        // Do not return an element, since it will already be drawn due to defer_draw.
 8418        None
 8419    }
 8420
 8421    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8422        px(30.)
 8423    }
 8424
 8425    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8426        if self.read_only(cx) {
 8427            cx.theme().players().read_only()
 8428        } else {
 8429            self.style.as_ref().unwrap().local_player
 8430        }
 8431    }
 8432
 8433    fn render_edit_prediction_accept_keybind(
 8434        &self,
 8435        window: &mut Window,
 8436        cx: &App,
 8437    ) -> Option<AnyElement> {
 8438        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8439        let accept_keystroke = accept_binding.keystroke()?;
 8440
 8441        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8442
 8443        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8444            Color::Accent
 8445        } else {
 8446            Color::Muted
 8447        };
 8448
 8449        h_flex()
 8450            .px_0p5()
 8451            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8452            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8453            .text_size(TextSize::XSmall.rems(cx))
 8454            .child(h_flex().children(ui::render_modifiers(
 8455                &accept_keystroke.modifiers,
 8456                PlatformStyle::platform(),
 8457                Some(modifiers_color),
 8458                Some(IconSize::XSmall.rems().into()),
 8459                true,
 8460            )))
 8461            .when(is_platform_style_mac, |parent| {
 8462                parent.child(accept_keystroke.key.clone())
 8463            })
 8464            .when(!is_platform_style_mac, |parent| {
 8465                parent.child(
 8466                    Key::new(
 8467                        util::capitalize(&accept_keystroke.key),
 8468                        Some(Color::Default),
 8469                    )
 8470                    .size(Some(IconSize::XSmall.rems().into())),
 8471                )
 8472            })
 8473            .into_any()
 8474            .into()
 8475    }
 8476
 8477    fn render_edit_prediction_line_popover(
 8478        &self,
 8479        label: impl Into<SharedString>,
 8480        icon: Option<IconName>,
 8481        window: &mut Window,
 8482        cx: &App,
 8483    ) -> Option<Stateful<Div>> {
 8484        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8485
 8486        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8487        let has_keybind = keybind.is_some();
 8488
 8489        let result = h_flex()
 8490            .id("ep-line-popover")
 8491            .py_0p5()
 8492            .pl_1()
 8493            .pr(padding_right)
 8494            .gap_1()
 8495            .rounded_md()
 8496            .border_1()
 8497            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8498            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8499            .shadow_sm()
 8500            .when(!has_keybind, |el| {
 8501                let status_colors = cx.theme().status();
 8502
 8503                el.bg(status_colors.error_background)
 8504                    .border_color(status_colors.error.opacity(0.6))
 8505                    .pl_2()
 8506                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8507                    .cursor_default()
 8508                    .hoverable_tooltip(move |_window, cx| {
 8509                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8510                    })
 8511            })
 8512            .children(keybind)
 8513            .child(
 8514                Label::new(label)
 8515                    .size(LabelSize::Small)
 8516                    .when(!has_keybind, |el| {
 8517                        el.color(cx.theme().status().error.into()).strikethrough()
 8518                    }),
 8519            )
 8520            .when(!has_keybind, |el| {
 8521                el.child(
 8522                    h_flex().ml_1().child(
 8523                        Icon::new(IconName::Info)
 8524                            .size(IconSize::Small)
 8525                            .color(cx.theme().status().error.into()),
 8526                    ),
 8527                )
 8528            })
 8529            .when_some(icon, |element, icon| {
 8530                element.child(
 8531                    div()
 8532                        .mt(px(1.5))
 8533                        .child(Icon::new(icon).size(IconSize::Small)),
 8534                )
 8535            });
 8536
 8537        Some(result)
 8538    }
 8539
 8540    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8541        let accent_color = cx.theme().colors().text_accent;
 8542        let editor_bg_color = cx.theme().colors().editor_background;
 8543        editor_bg_color.blend(accent_color.opacity(0.1))
 8544    }
 8545
 8546    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8547        let accent_color = cx.theme().colors().text_accent;
 8548        let editor_bg_color = cx.theme().colors().editor_background;
 8549        editor_bg_color.blend(accent_color.opacity(0.6))
 8550    }
 8551
 8552    fn render_edit_prediction_cursor_popover(
 8553        &self,
 8554        min_width: Pixels,
 8555        max_width: Pixels,
 8556        cursor_point: Point,
 8557        style: &EditorStyle,
 8558        accept_keystroke: Option<&gpui::Keystroke>,
 8559        _window: &Window,
 8560        cx: &mut Context<Editor>,
 8561    ) -> Option<AnyElement> {
 8562        let provider = self.edit_prediction_provider.as_ref()?;
 8563
 8564        if provider.provider.needs_terms_acceptance(cx) {
 8565            return Some(
 8566                h_flex()
 8567                    .min_w(min_width)
 8568                    .flex_1()
 8569                    .px_2()
 8570                    .py_1()
 8571                    .gap_3()
 8572                    .elevation_2(cx)
 8573                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8574                    .id("accept-terms")
 8575                    .cursor_pointer()
 8576                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8577                    .on_click(cx.listener(|this, _event, window, cx| {
 8578                        cx.stop_propagation();
 8579                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8580                        window.dispatch_action(
 8581                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8582                            cx,
 8583                        );
 8584                    }))
 8585                    .child(
 8586                        h_flex()
 8587                            .flex_1()
 8588                            .gap_2()
 8589                            .child(Icon::new(IconName::ZedPredict))
 8590                            .child(Label::new("Accept Terms of Service"))
 8591                            .child(div().w_full())
 8592                            .child(
 8593                                Icon::new(IconName::ArrowUpRight)
 8594                                    .color(Color::Muted)
 8595                                    .size(IconSize::Small),
 8596                            )
 8597                            .into_any_element(),
 8598                    )
 8599                    .into_any(),
 8600            );
 8601        }
 8602
 8603        let is_refreshing = provider.provider.is_refreshing(cx);
 8604
 8605        fn pending_completion_container() -> Div {
 8606            h_flex()
 8607                .h_full()
 8608                .flex_1()
 8609                .gap_2()
 8610                .child(Icon::new(IconName::ZedPredict))
 8611        }
 8612
 8613        let completion = match &self.active_inline_completion {
 8614            Some(prediction) => {
 8615                if !self.has_visible_completions_menu() {
 8616                    const RADIUS: Pixels = px(6.);
 8617                    const BORDER_WIDTH: Pixels = px(1.);
 8618
 8619                    return Some(
 8620                        h_flex()
 8621                            .elevation_2(cx)
 8622                            .border(BORDER_WIDTH)
 8623                            .border_color(cx.theme().colors().border)
 8624                            .when(accept_keystroke.is_none(), |el| {
 8625                                el.border_color(cx.theme().status().error)
 8626                            })
 8627                            .rounded(RADIUS)
 8628                            .rounded_tl(px(0.))
 8629                            .overflow_hidden()
 8630                            .child(div().px_1p5().child(match &prediction.completion {
 8631                                InlineCompletion::Move { target, snapshot } => {
 8632                                    use text::ToPoint as _;
 8633                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8634                                    {
 8635                                        Icon::new(IconName::ZedPredictDown)
 8636                                    } else {
 8637                                        Icon::new(IconName::ZedPredictUp)
 8638                                    }
 8639                                }
 8640                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8641                            }))
 8642                            .child(
 8643                                h_flex()
 8644                                    .gap_1()
 8645                                    .py_1()
 8646                                    .px_2()
 8647                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8648                                    .border_l_1()
 8649                                    .border_color(cx.theme().colors().border)
 8650                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8651                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8652                                        el.child(
 8653                                            Label::new("Hold")
 8654                                                .size(LabelSize::Small)
 8655                                                .when(accept_keystroke.is_none(), |el| {
 8656                                                    el.strikethrough()
 8657                                                })
 8658                                                .line_height_style(LineHeightStyle::UiLabel),
 8659                                        )
 8660                                    })
 8661                                    .id("edit_prediction_cursor_popover_keybind")
 8662                                    .when(accept_keystroke.is_none(), |el| {
 8663                                        let status_colors = cx.theme().status();
 8664
 8665                                        el.bg(status_colors.error_background)
 8666                                            .border_color(status_colors.error.opacity(0.6))
 8667                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8668                                            .cursor_default()
 8669                                            .hoverable_tooltip(move |_window, cx| {
 8670                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8671                                                    .into()
 8672                                            })
 8673                                    })
 8674                                    .when_some(
 8675                                        accept_keystroke.as_ref(),
 8676                                        |el, accept_keystroke| {
 8677                                            el.child(h_flex().children(ui::render_modifiers(
 8678                                                &accept_keystroke.modifiers,
 8679                                                PlatformStyle::platform(),
 8680                                                Some(Color::Default),
 8681                                                Some(IconSize::XSmall.rems().into()),
 8682                                                false,
 8683                                            )))
 8684                                        },
 8685                                    ),
 8686                            )
 8687                            .into_any(),
 8688                    );
 8689                }
 8690
 8691                self.render_edit_prediction_cursor_popover_preview(
 8692                    prediction,
 8693                    cursor_point,
 8694                    style,
 8695                    cx,
 8696                )?
 8697            }
 8698
 8699            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8700                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8701                    stale_completion,
 8702                    cursor_point,
 8703                    style,
 8704                    cx,
 8705                )?,
 8706
 8707                None => {
 8708                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8709                }
 8710            },
 8711
 8712            None => pending_completion_container().child(Label::new("No Prediction")),
 8713        };
 8714
 8715        let completion = if is_refreshing {
 8716            completion
 8717                .with_animation(
 8718                    "loading-completion",
 8719                    Animation::new(Duration::from_secs(2))
 8720                        .repeat()
 8721                        .with_easing(pulsating_between(0.4, 0.8)),
 8722                    |label, delta| label.opacity(delta),
 8723                )
 8724                .into_any_element()
 8725        } else {
 8726            completion.into_any_element()
 8727        };
 8728
 8729        let has_completion = self.active_inline_completion.is_some();
 8730
 8731        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8732        Some(
 8733            h_flex()
 8734                .min_w(min_width)
 8735                .max_w(max_width)
 8736                .flex_1()
 8737                .elevation_2(cx)
 8738                .border_color(cx.theme().colors().border)
 8739                .child(
 8740                    div()
 8741                        .flex_1()
 8742                        .py_1()
 8743                        .px_2()
 8744                        .overflow_hidden()
 8745                        .child(completion),
 8746                )
 8747                .when_some(accept_keystroke, |el, accept_keystroke| {
 8748                    if !accept_keystroke.modifiers.modified() {
 8749                        return el;
 8750                    }
 8751
 8752                    el.child(
 8753                        h_flex()
 8754                            .h_full()
 8755                            .border_l_1()
 8756                            .rounded_r_lg()
 8757                            .border_color(cx.theme().colors().border)
 8758                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8759                            .gap_1()
 8760                            .py_1()
 8761                            .px_2()
 8762                            .child(
 8763                                h_flex()
 8764                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8765                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8766                                    .child(h_flex().children(ui::render_modifiers(
 8767                                        &accept_keystroke.modifiers,
 8768                                        PlatformStyle::platform(),
 8769                                        Some(if !has_completion {
 8770                                            Color::Muted
 8771                                        } else {
 8772                                            Color::Default
 8773                                        }),
 8774                                        None,
 8775                                        false,
 8776                                    ))),
 8777                            )
 8778                            .child(Label::new("Preview").into_any_element())
 8779                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8780                    )
 8781                })
 8782                .into_any(),
 8783        )
 8784    }
 8785
 8786    fn render_edit_prediction_cursor_popover_preview(
 8787        &self,
 8788        completion: &InlineCompletionState,
 8789        cursor_point: Point,
 8790        style: &EditorStyle,
 8791        cx: &mut Context<Editor>,
 8792    ) -> Option<Div> {
 8793        use text::ToPoint as _;
 8794
 8795        fn render_relative_row_jump(
 8796            prefix: impl Into<String>,
 8797            current_row: u32,
 8798            target_row: u32,
 8799        ) -> Div {
 8800            let (row_diff, arrow) = if target_row < current_row {
 8801                (current_row - target_row, IconName::ArrowUp)
 8802            } else {
 8803                (target_row - current_row, IconName::ArrowDown)
 8804            };
 8805
 8806            h_flex()
 8807                .child(
 8808                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8809                        .color(Color::Muted)
 8810                        .size(LabelSize::Small),
 8811                )
 8812                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8813        }
 8814
 8815        match &completion.completion {
 8816            InlineCompletion::Move {
 8817                target, snapshot, ..
 8818            } => Some(
 8819                h_flex()
 8820                    .px_2()
 8821                    .gap_2()
 8822                    .flex_1()
 8823                    .child(
 8824                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8825                            Icon::new(IconName::ZedPredictDown)
 8826                        } else {
 8827                            Icon::new(IconName::ZedPredictUp)
 8828                        },
 8829                    )
 8830                    .child(Label::new("Jump to Edit")),
 8831            ),
 8832
 8833            InlineCompletion::Edit {
 8834                edits,
 8835                edit_preview,
 8836                snapshot,
 8837                display_mode: _,
 8838            } => {
 8839                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8840
 8841                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8842                    &snapshot,
 8843                    &edits,
 8844                    edit_preview.as_ref()?,
 8845                    true,
 8846                    cx,
 8847                )
 8848                .first_line_preview();
 8849
 8850                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8851                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8852
 8853                let preview = h_flex()
 8854                    .gap_1()
 8855                    .min_w_16()
 8856                    .child(styled_text)
 8857                    .when(has_more_lines, |parent| parent.child(""));
 8858
 8859                let left = if first_edit_row != cursor_point.row {
 8860                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8861                        .into_any_element()
 8862                } else {
 8863                    Icon::new(IconName::ZedPredict).into_any_element()
 8864                };
 8865
 8866                Some(
 8867                    h_flex()
 8868                        .h_full()
 8869                        .flex_1()
 8870                        .gap_2()
 8871                        .pr_1()
 8872                        .overflow_x_hidden()
 8873                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8874                        .child(left)
 8875                        .child(preview),
 8876                )
 8877            }
 8878        }
 8879    }
 8880
 8881    pub fn render_context_menu(
 8882        &self,
 8883        style: &EditorStyle,
 8884        max_height_in_lines: u32,
 8885        window: &mut Window,
 8886        cx: &mut Context<Editor>,
 8887    ) -> Option<AnyElement> {
 8888        let menu = self.context_menu.borrow();
 8889        let menu = menu.as_ref()?;
 8890        if !menu.visible() {
 8891            return None;
 8892        };
 8893        Some(menu.render(style, max_height_in_lines, window, cx))
 8894    }
 8895
 8896    fn render_context_menu_aside(
 8897        &mut self,
 8898        max_size: Size<Pixels>,
 8899        window: &mut Window,
 8900        cx: &mut Context<Editor>,
 8901    ) -> Option<AnyElement> {
 8902        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8903            if menu.visible() {
 8904                menu.render_aside(max_size, window, cx)
 8905            } else {
 8906                None
 8907            }
 8908        })
 8909    }
 8910
 8911    fn hide_context_menu(
 8912        &mut self,
 8913        window: &mut Window,
 8914        cx: &mut Context<Self>,
 8915    ) -> Option<CodeContextMenu> {
 8916        cx.notify();
 8917        self.completion_tasks.clear();
 8918        let context_menu = self.context_menu.borrow_mut().take();
 8919        self.stale_inline_completion_in_menu.take();
 8920        self.update_visible_inline_completion(window, cx);
 8921        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 8922            if let Some(completion_provider) = &self.completion_provider {
 8923                completion_provider.selection_changed(None, window, cx);
 8924            }
 8925        }
 8926        context_menu
 8927    }
 8928
 8929    fn show_snippet_choices(
 8930        &mut self,
 8931        choices: &Vec<String>,
 8932        selection: Range<Anchor>,
 8933        cx: &mut Context<Self>,
 8934    ) {
 8935        if selection.start.buffer_id.is_none() {
 8936            return;
 8937        }
 8938        let buffer_id = selection.start.buffer_id.unwrap();
 8939        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8940        let id = post_inc(&mut self.next_completion_id);
 8941        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8942
 8943        if let Some(buffer) = buffer {
 8944            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8945                CompletionsMenu::new_snippet_choices(
 8946                    id,
 8947                    true,
 8948                    choices,
 8949                    selection,
 8950                    buffer,
 8951                    snippet_sort_order,
 8952                ),
 8953            ));
 8954        }
 8955    }
 8956
 8957    pub fn insert_snippet(
 8958        &mut self,
 8959        insertion_ranges: &[Range<usize>],
 8960        snippet: Snippet,
 8961        window: &mut Window,
 8962        cx: &mut Context<Self>,
 8963    ) -> Result<()> {
 8964        struct Tabstop<T> {
 8965            is_end_tabstop: bool,
 8966            ranges: Vec<Range<T>>,
 8967            choices: Option<Vec<String>>,
 8968        }
 8969
 8970        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8971            let snippet_text: Arc<str> = snippet.text.clone().into();
 8972            let edits = insertion_ranges
 8973                .iter()
 8974                .cloned()
 8975                .map(|range| (range, snippet_text.clone()));
 8976            let autoindent_mode = AutoindentMode::Block {
 8977                original_indent_columns: Vec::new(),
 8978            };
 8979            buffer.edit(edits, Some(autoindent_mode), cx);
 8980
 8981            let snapshot = &*buffer.read(cx);
 8982            let snippet = &snippet;
 8983            snippet
 8984                .tabstops
 8985                .iter()
 8986                .map(|tabstop| {
 8987                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8988                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8989                    });
 8990                    let mut tabstop_ranges = tabstop
 8991                        .ranges
 8992                        .iter()
 8993                        .flat_map(|tabstop_range| {
 8994                            let mut delta = 0_isize;
 8995                            insertion_ranges.iter().map(move |insertion_range| {
 8996                                let insertion_start = insertion_range.start as isize + delta;
 8997                                delta +=
 8998                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8999
 9000                                let start = ((insertion_start + tabstop_range.start) as usize)
 9001                                    .min(snapshot.len());
 9002                                let end = ((insertion_start + tabstop_range.end) as usize)
 9003                                    .min(snapshot.len());
 9004                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9005                            })
 9006                        })
 9007                        .collect::<Vec<_>>();
 9008                    // Sort in reverse order so that the first range is the newest created
 9009                    // selection. Completions will use it and autoscroll will prioritize it.
 9010                    tabstop_ranges.sort_unstable_by(|a, b| b.start.cmp(&a.start, snapshot));
 9011
 9012                    Tabstop {
 9013                        is_end_tabstop,
 9014                        ranges: tabstop_ranges,
 9015                        choices: tabstop.choices.clone(),
 9016                    }
 9017                })
 9018                .collect::<Vec<_>>()
 9019        });
 9020        if let Some(tabstop) = tabstops.first() {
 9021            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9022                s.select_ranges(tabstop.ranges.iter().cloned());
 9023            });
 9024
 9025            if let Some(choices) = &tabstop.choices {
 9026                if let Some(selection) = tabstop.ranges.first() {
 9027                    self.show_snippet_choices(choices, selection.clone(), cx)
 9028                }
 9029            }
 9030
 9031            // If we're already at the last tabstop and it's at the end of the snippet,
 9032            // we're done, we don't need to keep the state around.
 9033            if !tabstop.is_end_tabstop {
 9034                let choices = tabstops
 9035                    .iter()
 9036                    .map(|tabstop| tabstop.choices.clone())
 9037                    .collect();
 9038
 9039                let ranges = tabstops
 9040                    .into_iter()
 9041                    .map(|tabstop| tabstop.ranges)
 9042                    .collect::<Vec<_>>();
 9043
 9044                self.snippet_stack.push(SnippetState {
 9045                    active_index: 0,
 9046                    ranges,
 9047                    choices,
 9048                });
 9049            }
 9050
 9051            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9052            if self.autoclose_regions.is_empty() {
 9053                let snapshot = self.buffer.read(cx).snapshot(cx);
 9054                for selection in &mut self.selections.all::<Point>(cx) {
 9055                    let selection_head = selection.head();
 9056                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9057                        continue;
 9058                    };
 9059
 9060                    let mut bracket_pair = None;
 9061                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9062                    let prev_chars = snapshot
 9063                        .reversed_chars_at(selection_head)
 9064                        .collect::<String>();
 9065                    for (pair, enabled) in scope.brackets() {
 9066                        if enabled
 9067                            && pair.close
 9068                            && prev_chars.starts_with(pair.start.as_str())
 9069                            && next_chars.starts_with(pair.end.as_str())
 9070                        {
 9071                            bracket_pair = Some(pair.clone());
 9072                            break;
 9073                        }
 9074                    }
 9075                    if let Some(pair) = bracket_pair {
 9076                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9077                        let autoclose_enabled =
 9078                            self.use_autoclose && snapshot_settings.use_autoclose;
 9079                        if autoclose_enabled {
 9080                            let start = snapshot.anchor_after(selection_head);
 9081                            let end = snapshot.anchor_after(selection_head);
 9082                            self.autoclose_regions.push(AutocloseRegion {
 9083                                selection_id: selection.id,
 9084                                range: start..end,
 9085                                pair,
 9086                            });
 9087                        }
 9088                    }
 9089                }
 9090            }
 9091        }
 9092        Ok(())
 9093    }
 9094
 9095    pub fn move_to_next_snippet_tabstop(
 9096        &mut self,
 9097        window: &mut Window,
 9098        cx: &mut Context<Self>,
 9099    ) -> bool {
 9100        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9101    }
 9102
 9103    pub fn move_to_prev_snippet_tabstop(
 9104        &mut self,
 9105        window: &mut Window,
 9106        cx: &mut Context<Self>,
 9107    ) -> bool {
 9108        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9109    }
 9110
 9111    pub fn move_to_snippet_tabstop(
 9112        &mut self,
 9113        bias: Bias,
 9114        window: &mut Window,
 9115        cx: &mut Context<Self>,
 9116    ) -> bool {
 9117        if let Some(mut snippet) = self.snippet_stack.pop() {
 9118            match bias {
 9119                Bias::Left => {
 9120                    if snippet.active_index > 0 {
 9121                        snippet.active_index -= 1;
 9122                    } else {
 9123                        self.snippet_stack.push(snippet);
 9124                        return false;
 9125                    }
 9126                }
 9127                Bias::Right => {
 9128                    if snippet.active_index + 1 < snippet.ranges.len() {
 9129                        snippet.active_index += 1;
 9130                    } else {
 9131                        self.snippet_stack.push(snippet);
 9132                        return false;
 9133                    }
 9134                }
 9135            }
 9136            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9137                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9138                    s.select_ranges(current_ranges.iter().cloned())
 9139                });
 9140
 9141                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9142                    if let Some(selection) = current_ranges.first() {
 9143                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9144                    }
 9145                }
 9146
 9147                // If snippet state is not at the last tabstop, push it back on the stack
 9148                if snippet.active_index + 1 < snippet.ranges.len() {
 9149                    self.snippet_stack.push(snippet);
 9150                }
 9151                return true;
 9152            }
 9153        }
 9154
 9155        false
 9156    }
 9157
 9158    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9159        self.transact(window, cx, |this, window, cx| {
 9160            this.select_all(&SelectAll, window, cx);
 9161            this.insert("", window, cx);
 9162        });
 9163    }
 9164
 9165    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9166        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9167        self.transact(window, cx, |this, window, cx| {
 9168            this.select_autoclose_pair(window, cx);
 9169            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9170            if !this.linked_edit_ranges.is_empty() {
 9171                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9172                let snapshot = this.buffer.read(cx).snapshot(cx);
 9173
 9174                for selection in selections.iter() {
 9175                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9176                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9177                    if selection_start.buffer_id != selection_end.buffer_id {
 9178                        continue;
 9179                    }
 9180                    if let Some(ranges) =
 9181                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9182                    {
 9183                        for (buffer, entries) in ranges {
 9184                            linked_ranges.entry(buffer).or_default().extend(entries);
 9185                        }
 9186                    }
 9187                }
 9188            }
 9189
 9190            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9191            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9192            for selection in &mut selections {
 9193                if selection.is_empty() {
 9194                    let old_head = selection.head();
 9195                    let mut new_head =
 9196                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9197                            .to_point(&display_map);
 9198                    if let Some((buffer, line_buffer_range)) = display_map
 9199                        .buffer_snapshot
 9200                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9201                    {
 9202                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9203                        let indent_len = match indent_size.kind {
 9204                            IndentKind::Space => {
 9205                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9206                            }
 9207                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9208                        };
 9209                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9210                            let indent_len = indent_len.get();
 9211                            new_head = cmp::min(
 9212                                new_head,
 9213                                MultiBufferPoint::new(
 9214                                    old_head.row,
 9215                                    ((old_head.column - 1) / indent_len) * indent_len,
 9216                                ),
 9217                            );
 9218                        }
 9219                    }
 9220
 9221                    selection.set_head(new_head, SelectionGoal::None);
 9222                }
 9223            }
 9224
 9225            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9226                s.select(selections)
 9227            });
 9228            this.insert("", window, cx);
 9229            let empty_str: Arc<str> = Arc::from("");
 9230            for (buffer, edits) in linked_ranges {
 9231                let snapshot = buffer.read(cx).snapshot();
 9232                use text::ToPoint as TP;
 9233
 9234                let edits = edits
 9235                    .into_iter()
 9236                    .map(|range| {
 9237                        let end_point = TP::to_point(&range.end, &snapshot);
 9238                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9239
 9240                        if end_point == start_point {
 9241                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9242                                .saturating_sub(1);
 9243                            start_point =
 9244                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9245                        };
 9246
 9247                        (start_point..end_point, empty_str.clone())
 9248                    })
 9249                    .sorted_by_key(|(range, _)| range.start)
 9250                    .collect::<Vec<_>>();
 9251                buffer.update(cx, |this, cx| {
 9252                    this.edit(edits, None, cx);
 9253                })
 9254            }
 9255            this.refresh_inline_completion(true, false, window, cx);
 9256            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9257        });
 9258    }
 9259
 9260    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9261        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9262        self.transact(window, cx, |this, window, cx| {
 9263            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9264                s.move_with(|map, selection| {
 9265                    if selection.is_empty() {
 9266                        let cursor = movement::right(map, selection.head());
 9267                        selection.end = cursor;
 9268                        selection.reversed = true;
 9269                        selection.goal = SelectionGoal::None;
 9270                    }
 9271                })
 9272            });
 9273            this.insert("", window, cx);
 9274            this.refresh_inline_completion(true, false, window, cx);
 9275        });
 9276    }
 9277
 9278    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9279        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9280        if self.move_to_prev_snippet_tabstop(window, cx) {
 9281            return;
 9282        }
 9283        self.outdent(&Outdent, window, cx);
 9284    }
 9285
 9286    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9287        if self.move_to_next_snippet_tabstop(window, cx) {
 9288            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9289            return;
 9290        }
 9291        if self.read_only(cx) {
 9292            return;
 9293        }
 9294        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9295        let mut selections = self.selections.all_adjusted(cx);
 9296        let buffer = self.buffer.read(cx);
 9297        let snapshot = buffer.snapshot(cx);
 9298        let rows_iter = selections.iter().map(|s| s.head().row);
 9299        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9300
 9301        let has_some_cursor_in_whitespace = selections
 9302            .iter()
 9303            .filter(|selection| selection.is_empty())
 9304            .any(|selection| {
 9305                let cursor = selection.head();
 9306                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9307                cursor.column < current_indent.len
 9308            });
 9309
 9310        let mut edits = Vec::new();
 9311        let mut prev_edited_row = 0;
 9312        let mut row_delta = 0;
 9313        for selection in &mut selections {
 9314            if selection.start.row != prev_edited_row {
 9315                row_delta = 0;
 9316            }
 9317            prev_edited_row = selection.end.row;
 9318
 9319            // If the selection is non-empty, then increase the indentation of the selected lines.
 9320            if !selection.is_empty() {
 9321                row_delta =
 9322                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9323                continue;
 9324            }
 9325
 9326            let cursor = selection.head();
 9327            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9328            if let Some(suggested_indent) =
 9329                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9330            {
 9331                // Don't do anything if already at suggested indent
 9332                // and there is any other cursor which is not
 9333                if has_some_cursor_in_whitespace
 9334                    && cursor.column == current_indent.len
 9335                    && current_indent.len == suggested_indent.len
 9336                {
 9337                    continue;
 9338                }
 9339
 9340                // Adjust line and move cursor to suggested indent
 9341                // if cursor is not at suggested indent
 9342                if cursor.column < suggested_indent.len
 9343                    && cursor.column <= current_indent.len
 9344                    && current_indent.len <= suggested_indent.len
 9345                {
 9346                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9347                    selection.end = selection.start;
 9348                    if row_delta == 0 {
 9349                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9350                            cursor.row,
 9351                            current_indent,
 9352                            suggested_indent,
 9353                        ));
 9354                        row_delta = suggested_indent.len - current_indent.len;
 9355                    }
 9356                    continue;
 9357                }
 9358
 9359                // If current indent is more than suggested indent
 9360                // only move cursor to current indent and skip indent
 9361                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9362                    selection.start = Point::new(cursor.row, current_indent.len);
 9363                    selection.end = selection.start;
 9364                    continue;
 9365                }
 9366            }
 9367
 9368            // Otherwise, insert a hard or soft tab.
 9369            let settings = buffer.language_settings_at(cursor, cx);
 9370            let tab_size = if settings.hard_tabs {
 9371                IndentSize::tab()
 9372            } else {
 9373                let tab_size = settings.tab_size.get();
 9374                let indent_remainder = snapshot
 9375                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9376                    .flat_map(str::chars)
 9377                    .fold(row_delta % tab_size, |counter: u32, c| {
 9378                        if c == '\t' {
 9379                            0
 9380                        } else {
 9381                            (counter + 1) % tab_size
 9382                        }
 9383                    });
 9384
 9385                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9386                IndentSize::spaces(chars_to_next_tab_stop)
 9387            };
 9388            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9389            selection.end = selection.start;
 9390            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9391            row_delta += tab_size.len;
 9392        }
 9393
 9394        self.transact(window, cx, |this, window, cx| {
 9395            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9396            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9397                s.select(selections)
 9398            });
 9399            this.refresh_inline_completion(true, false, window, cx);
 9400        });
 9401    }
 9402
 9403    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9404        if self.read_only(cx) {
 9405            return;
 9406        }
 9407        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9408        let mut selections = self.selections.all::<Point>(cx);
 9409        let mut prev_edited_row = 0;
 9410        let mut row_delta = 0;
 9411        let mut edits = Vec::new();
 9412        let buffer = self.buffer.read(cx);
 9413        let snapshot = buffer.snapshot(cx);
 9414        for selection in &mut selections {
 9415            if selection.start.row != prev_edited_row {
 9416                row_delta = 0;
 9417            }
 9418            prev_edited_row = selection.end.row;
 9419
 9420            row_delta =
 9421                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9422        }
 9423
 9424        self.transact(window, cx, |this, window, cx| {
 9425            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9426            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9427                s.select(selections)
 9428            });
 9429        });
 9430    }
 9431
 9432    fn indent_selection(
 9433        buffer: &MultiBuffer,
 9434        snapshot: &MultiBufferSnapshot,
 9435        selection: &mut Selection<Point>,
 9436        edits: &mut Vec<(Range<Point>, String)>,
 9437        delta_for_start_row: u32,
 9438        cx: &App,
 9439    ) -> u32 {
 9440        let settings = buffer.language_settings_at(selection.start, cx);
 9441        let tab_size = settings.tab_size.get();
 9442        let indent_kind = if settings.hard_tabs {
 9443            IndentKind::Tab
 9444        } else {
 9445            IndentKind::Space
 9446        };
 9447        let mut start_row = selection.start.row;
 9448        let mut end_row = selection.end.row + 1;
 9449
 9450        // If a selection ends at the beginning of a line, don't indent
 9451        // that last line.
 9452        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9453            end_row -= 1;
 9454        }
 9455
 9456        // Avoid re-indenting a row that has already been indented by a
 9457        // previous selection, but still update this selection's column
 9458        // to reflect that indentation.
 9459        if delta_for_start_row > 0 {
 9460            start_row += 1;
 9461            selection.start.column += delta_for_start_row;
 9462            if selection.end.row == selection.start.row {
 9463                selection.end.column += delta_for_start_row;
 9464            }
 9465        }
 9466
 9467        let mut delta_for_end_row = 0;
 9468        let has_multiple_rows = start_row + 1 != end_row;
 9469        for row in start_row..end_row {
 9470            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9471            let indent_delta = match (current_indent.kind, indent_kind) {
 9472                (IndentKind::Space, IndentKind::Space) => {
 9473                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9474                    IndentSize::spaces(columns_to_next_tab_stop)
 9475                }
 9476                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9477                (_, IndentKind::Tab) => IndentSize::tab(),
 9478            };
 9479
 9480            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9481                0
 9482            } else {
 9483                selection.start.column
 9484            };
 9485            let row_start = Point::new(row, start);
 9486            edits.push((
 9487                row_start..row_start,
 9488                indent_delta.chars().collect::<String>(),
 9489            ));
 9490
 9491            // Update this selection's endpoints to reflect the indentation.
 9492            if row == selection.start.row {
 9493                selection.start.column += indent_delta.len;
 9494            }
 9495            if row == selection.end.row {
 9496                selection.end.column += indent_delta.len;
 9497                delta_for_end_row = indent_delta.len;
 9498            }
 9499        }
 9500
 9501        if selection.start.row == selection.end.row {
 9502            delta_for_start_row + delta_for_end_row
 9503        } else {
 9504            delta_for_end_row
 9505        }
 9506    }
 9507
 9508    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9509        if self.read_only(cx) {
 9510            return;
 9511        }
 9512        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9513        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9514        let selections = self.selections.all::<Point>(cx);
 9515        let mut deletion_ranges = Vec::new();
 9516        let mut last_outdent = None;
 9517        {
 9518            let buffer = self.buffer.read(cx);
 9519            let snapshot = buffer.snapshot(cx);
 9520            for selection in &selections {
 9521                let settings = buffer.language_settings_at(selection.start, cx);
 9522                let tab_size = settings.tab_size.get();
 9523                let mut rows = selection.spanned_rows(false, &display_map);
 9524
 9525                // Avoid re-outdenting a row that has already been outdented by a
 9526                // previous selection.
 9527                if let Some(last_row) = last_outdent {
 9528                    if last_row == rows.start {
 9529                        rows.start = rows.start.next_row();
 9530                    }
 9531                }
 9532                let has_multiple_rows = rows.len() > 1;
 9533                for row in rows.iter_rows() {
 9534                    let indent_size = snapshot.indent_size_for_line(row);
 9535                    if indent_size.len > 0 {
 9536                        let deletion_len = match indent_size.kind {
 9537                            IndentKind::Space => {
 9538                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9539                                if columns_to_prev_tab_stop == 0 {
 9540                                    tab_size
 9541                                } else {
 9542                                    columns_to_prev_tab_stop
 9543                                }
 9544                            }
 9545                            IndentKind::Tab => 1,
 9546                        };
 9547                        let start = if has_multiple_rows
 9548                            || deletion_len > selection.start.column
 9549                            || indent_size.len < selection.start.column
 9550                        {
 9551                            0
 9552                        } else {
 9553                            selection.start.column - deletion_len
 9554                        };
 9555                        deletion_ranges.push(
 9556                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9557                        );
 9558                        last_outdent = Some(row);
 9559                    }
 9560                }
 9561            }
 9562        }
 9563
 9564        self.transact(window, cx, |this, window, cx| {
 9565            this.buffer.update(cx, |buffer, cx| {
 9566                let empty_str: Arc<str> = Arc::default();
 9567                buffer.edit(
 9568                    deletion_ranges
 9569                        .into_iter()
 9570                        .map(|range| (range, empty_str.clone())),
 9571                    None,
 9572                    cx,
 9573                );
 9574            });
 9575            let selections = this.selections.all::<usize>(cx);
 9576            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9577                s.select(selections)
 9578            });
 9579        });
 9580    }
 9581
 9582    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9583        if self.read_only(cx) {
 9584            return;
 9585        }
 9586        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9587        let selections = self
 9588            .selections
 9589            .all::<usize>(cx)
 9590            .into_iter()
 9591            .map(|s| s.range());
 9592
 9593        self.transact(window, cx, |this, window, cx| {
 9594            this.buffer.update(cx, |buffer, cx| {
 9595                buffer.autoindent_ranges(selections, cx);
 9596            });
 9597            let selections = this.selections.all::<usize>(cx);
 9598            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9599                s.select(selections)
 9600            });
 9601        });
 9602    }
 9603
 9604    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9605        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9606        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9607        let selections = self.selections.all::<Point>(cx);
 9608
 9609        let mut new_cursors = Vec::new();
 9610        let mut edit_ranges = Vec::new();
 9611        let mut selections = selections.iter().peekable();
 9612        while let Some(selection) = selections.next() {
 9613            let mut rows = selection.spanned_rows(false, &display_map);
 9614            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9615
 9616            // Accumulate contiguous regions of rows that we want to delete.
 9617            while let Some(next_selection) = selections.peek() {
 9618                let next_rows = next_selection.spanned_rows(false, &display_map);
 9619                if next_rows.start <= rows.end {
 9620                    rows.end = next_rows.end;
 9621                    selections.next().unwrap();
 9622                } else {
 9623                    break;
 9624                }
 9625            }
 9626
 9627            let buffer = &display_map.buffer_snapshot;
 9628            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9629            let edit_end;
 9630            let cursor_buffer_row;
 9631            if buffer.max_point().row >= rows.end.0 {
 9632                // If there's a line after the range, delete the \n from the end of the row range
 9633                // and position the cursor on the next line.
 9634                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9635                cursor_buffer_row = rows.end;
 9636            } else {
 9637                // If there isn't a line after the range, delete the \n from the line before the
 9638                // start of the row range and position the cursor there.
 9639                edit_start = edit_start.saturating_sub(1);
 9640                edit_end = buffer.len();
 9641                cursor_buffer_row = rows.start.previous_row();
 9642            }
 9643
 9644            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9645            *cursor.column_mut() =
 9646                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9647
 9648            new_cursors.push((
 9649                selection.id,
 9650                buffer.anchor_after(cursor.to_point(&display_map)),
 9651            ));
 9652            edit_ranges.push(edit_start..edit_end);
 9653        }
 9654
 9655        self.transact(window, cx, |this, window, cx| {
 9656            let buffer = this.buffer.update(cx, |buffer, cx| {
 9657                let empty_str: Arc<str> = Arc::default();
 9658                buffer.edit(
 9659                    edit_ranges
 9660                        .into_iter()
 9661                        .map(|range| (range, empty_str.clone())),
 9662                    None,
 9663                    cx,
 9664                );
 9665                buffer.snapshot(cx)
 9666            });
 9667            let new_selections = new_cursors
 9668                .into_iter()
 9669                .map(|(id, cursor)| {
 9670                    let cursor = cursor.to_point(&buffer);
 9671                    Selection {
 9672                        id,
 9673                        start: cursor,
 9674                        end: cursor,
 9675                        reversed: false,
 9676                        goal: SelectionGoal::None,
 9677                    }
 9678                })
 9679                .collect();
 9680
 9681            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9682                s.select(new_selections);
 9683            });
 9684        });
 9685    }
 9686
 9687    pub fn join_lines_impl(
 9688        &mut self,
 9689        insert_whitespace: bool,
 9690        window: &mut Window,
 9691        cx: &mut Context<Self>,
 9692    ) {
 9693        if self.read_only(cx) {
 9694            return;
 9695        }
 9696        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9697        for selection in self.selections.all::<Point>(cx) {
 9698            let start = MultiBufferRow(selection.start.row);
 9699            // Treat single line selections as if they include the next line. Otherwise this action
 9700            // would do nothing for single line selections individual cursors.
 9701            let end = if selection.start.row == selection.end.row {
 9702                MultiBufferRow(selection.start.row + 1)
 9703            } else {
 9704                MultiBufferRow(selection.end.row)
 9705            };
 9706
 9707            if let Some(last_row_range) = row_ranges.last_mut() {
 9708                if start <= last_row_range.end {
 9709                    last_row_range.end = end;
 9710                    continue;
 9711                }
 9712            }
 9713            row_ranges.push(start..end);
 9714        }
 9715
 9716        let snapshot = self.buffer.read(cx).snapshot(cx);
 9717        let mut cursor_positions = Vec::new();
 9718        for row_range in &row_ranges {
 9719            let anchor = snapshot.anchor_before(Point::new(
 9720                row_range.end.previous_row().0,
 9721                snapshot.line_len(row_range.end.previous_row()),
 9722            ));
 9723            cursor_positions.push(anchor..anchor);
 9724        }
 9725
 9726        self.transact(window, cx, |this, window, cx| {
 9727            for row_range in row_ranges.into_iter().rev() {
 9728                for row in row_range.iter_rows().rev() {
 9729                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9730                    let next_line_row = row.next_row();
 9731                    let indent = snapshot.indent_size_for_line(next_line_row);
 9732                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9733
 9734                    let replace =
 9735                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9736                            " "
 9737                        } else {
 9738                            ""
 9739                        };
 9740
 9741                    this.buffer.update(cx, |buffer, cx| {
 9742                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9743                    });
 9744                }
 9745            }
 9746
 9747            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9748                s.select_anchor_ranges(cursor_positions)
 9749            });
 9750        });
 9751    }
 9752
 9753    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9754        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9755        self.join_lines_impl(true, window, cx);
 9756    }
 9757
 9758    pub fn sort_lines_case_sensitive(
 9759        &mut self,
 9760        _: &SortLinesCaseSensitive,
 9761        window: &mut Window,
 9762        cx: &mut Context<Self>,
 9763    ) {
 9764        self.manipulate_lines(window, cx, |lines| lines.sort())
 9765    }
 9766
 9767    pub fn sort_lines_case_insensitive(
 9768        &mut self,
 9769        _: &SortLinesCaseInsensitive,
 9770        window: &mut Window,
 9771        cx: &mut Context<Self>,
 9772    ) {
 9773        self.manipulate_lines(window, cx, |lines| {
 9774            lines.sort_by_key(|line| line.to_lowercase())
 9775        })
 9776    }
 9777
 9778    pub fn unique_lines_case_insensitive(
 9779        &mut self,
 9780        _: &UniqueLinesCaseInsensitive,
 9781        window: &mut Window,
 9782        cx: &mut Context<Self>,
 9783    ) {
 9784        self.manipulate_lines(window, cx, |lines| {
 9785            let mut seen = HashSet::default();
 9786            lines.retain(|line| seen.insert(line.to_lowercase()));
 9787        })
 9788    }
 9789
 9790    pub fn unique_lines_case_sensitive(
 9791        &mut self,
 9792        _: &UniqueLinesCaseSensitive,
 9793        window: &mut Window,
 9794        cx: &mut Context<Self>,
 9795    ) {
 9796        self.manipulate_lines(window, cx, |lines| {
 9797            let mut seen = HashSet::default();
 9798            lines.retain(|line| seen.insert(*line));
 9799        })
 9800    }
 9801
 9802    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9803        let Some(project) = self.project.clone() else {
 9804            return;
 9805        };
 9806        self.reload(project, window, cx)
 9807            .detach_and_notify_err(window, cx);
 9808    }
 9809
 9810    pub fn restore_file(
 9811        &mut self,
 9812        _: &::git::RestoreFile,
 9813        window: &mut Window,
 9814        cx: &mut Context<Self>,
 9815    ) {
 9816        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9817        let mut buffer_ids = HashSet::default();
 9818        let snapshot = self.buffer().read(cx).snapshot(cx);
 9819        for selection in self.selections.all::<usize>(cx) {
 9820            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9821        }
 9822
 9823        let buffer = self.buffer().read(cx);
 9824        let ranges = buffer_ids
 9825            .into_iter()
 9826            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9827            .collect::<Vec<_>>();
 9828
 9829        self.restore_hunks_in_ranges(ranges, window, cx);
 9830    }
 9831
 9832    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9833        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9834        let selections = self
 9835            .selections
 9836            .all(cx)
 9837            .into_iter()
 9838            .map(|s| s.range())
 9839            .collect();
 9840        self.restore_hunks_in_ranges(selections, window, cx);
 9841    }
 9842
 9843    pub fn restore_hunks_in_ranges(
 9844        &mut self,
 9845        ranges: Vec<Range<Point>>,
 9846        window: &mut Window,
 9847        cx: &mut Context<Editor>,
 9848    ) {
 9849        let mut revert_changes = HashMap::default();
 9850        let chunk_by = self
 9851            .snapshot(window, cx)
 9852            .hunks_for_ranges(ranges)
 9853            .into_iter()
 9854            .chunk_by(|hunk| hunk.buffer_id);
 9855        for (buffer_id, hunks) in &chunk_by {
 9856            let hunks = hunks.collect::<Vec<_>>();
 9857            for hunk in &hunks {
 9858                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9859            }
 9860            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9861        }
 9862        drop(chunk_by);
 9863        if !revert_changes.is_empty() {
 9864            self.transact(window, cx, |editor, window, cx| {
 9865                editor.restore(revert_changes, window, cx);
 9866            });
 9867        }
 9868    }
 9869
 9870    pub fn open_active_item_in_terminal(
 9871        &mut self,
 9872        _: &OpenInTerminal,
 9873        window: &mut Window,
 9874        cx: &mut Context<Self>,
 9875    ) {
 9876        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9877            let project_path = buffer.read(cx).project_path(cx)?;
 9878            let project = self.project.as_ref()?.read(cx);
 9879            let entry = project.entry_for_path(&project_path, cx)?;
 9880            let parent = match &entry.canonical_path {
 9881                Some(canonical_path) => canonical_path.to_path_buf(),
 9882                None => project.absolute_path(&project_path, cx)?,
 9883            }
 9884            .parent()?
 9885            .to_path_buf();
 9886            Some(parent)
 9887        }) {
 9888            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9889        }
 9890    }
 9891
 9892    fn set_breakpoint_context_menu(
 9893        &mut self,
 9894        display_row: DisplayRow,
 9895        position: Option<Anchor>,
 9896        clicked_point: gpui::Point<Pixels>,
 9897        window: &mut Window,
 9898        cx: &mut Context<Self>,
 9899    ) {
 9900        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9901            return;
 9902        }
 9903        let source = self
 9904            .buffer
 9905            .read(cx)
 9906            .snapshot(cx)
 9907            .anchor_before(Point::new(display_row.0, 0u32));
 9908
 9909        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9910
 9911        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9912            self,
 9913            source,
 9914            clicked_point,
 9915            context_menu,
 9916            window,
 9917            cx,
 9918        );
 9919    }
 9920
 9921    fn add_edit_breakpoint_block(
 9922        &mut self,
 9923        anchor: Anchor,
 9924        breakpoint: &Breakpoint,
 9925        edit_action: BreakpointPromptEditAction,
 9926        window: &mut Window,
 9927        cx: &mut Context<Self>,
 9928    ) {
 9929        let weak_editor = cx.weak_entity();
 9930        let bp_prompt = cx.new(|cx| {
 9931            BreakpointPromptEditor::new(
 9932                weak_editor,
 9933                anchor,
 9934                breakpoint.clone(),
 9935                edit_action,
 9936                window,
 9937                cx,
 9938            )
 9939        });
 9940
 9941        let height = bp_prompt.update(cx, |this, cx| {
 9942            this.prompt
 9943                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9944        });
 9945        let cloned_prompt = bp_prompt.clone();
 9946        let blocks = vec![BlockProperties {
 9947            style: BlockStyle::Sticky,
 9948            placement: BlockPlacement::Above(anchor),
 9949            height: Some(height),
 9950            render: Arc::new(move |cx| {
 9951                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9952                cloned_prompt.clone().into_any_element()
 9953            }),
 9954            priority: 0,
 9955            render_in_minimap: true,
 9956        }];
 9957
 9958        let focus_handle = bp_prompt.focus_handle(cx);
 9959        window.focus(&focus_handle);
 9960
 9961        let block_ids = self.insert_blocks(blocks, None, cx);
 9962        bp_prompt.update(cx, |prompt, _| {
 9963            prompt.add_block_ids(block_ids);
 9964        });
 9965    }
 9966
 9967    pub(crate) fn breakpoint_at_row(
 9968        &self,
 9969        row: u32,
 9970        window: &mut Window,
 9971        cx: &mut Context<Self>,
 9972    ) -> Option<(Anchor, Breakpoint)> {
 9973        let snapshot = self.snapshot(window, cx);
 9974        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9975
 9976        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9977    }
 9978
 9979    pub(crate) fn breakpoint_at_anchor(
 9980        &self,
 9981        breakpoint_position: Anchor,
 9982        snapshot: &EditorSnapshot,
 9983        cx: &mut Context<Self>,
 9984    ) -> Option<(Anchor, Breakpoint)> {
 9985        let project = self.project.clone()?;
 9986
 9987        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9988            snapshot
 9989                .buffer_snapshot
 9990                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9991        })?;
 9992
 9993        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9994        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
 9995        let buffer_snapshot = buffer.read(cx).snapshot();
 9996
 9997        let row = buffer_snapshot
 9998            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9999            .row;
10000
10001        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10002        let anchor_end = snapshot
10003            .buffer_snapshot
10004            .anchor_after(Point::new(row, line_len));
10005
10006        let bp = self
10007            .breakpoint_store
10008            .as_ref()?
10009            .read_with(cx, |breakpoint_store, cx| {
10010                breakpoint_store
10011                    .breakpoints(
10012                        &buffer,
10013                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10014                        &buffer_snapshot,
10015                        cx,
10016                    )
10017                    .next()
10018                    .and_then(|(bp, _)| {
10019                        let breakpoint_row = buffer_snapshot
10020                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10021                            .row;
10022
10023                        if breakpoint_row == row {
10024                            snapshot
10025                                .buffer_snapshot
10026                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10027                                .map(|position| (position, bp.bp.clone()))
10028                        } else {
10029                            None
10030                        }
10031                    })
10032            });
10033        bp
10034    }
10035
10036    pub fn edit_log_breakpoint(
10037        &mut self,
10038        _: &EditLogBreakpoint,
10039        window: &mut Window,
10040        cx: &mut Context<Self>,
10041    ) {
10042        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10043            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10044                message: None,
10045                state: BreakpointState::Enabled,
10046                condition: None,
10047                hit_condition: None,
10048            });
10049
10050            self.add_edit_breakpoint_block(
10051                anchor,
10052                &breakpoint,
10053                BreakpointPromptEditAction::Log,
10054                window,
10055                cx,
10056            );
10057        }
10058    }
10059
10060    fn breakpoints_at_cursors(
10061        &self,
10062        window: &mut Window,
10063        cx: &mut Context<Self>,
10064    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10065        let snapshot = self.snapshot(window, cx);
10066        let cursors = self
10067            .selections
10068            .disjoint_anchors()
10069            .into_iter()
10070            .map(|selection| {
10071                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10072
10073                let breakpoint_position = self
10074                    .breakpoint_at_row(cursor_position.row, window, cx)
10075                    .map(|bp| bp.0)
10076                    .unwrap_or_else(|| {
10077                        snapshot
10078                            .display_snapshot
10079                            .buffer_snapshot
10080                            .anchor_after(Point::new(cursor_position.row, 0))
10081                    });
10082
10083                let breakpoint = self
10084                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10085                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10086
10087                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10088            })
10089            // 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.
10090            .collect::<HashMap<Anchor, _>>();
10091
10092        cursors.into_iter().collect()
10093    }
10094
10095    pub fn enable_breakpoint(
10096        &mut self,
10097        _: &crate::actions::EnableBreakpoint,
10098        window: &mut Window,
10099        cx: &mut Context<Self>,
10100    ) {
10101        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10102            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10103                continue;
10104            };
10105            self.edit_breakpoint_at_anchor(
10106                anchor,
10107                breakpoint,
10108                BreakpointEditAction::InvertState,
10109                cx,
10110            );
10111        }
10112    }
10113
10114    pub fn disable_breakpoint(
10115        &mut self,
10116        _: &crate::actions::DisableBreakpoint,
10117        window: &mut Window,
10118        cx: &mut Context<Self>,
10119    ) {
10120        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10121            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10122                continue;
10123            };
10124            self.edit_breakpoint_at_anchor(
10125                anchor,
10126                breakpoint,
10127                BreakpointEditAction::InvertState,
10128                cx,
10129            );
10130        }
10131    }
10132
10133    pub fn toggle_breakpoint(
10134        &mut self,
10135        _: &crate::actions::ToggleBreakpoint,
10136        window: &mut Window,
10137        cx: &mut Context<Self>,
10138    ) {
10139        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10140            if let Some(breakpoint) = breakpoint {
10141                self.edit_breakpoint_at_anchor(
10142                    anchor,
10143                    breakpoint,
10144                    BreakpointEditAction::Toggle,
10145                    cx,
10146                );
10147            } else {
10148                self.edit_breakpoint_at_anchor(
10149                    anchor,
10150                    Breakpoint::new_standard(),
10151                    BreakpointEditAction::Toggle,
10152                    cx,
10153                );
10154            }
10155        }
10156    }
10157
10158    pub fn edit_breakpoint_at_anchor(
10159        &mut self,
10160        breakpoint_position: Anchor,
10161        breakpoint: Breakpoint,
10162        edit_action: BreakpointEditAction,
10163        cx: &mut Context<Self>,
10164    ) {
10165        let Some(breakpoint_store) = &self.breakpoint_store else {
10166            return;
10167        };
10168
10169        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10170            if breakpoint_position == Anchor::min() {
10171                self.buffer()
10172                    .read(cx)
10173                    .excerpt_buffer_ids()
10174                    .into_iter()
10175                    .next()
10176            } else {
10177                None
10178            }
10179        }) else {
10180            return;
10181        };
10182
10183        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10184            return;
10185        };
10186
10187        breakpoint_store.update(cx, |breakpoint_store, cx| {
10188            breakpoint_store.toggle_breakpoint(
10189                buffer,
10190                BreakpointWithPosition {
10191                    position: breakpoint_position.text_anchor,
10192                    bp: breakpoint,
10193                },
10194                edit_action,
10195                cx,
10196            );
10197        });
10198
10199        cx.notify();
10200    }
10201
10202    #[cfg(any(test, feature = "test-support"))]
10203    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10204        self.breakpoint_store.clone()
10205    }
10206
10207    pub fn prepare_restore_change(
10208        &self,
10209        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10210        hunk: &MultiBufferDiffHunk,
10211        cx: &mut App,
10212    ) -> Option<()> {
10213        if hunk.is_created_file() {
10214            return None;
10215        }
10216        let buffer = self.buffer.read(cx);
10217        let diff = buffer.diff_for(hunk.buffer_id)?;
10218        let buffer = buffer.buffer(hunk.buffer_id)?;
10219        let buffer = buffer.read(cx);
10220        let original_text = diff
10221            .read(cx)
10222            .base_text()
10223            .as_rope()
10224            .slice(hunk.diff_base_byte_range.clone());
10225        let buffer_snapshot = buffer.snapshot();
10226        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10227        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10228            probe
10229                .0
10230                .start
10231                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10232                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10233        }) {
10234            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10235            Some(())
10236        } else {
10237            None
10238        }
10239    }
10240
10241    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10242        self.manipulate_lines(window, cx, |lines| lines.reverse())
10243    }
10244
10245    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10246        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10247    }
10248
10249    fn manipulate_lines<Fn>(
10250        &mut self,
10251        window: &mut Window,
10252        cx: &mut Context<Self>,
10253        mut callback: Fn,
10254    ) where
10255        Fn: FnMut(&mut Vec<&str>),
10256    {
10257        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10258
10259        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10260        let buffer = self.buffer.read(cx).snapshot(cx);
10261
10262        let mut edits = Vec::new();
10263
10264        let selections = self.selections.all::<Point>(cx);
10265        let mut selections = selections.iter().peekable();
10266        let mut contiguous_row_selections = Vec::new();
10267        let mut new_selections = Vec::new();
10268        let mut added_lines = 0;
10269        let mut removed_lines = 0;
10270
10271        while let Some(selection) = selections.next() {
10272            let (start_row, end_row) = consume_contiguous_rows(
10273                &mut contiguous_row_selections,
10274                selection,
10275                &display_map,
10276                &mut selections,
10277            );
10278
10279            let start_point = Point::new(start_row.0, 0);
10280            let end_point = Point::new(
10281                end_row.previous_row().0,
10282                buffer.line_len(end_row.previous_row()),
10283            );
10284            let text = buffer
10285                .text_for_range(start_point..end_point)
10286                .collect::<String>();
10287
10288            let mut lines = text.split('\n').collect_vec();
10289
10290            let lines_before = lines.len();
10291            callback(&mut lines);
10292            let lines_after = lines.len();
10293
10294            edits.push((start_point..end_point, lines.join("\n")));
10295
10296            // Selections must change based on added and removed line count
10297            let start_row =
10298                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10299            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10300            new_selections.push(Selection {
10301                id: selection.id,
10302                start: start_row,
10303                end: end_row,
10304                goal: SelectionGoal::None,
10305                reversed: selection.reversed,
10306            });
10307
10308            if lines_after > lines_before {
10309                added_lines += lines_after - lines_before;
10310            } else if lines_before > lines_after {
10311                removed_lines += lines_before - lines_after;
10312            }
10313        }
10314
10315        self.transact(window, cx, |this, window, cx| {
10316            let buffer = this.buffer.update(cx, |buffer, cx| {
10317                buffer.edit(edits, None, cx);
10318                buffer.snapshot(cx)
10319            });
10320
10321            // Recalculate offsets on newly edited buffer
10322            let new_selections = new_selections
10323                .iter()
10324                .map(|s| {
10325                    let start_point = Point::new(s.start.0, 0);
10326                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10327                    Selection {
10328                        id: s.id,
10329                        start: buffer.point_to_offset(start_point),
10330                        end: buffer.point_to_offset(end_point),
10331                        goal: s.goal,
10332                        reversed: s.reversed,
10333                    }
10334                })
10335                .collect();
10336
10337            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10338                s.select(new_selections);
10339            });
10340
10341            this.request_autoscroll(Autoscroll::fit(), cx);
10342        });
10343    }
10344
10345    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10346        self.manipulate_text(window, cx, |text| {
10347            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10348            if has_upper_case_characters {
10349                text.to_lowercase()
10350            } else {
10351                text.to_uppercase()
10352            }
10353        })
10354    }
10355
10356    pub fn convert_to_upper_case(
10357        &mut self,
10358        _: &ConvertToUpperCase,
10359        window: &mut Window,
10360        cx: &mut Context<Self>,
10361    ) {
10362        self.manipulate_text(window, cx, |text| text.to_uppercase())
10363    }
10364
10365    pub fn convert_to_lower_case(
10366        &mut self,
10367        _: &ConvertToLowerCase,
10368        window: &mut Window,
10369        cx: &mut Context<Self>,
10370    ) {
10371        self.manipulate_text(window, cx, |text| text.to_lowercase())
10372    }
10373
10374    pub fn convert_to_title_case(
10375        &mut self,
10376        _: &ConvertToTitleCase,
10377        window: &mut Window,
10378        cx: &mut Context<Self>,
10379    ) {
10380        self.manipulate_text(window, cx, |text| {
10381            text.split('\n')
10382                .map(|line| line.to_case(Case::Title))
10383                .join("\n")
10384        })
10385    }
10386
10387    pub fn convert_to_snake_case(
10388        &mut self,
10389        _: &ConvertToSnakeCase,
10390        window: &mut Window,
10391        cx: &mut Context<Self>,
10392    ) {
10393        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10394    }
10395
10396    pub fn convert_to_kebab_case(
10397        &mut self,
10398        _: &ConvertToKebabCase,
10399        window: &mut Window,
10400        cx: &mut Context<Self>,
10401    ) {
10402        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10403    }
10404
10405    pub fn convert_to_upper_camel_case(
10406        &mut self,
10407        _: &ConvertToUpperCamelCase,
10408        window: &mut Window,
10409        cx: &mut Context<Self>,
10410    ) {
10411        self.manipulate_text(window, cx, |text| {
10412            text.split('\n')
10413                .map(|line| line.to_case(Case::UpperCamel))
10414                .join("\n")
10415        })
10416    }
10417
10418    pub fn convert_to_lower_camel_case(
10419        &mut self,
10420        _: &ConvertToLowerCamelCase,
10421        window: &mut Window,
10422        cx: &mut Context<Self>,
10423    ) {
10424        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10425    }
10426
10427    pub fn convert_to_opposite_case(
10428        &mut self,
10429        _: &ConvertToOppositeCase,
10430        window: &mut Window,
10431        cx: &mut Context<Self>,
10432    ) {
10433        self.manipulate_text(window, cx, |text| {
10434            text.chars()
10435                .fold(String::with_capacity(text.len()), |mut t, c| {
10436                    if c.is_uppercase() {
10437                        t.extend(c.to_lowercase());
10438                    } else {
10439                        t.extend(c.to_uppercase());
10440                    }
10441                    t
10442                })
10443        })
10444    }
10445
10446    pub fn convert_to_rot13(
10447        &mut self,
10448        _: &ConvertToRot13,
10449        window: &mut Window,
10450        cx: &mut Context<Self>,
10451    ) {
10452        self.manipulate_text(window, cx, |text| {
10453            text.chars()
10454                .map(|c| match c {
10455                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10456                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10457                    _ => c,
10458                })
10459                .collect()
10460        })
10461    }
10462
10463    pub fn convert_to_rot47(
10464        &mut self,
10465        _: &ConvertToRot47,
10466        window: &mut Window,
10467        cx: &mut Context<Self>,
10468    ) {
10469        self.manipulate_text(window, cx, |text| {
10470            text.chars()
10471                .map(|c| {
10472                    let code_point = c as u32;
10473                    if code_point >= 33 && code_point <= 126 {
10474                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10475                    }
10476                    c
10477                })
10478                .collect()
10479        })
10480    }
10481
10482    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10483    where
10484        Fn: FnMut(&str) -> String,
10485    {
10486        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10487        let buffer = self.buffer.read(cx).snapshot(cx);
10488
10489        let mut new_selections = Vec::new();
10490        let mut edits = Vec::new();
10491        let mut selection_adjustment = 0i32;
10492
10493        for selection in self.selections.all::<usize>(cx) {
10494            let selection_is_empty = selection.is_empty();
10495
10496            let (start, end) = if selection_is_empty {
10497                let word_range = movement::surrounding_word(
10498                    &display_map,
10499                    selection.start.to_display_point(&display_map),
10500                );
10501                let start = word_range.start.to_offset(&display_map, Bias::Left);
10502                let end = word_range.end.to_offset(&display_map, Bias::Left);
10503                (start, end)
10504            } else {
10505                (selection.start, selection.end)
10506            };
10507
10508            let text = buffer.text_for_range(start..end).collect::<String>();
10509            let old_length = text.len() as i32;
10510            let text = callback(&text);
10511
10512            new_selections.push(Selection {
10513                start: (start as i32 - selection_adjustment) as usize,
10514                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10515                goal: SelectionGoal::None,
10516                ..selection
10517            });
10518
10519            selection_adjustment += old_length - text.len() as i32;
10520
10521            edits.push((start..end, text));
10522        }
10523
10524        self.transact(window, cx, |this, window, cx| {
10525            this.buffer.update(cx, |buffer, cx| {
10526                buffer.edit(edits, None, cx);
10527            });
10528
10529            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10530                s.select(new_selections);
10531            });
10532
10533            this.request_autoscroll(Autoscroll::fit(), cx);
10534        });
10535    }
10536
10537    pub fn duplicate(
10538        &mut self,
10539        upwards: bool,
10540        whole_lines: bool,
10541        window: &mut Window,
10542        cx: &mut Context<Self>,
10543    ) {
10544        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10545
10546        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10547        let buffer = &display_map.buffer_snapshot;
10548        let selections = self.selections.all::<Point>(cx);
10549
10550        let mut edits = Vec::new();
10551        let mut selections_iter = selections.iter().peekable();
10552        while let Some(selection) = selections_iter.next() {
10553            let mut rows = selection.spanned_rows(false, &display_map);
10554            // duplicate line-wise
10555            if whole_lines || selection.start == selection.end {
10556                // Avoid duplicating the same lines twice.
10557                while let Some(next_selection) = selections_iter.peek() {
10558                    let next_rows = next_selection.spanned_rows(false, &display_map);
10559                    if next_rows.start < rows.end {
10560                        rows.end = next_rows.end;
10561                        selections_iter.next().unwrap();
10562                    } else {
10563                        break;
10564                    }
10565                }
10566
10567                // Copy the text from the selected row region and splice it either at the start
10568                // or end of the region.
10569                let start = Point::new(rows.start.0, 0);
10570                let end = Point::new(
10571                    rows.end.previous_row().0,
10572                    buffer.line_len(rows.end.previous_row()),
10573                );
10574                let text = buffer
10575                    .text_for_range(start..end)
10576                    .chain(Some("\n"))
10577                    .collect::<String>();
10578                let insert_location = if upwards {
10579                    Point::new(rows.end.0, 0)
10580                } else {
10581                    start
10582                };
10583                edits.push((insert_location..insert_location, text));
10584            } else {
10585                // duplicate character-wise
10586                let start = selection.start;
10587                let end = selection.end;
10588                let text = buffer.text_for_range(start..end).collect::<String>();
10589                edits.push((selection.end..selection.end, text));
10590            }
10591        }
10592
10593        self.transact(window, cx, |this, _, cx| {
10594            this.buffer.update(cx, |buffer, cx| {
10595                buffer.edit(edits, None, cx);
10596            });
10597
10598            this.request_autoscroll(Autoscroll::fit(), cx);
10599        });
10600    }
10601
10602    pub fn duplicate_line_up(
10603        &mut self,
10604        _: &DuplicateLineUp,
10605        window: &mut Window,
10606        cx: &mut Context<Self>,
10607    ) {
10608        self.duplicate(true, true, window, cx);
10609    }
10610
10611    pub fn duplicate_line_down(
10612        &mut self,
10613        _: &DuplicateLineDown,
10614        window: &mut Window,
10615        cx: &mut Context<Self>,
10616    ) {
10617        self.duplicate(false, true, window, cx);
10618    }
10619
10620    pub fn duplicate_selection(
10621        &mut self,
10622        _: &DuplicateSelection,
10623        window: &mut Window,
10624        cx: &mut Context<Self>,
10625    ) {
10626        self.duplicate(false, false, window, cx);
10627    }
10628
10629    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10630        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10631
10632        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10633        let buffer = self.buffer.read(cx).snapshot(cx);
10634
10635        let mut edits = Vec::new();
10636        let mut unfold_ranges = Vec::new();
10637        let mut refold_creases = Vec::new();
10638
10639        let selections = self.selections.all::<Point>(cx);
10640        let mut selections = selections.iter().peekable();
10641        let mut contiguous_row_selections = Vec::new();
10642        let mut new_selections = Vec::new();
10643
10644        while let Some(selection) = selections.next() {
10645            // Find all the selections that span a contiguous row range
10646            let (start_row, end_row) = consume_contiguous_rows(
10647                &mut contiguous_row_selections,
10648                selection,
10649                &display_map,
10650                &mut selections,
10651            );
10652
10653            // Move the text spanned by the row range to be before the line preceding the row range
10654            if start_row.0 > 0 {
10655                let range_to_move = Point::new(
10656                    start_row.previous_row().0,
10657                    buffer.line_len(start_row.previous_row()),
10658                )
10659                    ..Point::new(
10660                        end_row.previous_row().0,
10661                        buffer.line_len(end_row.previous_row()),
10662                    );
10663                let insertion_point = display_map
10664                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10665                    .0;
10666
10667                // Don't move lines across excerpts
10668                if buffer
10669                    .excerpt_containing(insertion_point..range_to_move.end)
10670                    .is_some()
10671                {
10672                    let text = buffer
10673                        .text_for_range(range_to_move.clone())
10674                        .flat_map(|s| s.chars())
10675                        .skip(1)
10676                        .chain(['\n'])
10677                        .collect::<String>();
10678
10679                    edits.push((
10680                        buffer.anchor_after(range_to_move.start)
10681                            ..buffer.anchor_before(range_to_move.end),
10682                        String::new(),
10683                    ));
10684                    let insertion_anchor = buffer.anchor_after(insertion_point);
10685                    edits.push((insertion_anchor..insertion_anchor, text));
10686
10687                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10688
10689                    // Move selections up
10690                    new_selections.extend(contiguous_row_selections.drain(..).map(
10691                        |mut selection| {
10692                            selection.start.row -= row_delta;
10693                            selection.end.row -= row_delta;
10694                            selection
10695                        },
10696                    ));
10697
10698                    // Move folds up
10699                    unfold_ranges.push(range_to_move.clone());
10700                    for fold in display_map.folds_in_range(
10701                        buffer.anchor_before(range_to_move.start)
10702                            ..buffer.anchor_after(range_to_move.end),
10703                    ) {
10704                        let mut start = fold.range.start.to_point(&buffer);
10705                        let mut end = fold.range.end.to_point(&buffer);
10706                        start.row -= row_delta;
10707                        end.row -= row_delta;
10708                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10709                    }
10710                }
10711            }
10712
10713            // If we didn't move line(s), preserve the existing selections
10714            new_selections.append(&mut contiguous_row_selections);
10715        }
10716
10717        self.transact(window, cx, |this, window, cx| {
10718            this.unfold_ranges(&unfold_ranges, true, true, cx);
10719            this.buffer.update(cx, |buffer, cx| {
10720                for (range, text) in edits {
10721                    buffer.edit([(range, text)], None, cx);
10722                }
10723            });
10724            this.fold_creases(refold_creases, true, window, cx);
10725            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10726                s.select(new_selections);
10727            })
10728        });
10729    }
10730
10731    pub fn move_line_down(
10732        &mut self,
10733        _: &MoveLineDown,
10734        window: &mut Window,
10735        cx: &mut Context<Self>,
10736    ) {
10737        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10738
10739        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10740        let buffer = self.buffer.read(cx).snapshot(cx);
10741
10742        let mut edits = Vec::new();
10743        let mut unfold_ranges = Vec::new();
10744        let mut refold_creases = Vec::new();
10745
10746        let selections = self.selections.all::<Point>(cx);
10747        let mut selections = selections.iter().peekable();
10748        let mut contiguous_row_selections = Vec::new();
10749        let mut new_selections = Vec::new();
10750
10751        while let Some(selection) = selections.next() {
10752            // Find all the selections that span a contiguous row range
10753            let (start_row, end_row) = consume_contiguous_rows(
10754                &mut contiguous_row_selections,
10755                selection,
10756                &display_map,
10757                &mut selections,
10758            );
10759
10760            // Move the text spanned by the row range to be after the last line of the row range
10761            if end_row.0 <= buffer.max_point().row {
10762                let range_to_move =
10763                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10764                let insertion_point = display_map
10765                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10766                    .0;
10767
10768                // Don't move lines across excerpt boundaries
10769                if buffer
10770                    .excerpt_containing(range_to_move.start..insertion_point)
10771                    .is_some()
10772                {
10773                    let mut text = String::from("\n");
10774                    text.extend(buffer.text_for_range(range_to_move.clone()));
10775                    text.pop(); // Drop trailing newline
10776                    edits.push((
10777                        buffer.anchor_after(range_to_move.start)
10778                            ..buffer.anchor_before(range_to_move.end),
10779                        String::new(),
10780                    ));
10781                    let insertion_anchor = buffer.anchor_after(insertion_point);
10782                    edits.push((insertion_anchor..insertion_anchor, text));
10783
10784                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10785
10786                    // Move selections down
10787                    new_selections.extend(contiguous_row_selections.drain(..).map(
10788                        |mut selection| {
10789                            selection.start.row += row_delta;
10790                            selection.end.row += row_delta;
10791                            selection
10792                        },
10793                    ));
10794
10795                    // Move folds down
10796                    unfold_ranges.push(range_to_move.clone());
10797                    for fold in display_map.folds_in_range(
10798                        buffer.anchor_before(range_to_move.start)
10799                            ..buffer.anchor_after(range_to_move.end),
10800                    ) {
10801                        let mut start = fold.range.start.to_point(&buffer);
10802                        let mut end = fold.range.end.to_point(&buffer);
10803                        start.row += row_delta;
10804                        end.row += row_delta;
10805                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10806                    }
10807                }
10808            }
10809
10810            // If we didn't move line(s), preserve the existing selections
10811            new_selections.append(&mut contiguous_row_selections);
10812        }
10813
10814        self.transact(window, cx, |this, window, cx| {
10815            this.unfold_ranges(&unfold_ranges, true, true, cx);
10816            this.buffer.update(cx, |buffer, cx| {
10817                for (range, text) in edits {
10818                    buffer.edit([(range, text)], None, cx);
10819                }
10820            });
10821            this.fold_creases(refold_creases, true, window, cx);
10822            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10823                s.select(new_selections)
10824            });
10825        });
10826    }
10827
10828    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10829        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10830        let text_layout_details = &self.text_layout_details(window);
10831        self.transact(window, cx, |this, window, cx| {
10832            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10833                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10834                s.move_with(|display_map, selection| {
10835                    if !selection.is_empty() {
10836                        return;
10837                    }
10838
10839                    let mut head = selection.head();
10840                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10841                    if head.column() == display_map.line_len(head.row()) {
10842                        transpose_offset = display_map
10843                            .buffer_snapshot
10844                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10845                    }
10846
10847                    if transpose_offset == 0 {
10848                        return;
10849                    }
10850
10851                    *head.column_mut() += 1;
10852                    head = display_map.clip_point(head, Bias::Right);
10853                    let goal = SelectionGoal::HorizontalPosition(
10854                        display_map
10855                            .x_for_display_point(head, text_layout_details)
10856                            .into(),
10857                    );
10858                    selection.collapse_to(head, goal);
10859
10860                    let transpose_start = display_map
10861                        .buffer_snapshot
10862                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10863                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10864                        let transpose_end = display_map
10865                            .buffer_snapshot
10866                            .clip_offset(transpose_offset + 1, Bias::Right);
10867                        if let Some(ch) =
10868                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10869                        {
10870                            edits.push((transpose_start..transpose_offset, String::new()));
10871                            edits.push((transpose_end..transpose_end, ch.to_string()));
10872                        }
10873                    }
10874                });
10875                edits
10876            });
10877            this.buffer
10878                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10879            let selections = this.selections.all::<usize>(cx);
10880            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10881                s.select(selections);
10882            });
10883        });
10884    }
10885
10886    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10887        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10888        self.rewrap_impl(RewrapOptions::default(), cx)
10889    }
10890
10891    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10892        let buffer = self.buffer.read(cx).snapshot(cx);
10893        let selections = self.selections.all::<Point>(cx);
10894        let mut selections = selections.iter().peekable();
10895
10896        let mut edits = Vec::new();
10897        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10898
10899        while let Some(selection) = selections.next() {
10900            let mut start_row = selection.start.row;
10901            let mut end_row = selection.end.row;
10902
10903            // Skip selections that overlap with a range that has already been rewrapped.
10904            let selection_range = start_row..end_row;
10905            if rewrapped_row_ranges
10906                .iter()
10907                .any(|range| range.overlaps(&selection_range))
10908            {
10909                continue;
10910            }
10911
10912            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10913
10914            // Since not all lines in the selection may be at the same indent
10915            // level, choose the indent size that is the most common between all
10916            // of the lines.
10917            //
10918            // If there is a tie, we use the deepest indent.
10919            let (indent_size, indent_end) = {
10920                let mut indent_size_occurrences = HashMap::default();
10921                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10922
10923                for row in start_row..=end_row {
10924                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10925                    rows_by_indent_size.entry(indent).or_default().push(row);
10926                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10927                }
10928
10929                let indent_size = indent_size_occurrences
10930                    .into_iter()
10931                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10932                    .map(|(indent, _)| indent)
10933                    .unwrap_or_default();
10934                let row = rows_by_indent_size[&indent_size][0];
10935                let indent_end = Point::new(row, indent_size.len);
10936
10937                (indent_size, indent_end)
10938            };
10939
10940            let mut line_prefix = indent_size.chars().collect::<String>();
10941
10942            let mut inside_comment = false;
10943            if let Some(comment_prefix) =
10944                buffer
10945                    .language_scope_at(selection.head())
10946                    .and_then(|language| {
10947                        language
10948                            .line_comment_prefixes()
10949                            .iter()
10950                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10951                            .cloned()
10952                    })
10953            {
10954                line_prefix.push_str(&comment_prefix);
10955                inside_comment = true;
10956            }
10957
10958            let language_settings = buffer.language_settings_at(selection.head(), cx);
10959            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10960                RewrapBehavior::InComments => inside_comment,
10961                RewrapBehavior::InSelections => !selection.is_empty(),
10962                RewrapBehavior::Anywhere => true,
10963            };
10964
10965            let should_rewrap = options.override_language_settings
10966                || allow_rewrap_based_on_language
10967                || self.hard_wrap.is_some();
10968            if !should_rewrap {
10969                continue;
10970            }
10971
10972            if selection.is_empty() {
10973                'expand_upwards: while start_row > 0 {
10974                    let prev_row = start_row - 1;
10975                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10976                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10977                    {
10978                        start_row = prev_row;
10979                    } else {
10980                        break 'expand_upwards;
10981                    }
10982                }
10983
10984                'expand_downwards: while end_row < buffer.max_point().row {
10985                    let next_row = end_row + 1;
10986                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10987                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10988                    {
10989                        end_row = next_row;
10990                    } else {
10991                        break 'expand_downwards;
10992                    }
10993                }
10994            }
10995
10996            let start = Point::new(start_row, 0);
10997            let start_offset = start.to_offset(&buffer);
10998            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10999            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11000            let Some(lines_without_prefixes) = selection_text
11001                .lines()
11002                .map(|line| {
11003                    line.strip_prefix(&line_prefix)
11004                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
11005                        .with_context(|| {
11006                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
11007                        })
11008                })
11009                .collect::<Result<Vec<_>, _>>()
11010                .log_err()
11011            else {
11012                continue;
11013            };
11014
11015            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11016                buffer
11017                    .language_settings_at(Point::new(start_row, 0), cx)
11018                    .preferred_line_length as usize
11019            });
11020            let wrapped_text = wrap_with_prefix(
11021                line_prefix,
11022                lines_without_prefixes.join("\n"),
11023                wrap_column,
11024                tab_size,
11025                options.preserve_existing_whitespace,
11026            );
11027
11028            // TODO: should always use char-based diff while still supporting cursor behavior that
11029            // matches vim.
11030            let mut diff_options = DiffOptions::default();
11031            if options.override_language_settings {
11032                diff_options.max_word_diff_len = 0;
11033                diff_options.max_word_diff_line_count = 0;
11034            } else {
11035                diff_options.max_word_diff_len = usize::MAX;
11036                diff_options.max_word_diff_line_count = usize::MAX;
11037            }
11038
11039            for (old_range, new_text) in
11040                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11041            {
11042                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11043                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11044                edits.push((edit_start..edit_end, new_text));
11045            }
11046
11047            rewrapped_row_ranges.push(start_row..=end_row);
11048        }
11049
11050        self.buffer
11051            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11052    }
11053
11054    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11055        let mut text = String::new();
11056        let buffer = self.buffer.read(cx).snapshot(cx);
11057        let mut selections = self.selections.all::<Point>(cx);
11058        let mut clipboard_selections = Vec::with_capacity(selections.len());
11059        {
11060            let max_point = buffer.max_point();
11061            let mut is_first = true;
11062            for selection in &mut selections {
11063                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11064                if is_entire_line {
11065                    selection.start = Point::new(selection.start.row, 0);
11066                    if !selection.is_empty() && selection.end.column == 0 {
11067                        selection.end = cmp::min(max_point, selection.end);
11068                    } else {
11069                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11070                    }
11071                    selection.goal = SelectionGoal::None;
11072                }
11073                if is_first {
11074                    is_first = false;
11075                } else {
11076                    text += "\n";
11077                }
11078                let mut len = 0;
11079                for chunk in buffer.text_for_range(selection.start..selection.end) {
11080                    text.push_str(chunk);
11081                    len += chunk.len();
11082                }
11083                clipboard_selections.push(ClipboardSelection {
11084                    len,
11085                    is_entire_line,
11086                    first_line_indent: buffer
11087                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11088                        .len,
11089                });
11090            }
11091        }
11092
11093        self.transact(window, cx, |this, window, cx| {
11094            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11095                s.select(selections);
11096            });
11097            this.insert("", window, cx);
11098        });
11099        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11100    }
11101
11102    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11103        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11104        let item = self.cut_common(window, cx);
11105        cx.write_to_clipboard(item);
11106    }
11107
11108    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11109        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11110        self.change_selections(None, window, cx, |s| {
11111            s.move_with(|snapshot, sel| {
11112                if sel.is_empty() {
11113                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11114                }
11115            });
11116        });
11117        let item = self.cut_common(window, cx);
11118        cx.set_global(KillRing(item))
11119    }
11120
11121    pub fn kill_ring_yank(
11122        &mut self,
11123        _: &KillRingYank,
11124        window: &mut Window,
11125        cx: &mut Context<Self>,
11126    ) {
11127        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11128        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11129            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11130                (kill_ring.text().to_string(), kill_ring.metadata_json())
11131            } else {
11132                return;
11133            }
11134        } else {
11135            return;
11136        };
11137        self.do_paste(&text, metadata, false, window, cx);
11138    }
11139
11140    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11141        self.do_copy(true, cx);
11142    }
11143
11144    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11145        self.do_copy(false, cx);
11146    }
11147
11148    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11149        let selections = self.selections.all::<Point>(cx);
11150        let buffer = self.buffer.read(cx).read(cx);
11151        let mut text = String::new();
11152
11153        let mut clipboard_selections = Vec::with_capacity(selections.len());
11154        {
11155            let max_point = buffer.max_point();
11156            let mut is_first = true;
11157            for selection in &selections {
11158                let mut start = selection.start;
11159                let mut end = selection.end;
11160                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11161                if is_entire_line {
11162                    start = Point::new(start.row, 0);
11163                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11164                }
11165
11166                let mut trimmed_selections = Vec::new();
11167                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11168                    let row = MultiBufferRow(start.row);
11169                    let first_indent = buffer.indent_size_for_line(row);
11170                    if first_indent.len == 0 || start.column > first_indent.len {
11171                        trimmed_selections.push(start..end);
11172                    } else {
11173                        trimmed_selections.push(
11174                            Point::new(row.0, first_indent.len)
11175                                ..Point::new(row.0, buffer.line_len(row)),
11176                        );
11177                        for row in start.row + 1..=end.row {
11178                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11179                            if row == end.row {
11180                                line_len = end.column;
11181                            }
11182                            if line_len == 0 {
11183                                trimmed_selections
11184                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11185                                continue;
11186                            }
11187                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11188                            if row_indent_size.len >= first_indent.len {
11189                                trimmed_selections.push(
11190                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11191                                );
11192                            } else {
11193                                trimmed_selections.clear();
11194                                trimmed_selections.push(start..end);
11195                                break;
11196                            }
11197                        }
11198                    }
11199                } else {
11200                    trimmed_selections.push(start..end);
11201                }
11202
11203                for trimmed_range in trimmed_selections {
11204                    if is_first {
11205                        is_first = false;
11206                    } else {
11207                        text += "\n";
11208                    }
11209                    let mut len = 0;
11210                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11211                        text.push_str(chunk);
11212                        len += chunk.len();
11213                    }
11214                    clipboard_selections.push(ClipboardSelection {
11215                        len,
11216                        is_entire_line,
11217                        first_line_indent: buffer
11218                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11219                            .len,
11220                    });
11221                }
11222            }
11223        }
11224
11225        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11226            text,
11227            clipboard_selections,
11228        ));
11229    }
11230
11231    pub fn do_paste(
11232        &mut self,
11233        text: &String,
11234        clipboard_selections: Option<Vec<ClipboardSelection>>,
11235        handle_entire_lines: bool,
11236        window: &mut Window,
11237        cx: &mut Context<Self>,
11238    ) {
11239        if self.read_only(cx) {
11240            return;
11241        }
11242
11243        let clipboard_text = Cow::Borrowed(text);
11244
11245        self.transact(window, cx, |this, window, cx| {
11246            if let Some(mut clipboard_selections) = clipboard_selections {
11247                let old_selections = this.selections.all::<usize>(cx);
11248                let all_selections_were_entire_line =
11249                    clipboard_selections.iter().all(|s| s.is_entire_line);
11250                let first_selection_indent_column =
11251                    clipboard_selections.first().map(|s| s.first_line_indent);
11252                if clipboard_selections.len() != old_selections.len() {
11253                    clipboard_selections.drain(..);
11254                }
11255                let cursor_offset = this.selections.last::<usize>(cx).head();
11256                let mut auto_indent_on_paste = true;
11257
11258                this.buffer.update(cx, |buffer, cx| {
11259                    let snapshot = buffer.read(cx);
11260                    auto_indent_on_paste = snapshot
11261                        .language_settings_at(cursor_offset, cx)
11262                        .auto_indent_on_paste;
11263
11264                    let mut start_offset = 0;
11265                    let mut edits = Vec::new();
11266                    let mut original_indent_columns = Vec::new();
11267                    for (ix, selection) in old_selections.iter().enumerate() {
11268                        let to_insert;
11269                        let entire_line;
11270                        let original_indent_column;
11271                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11272                            let end_offset = start_offset + clipboard_selection.len;
11273                            to_insert = &clipboard_text[start_offset..end_offset];
11274                            entire_line = clipboard_selection.is_entire_line;
11275                            start_offset = end_offset + 1;
11276                            original_indent_column = Some(clipboard_selection.first_line_indent);
11277                        } else {
11278                            to_insert = clipboard_text.as_str();
11279                            entire_line = all_selections_were_entire_line;
11280                            original_indent_column = first_selection_indent_column
11281                        }
11282
11283                        // If the corresponding selection was empty when this slice of the
11284                        // clipboard text was written, then the entire line containing the
11285                        // selection was copied. If this selection is also currently empty,
11286                        // then paste the line before the current line of the buffer.
11287                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11288                            let column = selection.start.to_point(&snapshot).column as usize;
11289                            let line_start = selection.start - column;
11290                            line_start..line_start
11291                        } else {
11292                            selection.range()
11293                        };
11294
11295                        edits.push((range, to_insert));
11296                        original_indent_columns.push(original_indent_column);
11297                    }
11298                    drop(snapshot);
11299
11300                    buffer.edit(
11301                        edits,
11302                        if auto_indent_on_paste {
11303                            Some(AutoindentMode::Block {
11304                                original_indent_columns,
11305                            })
11306                        } else {
11307                            None
11308                        },
11309                        cx,
11310                    );
11311                });
11312
11313                let selections = this.selections.all::<usize>(cx);
11314                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11315                    s.select(selections)
11316                });
11317            } else {
11318                this.insert(&clipboard_text, window, cx);
11319            }
11320        });
11321    }
11322
11323    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11324        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11325        if let Some(item) = cx.read_from_clipboard() {
11326            let entries = item.entries();
11327
11328            match entries.first() {
11329                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11330                // of all the pasted entries.
11331                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11332                    .do_paste(
11333                        clipboard_string.text(),
11334                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11335                        true,
11336                        window,
11337                        cx,
11338                    ),
11339                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11340            }
11341        }
11342    }
11343
11344    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11345        if self.read_only(cx) {
11346            return;
11347        }
11348
11349        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11350
11351        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11352            if let Some((selections, _)) =
11353                self.selection_history.transaction(transaction_id).cloned()
11354            {
11355                self.change_selections(None, window, cx, |s| {
11356                    s.select_anchors(selections.to_vec());
11357                });
11358            } else {
11359                log::error!(
11360                    "No entry in selection_history found for undo. \
11361                     This may correspond to a bug where undo does not update the selection. \
11362                     If this is occurring, please add details to \
11363                     https://github.com/zed-industries/zed/issues/22692"
11364                );
11365            }
11366            self.request_autoscroll(Autoscroll::fit(), cx);
11367            self.unmark_text(window, cx);
11368            self.refresh_inline_completion(true, false, window, cx);
11369            cx.emit(EditorEvent::Edited { transaction_id });
11370            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11371        }
11372    }
11373
11374    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11375        if self.read_only(cx) {
11376            return;
11377        }
11378
11379        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11380
11381        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11382            if let Some((_, Some(selections))) =
11383                self.selection_history.transaction(transaction_id).cloned()
11384            {
11385                self.change_selections(None, window, cx, |s| {
11386                    s.select_anchors(selections.to_vec());
11387                });
11388            } else {
11389                log::error!(
11390                    "No entry in selection_history found for redo. \
11391                     This may correspond to a bug where undo does not update the selection. \
11392                     If this is occurring, please add details to \
11393                     https://github.com/zed-industries/zed/issues/22692"
11394                );
11395            }
11396            self.request_autoscroll(Autoscroll::fit(), cx);
11397            self.unmark_text(window, cx);
11398            self.refresh_inline_completion(true, false, window, cx);
11399            cx.emit(EditorEvent::Edited { transaction_id });
11400        }
11401    }
11402
11403    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11404        self.buffer
11405            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11406    }
11407
11408    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11409        self.buffer
11410            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11411    }
11412
11413    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11414        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11415        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11416            s.move_with(|map, selection| {
11417                let cursor = if selection.is_empty() {
11418                    movement::left(map, selection.start)
11419                } else {
11420                    selection.start
11421                };
11422                selection.collapse_to(cursor, SelectionGoal::None);
11423            });
11424        })
11425    }
11426
11427    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11428        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11429        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11430            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11431        })
11432    }
11433
11434    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11435        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11436        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11437            s.move_with(|map, selection| {
11438                let cursor = if selection.is_empty() {
11439                    movement::right(map, selection.end)
11440                } else {
11441                    selection.end
11442                };
11443                selection.collapse_to(cursor, SelectionGoal::None)
11444            });
11445        })
11446    }
11447
11448    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11449        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11450        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11451            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11452        })
11453    }
11454
11455    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11456        if self.take_rename(true, window, cx).is_some() {
11457            return;
11458        }
11459
11460        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11461            cx.propagate();
11462            return;
11463        }
11464
11465        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11466
11467        let text_layout_details = &self.text_layout_details(window);
11468        let selection_count = self.selections.count();
11469        let first_selection = self.selections.first_anchor();
11470
11471        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11472            s.move_with(|map, selection| {
11473                if !selection.is_empty() {
11474                    selection.goal = SelectionGoal::None;
11475                }
11476                let (cursor, goal) = movement::up(
11477                    map,
11478                    selection.start,
11479                    selection.goal,
11480                    false,
11481                    text_layout_details,
11482                );
11483                selection.collapse_to(cursor, goal);
11484            });
11485        });
11486
11487        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11488        {
11489            cx.propagate();
11490        }
11491    }
11492
11493    pub fn move_up_by_lines(
11494        &mut self,
11495        action: &MoveUpByLines,
11496        window: &mut Window,
11497        cx: &mut Context<Self>,
11498    ) {
11499        if self.take_rename(true, window, cx).is_some() {
11500            return;
11501        }
11502
11503        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11504            cx.propagate();
11505            return;
11506        }
11507
11508        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11509
11510        let text_layout_details = &self.text_layout_details(window);
11511
11512        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11513            s.move_with(|map, selection| {
11514                if !selection.is_empty() {
11515                    selection.goal = SelectionGoal::None;
11516                }
11517                let (cursor, goal) = movement::up_by_rows(
11518                    map,
11519                    selection.start,
11520                    action.lines,
11521                    selection.goal,
11522                    false,
11523                    text_layout_details,
11524                );
11525                selection.collapse_to(cursor, goal);
11526            });
11527        })
11528    }
11529
11530    pub fn move_down_by_lines(
11531        &mut self,
11532        action: &MoveDownByLines,
11533        window: &mut Window,
11534        cx: &mut Context<Self>,
11535    ) {
11536        if self.take_rename(true, window, cx).is_some() {
11537            return;
11538        }
11539
11540        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11541            cx.propagate();
11542            return;
11543        }
11544
11545        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11546
11547        let text_layout_details = &self.text_layout_details(window);
11548
11549        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11550            s.move_with(|map, selection| {
11551                if !selection.is_empty() {
11552                    selection.goal = SelectionGoal::None;
11553                }
11554                let (cursor, goal) = movement::down_by_rows(
11555                    map,
11556                    selection.start,
11557                    action.lines,
11558                    selection.goal,
11559                    false,
11560                    text_layout_details,
11561                );
11562                selection.collapse_to(cursor, goal);
11563            });
11564        })
11565    }
11566
11567    pub fn select_down_by_lines(
11568        &mut self,
11569        action: &SelectDownByLines,
11570        window: &mut Window,
11571        cx: &mut Context<Self>,
11572    ) {
11573        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11574        let text_layout_details = &self.text_layout_details(window);
11575        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11576            s.move_heads_with(|map, head, goal| {
11577                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11578            })
11579        })
11580    }
11581
11582    pub fn select_up_by_lines(
11583        &mut self,
11584        action: &SelectUpByLines,
11585        window: &mut Window,
11586        cx: &mut Context<Self>,
11587    ) {
11588        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11589        let text_layout_details = &self.text_layout_details(window);
11590        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11591            s.move_heads_with(|map, head, goal| {
11592                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11593            })
11594        })
11595    }
11596
11597    pub fn select_page_up(
11598        &mut self,
11599        _: &SelectPageUp,
11600        window: &mut Window,
11601        cx: &mut Context<Self>,
11602    ) {
11603        let Some(row_count) = self.visible_row_count() else {
11604            return;
11605        };
11606
11607        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11608
11609        let text_layout_details = &self.text_layout_details(window);
11610
11611        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11612            s.move_heads_with(|map, head, goal| {
11613                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11614            })
11615        })
11616    }
11617
11618    pub fn move_page_up(
11619        &mut self,
11620        action: &MovePageUp,
11621        window: &mut Window,
11622        cx: &mut Context<Self>,
11623    ) {
11624        if self.take_rename(true, window, cx).is_some() {
11625            return;
11626        }
11627
11628        if self
11629            .context_menu
11630            .borrow_mut()
11631            .as_mut()
11632            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11633            .unwrap_or(false)
11634        {
11635            return;
11636        }
11637
11638        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11639            cx.propagate();
11640            return;
11641        }
11642
11643        let Some(row_count) = self.visible_row_count() else {
11644            return;
11645        };
11646
11647        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11648
11649        let autoscroll = if action.center_cursor {
11650            Autoscroll::center()
11651        } else {
11652            Autoscroll::fit()
11653        };
11654
11655        let text_layout_details = &self.text_layout_details(window);
11656
11657        self.change_selections(Some(autoscroll), window, cx, |s| {
11658            s.move_with(|map, selection| {
11659                if !selection.is_empty() {
11660                    selection.goal = SelectionGoal::None;
11661                }
11662                let (cursor, goal) = movement::up_by_rows(
11663                    map,
11664                    selection.end,
11665                    row_count,
11666                    selection.goal,
11667                    false,
11668                    text_layout_details,
11669                );
11670                selection.collapse_to(cursor, goal);
11671            });
11672        });
11673    }
11674
11675    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11676        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11677        let text_layout_details = &self.text_layout_details(window);
11678        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11679            s.move_heads_with(|map, head, goal| {
11680                movement::up(map, head, goal, false, text_layout_details)
11681            })
11682        })
11683    }
11684
11685    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11686        self.take_rename(true, window, cx);
11687
11688        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11689            cx.propagate();
11690            return;
11691        }
11692
11693        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11694
11695        let text_layout_details = &self.text_layout_details(window);
11696        let selection_count = self.selections.count();
11697        let first_selection = self.selections.first_anchor();
11698
11699        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11700            s.move_with(|map, selection| {
11701                if !selection.is_empty() {
11702                    selection.goal = SelectionGoal::None;
11703                }
11704                let (cursor, goal) = movement::down(
11705                    map,
11706                    selection.end,
11707                    selection.goal,
11708                    false,
11709                    text_layout_details,
11710                );
11711                selection.collapse_to(cursor, goal);
11712            });
11713        });
11714
11715        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11716        {
11717            cx.propagate();
11718        }
11719    }
11720
11721    pub fn select_page_down(
11722        &mut self,
11723        _: &SelectPageDown,
11724        window: &mut Window,
11725        cx: &mut Context<Self>,
11726    ) {
11727        let Some(row_count) = self.visible_row_count() else {
11728            return;
11729        };
11730
11731        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11732
11733        let text_layout_details = &self.text_layout_details(window);
11734
11735        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11736            s.move_heads_with(|map, head, goal| {
11737                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11738            })
11739        })
11740    }
11741
11742    pub fn move_page_down(
11743        &mut self,
11744        action: &MovePageDown,
11745        window: &mut Window,
11746        cx: &mut Context<Self>,
11747    ) {
11748        if self.take_rename(true, window, cx).is_some() {
11749            return;
11750        }
11751
11752        if self
11753            .context_menu
11754            .borrow_mut()
11755            .as_mut()
11756            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
11757            .unwrap_or(false)
11758        {
11759            return;
11760        }
11761
11762        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11763            cx.propagate();
11764            return;
11765        }
11766
11767        let Some(row_count) = self.visible_row_count() else {
11768            return;
11769        };
11770
11771        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11772
11773        let autoscroll = if action.center_cursor {
11774            Autoscroll::center()
11775        } else {
11776            Autoscroll::fit()
11777        };
11778
11779        let text_layout_details = &self.text_layout_details(window);
11780        self.change_selections(Some(autoscroll), window, cx, |s| {
11781            s.move_with(|map, selection| {
11782                if !selection.is_empty() {
11783                    selection.goal = SelectionGoal::None;
11784                }
11785                let (cursor, goal) = movement::down_by_rows(
11786                    map,
11787                    selection.end,
11788                    row_count,
11789                    selection.goal,
11790                    false,
11791                    text_layout_details,
11792                );
11793                selection.collapse_to(cursor, goal);
11794            });
11795        });
11796    }
11797
11798    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11799        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11800        let text_layout_details = &self.text_layout_details(window);
11801        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11802            s.move_heads_with(|map, head, goal| {
11803                movement::down(map, head, goal, false, text_layout_details)
11804            })
11805        });
11806    }
11807
11808    pub fn context_menu_first(
11809        &mut self,
11810        _: &ContextMenuFirst,
11811        window: &mut Window,
11812        cx: &mut Context<Self>,
11813    ) {
11814        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11815            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
11816        }
11817    }
11818
11819    pub fn context_menu_prev(
11820        &mut self,
11821        _: &ContextMenuPrevious,
11822        window: &mut Window,
11823        cx: &mut Context<Self>,
11824    ) {
11825        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11826            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
11827        }
11828    }
11829
11830    pub fn context_menu_next(
11831        &mut self,
11832        _: &ContextMenuNext,
11833        window: &mut Window,
11834        cx: &mut Context<Self>,
11835    ) {
11836        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11837            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
11838        }
11839    }
11840
11841    pub fn context_menu_last(
11842        &mut self,
11843        _: &ContextMenuLast,
11844        window: &mut Window,
11845        cx: &mut Context<Self>,
11846    ) {
11847        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11848            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
11849        }
11850    }
11851
11852    pub fn move_to_previous_word_start(
11853        &mut self,
11854        _: &MoveToPreviousWordStart,
11855        window: &mut Window,
11856        cx: &mut Context<Self>,
11857    ) {
11858        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11859        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11860            s.move_cursors_with(|map, head, _| {
11861                (
11862                    movement::previous_word_start(map, head),
11863                    SelectionGoal::None,
11864                )
11865            });
11866        })
11867    }
11868
11869    pub fn move_to_previous_subword_start(
11870        &mut self,
11871        _: &MoveToPreviousSubwordStart,
11872        window: &mut Window,
11873        cx: &mut Context<Self>,
11874    ) {
11875        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11876        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11877            s.move_cursors_with(|map, head, _| {
11878                (
11879                    movement::previous_subword_start(map, head),
11880                    SelectionGoal::None,
11881                )
11882            });
11883        })
11884    }
11885
11886    pub fn select_to_previous_word_start(
11887        &mut self,
11888        _: &SelectToPreviousWordStart,
11889        window: &mut Window,
11890        cx: &mut Context<Self>,
11891    ) {
11892        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11893        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11894            s.move_heads_with(|map, head, _| {
11895                (
11896                    movement::previous_word_start(map, head),
11897                    SelectionGoal::None,
11898                )
11899            });
11900        })
11901    }
11902
11903    pub fn select_to_previous_subword_start(
11904        &mut self,
11905        _: &SelectToPreviousSubwordStart,
11906        window: &mut Window,
11907        cx: &mut Context<Self>,
11908    ) {
11909        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11910        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11911            s.move_heads_with(|map, head, _| {
11912                (
11913                    movement::previous_subword_start(map, head),
11914                    SelectionGoal::None,
11915                )
11916            });
11917        })
11918    }
11919
11920    pub fn delete_to_previous_word_start(
11921        &mut self,
11922        action: &DeleteToPreviousWordStart,
11923        window: &mut Window,
11924        cx: &mut Context<Self>,
11925    ) {
11926        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11927        self.transact(window, cx, |this, window, cx| {
11928            this.select_autoclose_pair(window, cx);
11929            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11930                s.move_with(|map, selection| {
11931                    if selection.is_empty() {
11932                        let cursor = if action.ignore_newlines {
11933                            movement::previous_word_start(map, selection.head())
11934                        } else {
11935                            movement::previous_word_start_or_newline(map, selection.head())
11936                        };
11937                        selection.set_head(cursor, SelectionGoal::None);
11938                    }
11939                });
11940            });
11941            this.insert("", window, cx);
11942        });
11943    }
11944
11945    pub fn delete_to_previous_subword_start(
11946        &mut self,
11947        _: &DeleteToPreviousSubwordStart,
11948        window: &mut Window,
11949        cx: &mut Context<Self>,
11950    ) {
11951        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11952        self.transact(window, cx, |this, window, cx| {
11953            this.select_autoclose_pair(window, cx);
11954            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11955                s.move_with(|map, selection| {
11956                    if selection.is_empty() {
11957                        let cursor = movement::previous_subword_start(map, selection.head());
11958                        selection.set_head(cursor, SelectionGoal::None);
11959                    }
11960                });
11961            });
11962            this.insert("", window, cx);
11963        });
11964    }
11965
11966    pub fn move_to_next_word_end(
11967        &mut self,
11968        _: &MoveToNextWordEnd,
11969        window: &mut Window,
11970        cx: &mut Context<Self>,
11971    ) {
11972        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11973        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11974            s.move_cursors_with(|map, head, _| {
11975                (movement::next_word_end(map, head), SelectionGoal::None)
11976            });
11977        })
11978    }
11979
11980    pub fn move_to_next_subword_end(
11981        &mut self,
11982        _: &MoveToNextSubwordEnd,
11983        window: &mut Window,
11984        cx: &mut Context<Self>,
11985    ) {
11986        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11987        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11988            s.move_cursors_with(|map, head, _| {
11989                (movement::next_subword_end(map, head), SelectionGoal::None)
11990            });
11991        })
11992    }
11993
11994    pub fn select_to_next_word_end(
11995        &mut self,
11996        _: &SelectToNextWordEnd,
11997        window: &mut Window,
11998        cx: &mut Context<Self>,
11999    ) {
12000        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12001        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12002            s.move_heads_with(|map, head, _| {
12003                (movement::next_word_end(map, head), SelectionGoal::None)
12004            });
12005        })
12006    }
12007
12008    pub fn select_to_next_subword_end(
12009        &mut self,
12010        _: &SelectToNextSubwordEnd,
12011        window: &mut Window,
12012        cx: &mut Context<Self>,
12013    ) {
12014        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12015        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12016            s.move_heads_with(|map, head, _| {
12017                (movement::next_subword_end(map, head), SelectionGoal::None)
12018            });
12019        })
12020    }
12021
12022    pub fn delete_to_next_word_end(
12023        &mut self,
12024        action: &DeleteToNextWordEnd,
12025        window: &mut Window,
12026        cx: &mut Context<Self>,
12027    ) {
12028        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12029        self.transact(window, cx, |this, window, cx| {
12030            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12031                s.move_with(|map, selection| {
12032                    if selection.is_empty() {
12033                        let cursor = if action.ignore_newlines {
12034                            movement::next_word_end(map, selection.head())
12035                        } else {
12036                            movement::next_word_end_or_newline(map, selection.head())
12037                        };
12038                        selection.set_head(cursor, SelectionGoal::None);
12039                    }
12040                });
12041            });
12042            this.insert("", window, cx);
12043        });
12044    }
12045
12046    pub fn delete_to_next_subword_end(
12047        &mut self,
12048        _: &DeleteToNextSubwordEnd,
12049        window: &mut Window,
12050        cx: &mut Context<Self>,
12051    ) {
12052        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12053        self.transact(window, cx, |this, window, cx| {
12054            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12055                s.move_with(|map, selection| {
12056                    if selection.is_empty() {
12057                        let cursor = movement::next_subword_end(map, selection.head());
12058                        selection.set_head(cursor, SelectionGoal::None);
12059                    }
12060                });
12061            });
12062            this.insert("", window, cx);
12063        });
12064    }
12065
12066    pub fn move_to_beginning_of_line(
12067        &mut self,
12068        action: &MoveToBeginningOfLine,
12069        window: &mut Window,
12070        cx: &mut Context<Self>,
12071    ) {
12072        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12073        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12074            s.move_cursors_with(|map, head, _| {
12075                (
12076                    movement::indented_line_beginning(
12077                        map,
12078                        head,
12079                        action.stop_at_soft_wraps,
12080                        action.stop_at_indent,
12081                    ),
12082                    SelectionGoal::None,
12083                )
12084            });
12085        })
12086    }
12087
12088    pub fn select_to_beginning_of_line(
12089        &mut self,
12090        action: &SelectToBeginningOfLine,
12091        window: &mut Window,
12092        cx: &mut Context<Self>,
12093    ) {
12094        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12095        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12096            s.move_heads_with(|map, head, _| {
12097                (
12098                    movement::indented_line_beginning(
12099                        map,
12100                        head,
12101                        action.stop_at_soft_wraps,
12102                        action.stop_at_indent,
12103                    ),
12104                    SelectionGoal::None,
12105                )
12106            });
12107        });
12108    }
12109
12110    pub fn delete_to_beginning_of_line(
12111        &mut self,
12112        action: &DeleteToBeginningOfLine,
12113        window: &mut Window,
12114        cx: &mut Context<Self>,
12115    ) {
12116        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12117        self.transact(window, cx, |this, window, cx| {
12118            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12119                s.move_with(|_, selection| {
12120                    selection.reversed = true;
12121                });
12122            });
12123
12124            this.select_to_beginning_of_line(
12125                &SelectToBeginningOfLine {
12126                    stop_at_soft_wraps: false,
12127                    stop_at_indent: action.stop_at_indent,
12128                },
12129                window,
12130                cx,
12131            );
12132            this.backspace(&Backspace, window, cx);
12133        });
12134    }
12135
12136    pub fn move_to_end_of_line(
12137        &mut self,
12138        action: &MoveToEndOfLine,
12139        window: &mut Window,
12140        cx: &mut Context<Self>,
12141    ) {
12142        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12143        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12144            s.move_cursors_with(|map, head, _| {
12145                (
12146                    movement::line_end(map, head, action.stop_at_soft_wraps),
12147                    SelectionGoal::None,
12148                )
12149            });
12150        })
12151    }
12152
12153    pub fn select_to_end_of_line(
12154        &mut self,
12155        action: &SelectToEndOfLine,
12156        window: &mut Window,
12157        cx: &mut Context<Self>,
12158    ) {
12159        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12160        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12161            s.move_heads_with(|map, head, _| {
12162                (
12163                    movement::line_end(map, head, action.stop_at_soft_wraps),
12164                    SelectionGoal::None,
12165                )
12166            });
12167        })
12168    }
12169
12170    pub fn delete_to_end_of_line(
12171        &mut self,
12172        _: &DeleteToEndOfLine,
12173        window: &mut Window,
12174        cx: &mut Context<Self>,
12175    ) {
12176        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12177        self.transact(window, cx, |this, window, cx| {
12178            this.select_to_end_of_line(
12179                &SelectToEndOfLine {
12180                    stop_at_soft_wraps: false,
12181                },
12182                window,
12183                cx,
12184            );
12185            this.delete(&Delete, window, cx);
12186        });
12187    }
12188
12189    pub fn cut_to_end_of_line(
12190        &mut self,
12191        _: &CutToEndOfLine,
12192        window: &mut Window,
12193        cx: &mut Context<Self>,
12194    ) {
12195        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12196        self.transact(window, cx, |this, window, cx| {
12197            this.select_to_end_of_line(
12198                &SelectToEndOfLine {
12199                    stop_at_soft_wraps: false,
12200                },
12201                window,
12202                cx,
12203            );
12204            this.cut(&Cut, window, cx);
12205        });
12206    }
12207
12208    pub fn move_to_start_of_paragraph(
12209        &mut self,
12210        _: &MoveToStartOfParagraph,
12211        window: &mut Window,
12212        cx: &mut Context<Self>,
12213    ) {
12214        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12215            cx.propagate();
12216            return;
12217        }
12218        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12219        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12220            s.move_with(|map, selection| {
12221                selection.collapse_to(
12222                    movement::start_of_paragraph(map, selection.head(), 1),
12223                    SelectionGoal::None,
12224                )
12225            });
12226        })
12227    }
12228
12229    pub fn move_to_end_of_paragraph(
12230        &mut self,
12231        _: &MoveToEndOfParagraph,
12232        window: &mut Window,
12233        cx: &mut Context<Self>,
12234    ) {
12235        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12236            cx.propagate();
12237            return;
12238        }
12239        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12240        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12241            s.move_with(|map, selection| {
12242                selection.collapse_to(
12243                    movement::end_of_paragraph(map, selection.head(), 1),
12244                    SelectionGoal::None,
12245                )
12246            });
12247        })
12248    }
12249
12250    pub fn select_to_start_of_paragraph(
12251        &mut self,
12252        _: &SelectToStartOfParagraph,
12253        window: &mut Window,
12254        cx: &mut Context<Self>,
12255    ) {
12256        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12257            cx.propagate();
12258            return;
12259        }
12260        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12261        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12262            s.move_heads_with(|map, head, _| {
12263                (
12264                    movement::start_of_paragraph(map, head, 1),
12265                    SelectionGoal::None,
12266                )
12267            });
12268        })
12269    }
12270
12271    pub fn select_to_end_of_paragraph(
12272        &mut self,
12273        _: &SelectToEndOfParagraph,
12274        window: &mut Window,
12275        cx: &mut Context<Self>,
12276    ) {
12277        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12278            cx.propagate();
12279            return;
12280        }
12281        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12282        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12283            s.move_heads_with(|map, head, _| {
12284                (
12285                    movement::end_of_paragraph(map, head, 1),
12286                    SelectionGoal::None,
12287                )
12288            });
12289        })
12290    }
12291
12292    pub fn move_to_start_of_excerpt(
12293        &mut self,
12294        _: &MoveToStartOfExcerpt,
12295        window: &mut Window,
12296        cx: &mut Context<Self>,
12297    ) {
12298        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12299            cx.propagate();
12300            return;
12301        }
12302        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12303        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12304            s.move_with(|map, selection| {
12305                selection.collapse_to(
12306                    movement::start_of_excerpt(
12307                        map,
12308                        selection.head(),
12309                        workspace::searchable::Direction::Prev,
12310                    ),
12311                    SelectionGoal::None,
12312                )
12313            });
12314        })
12315    }
12316
12317    pub fn move_to_start_of_next_excerpt(
12318        &mut self,
12319        _: &MoveToStartOfNextExcerpt,
12320        window: &mut Window,
12321        cx: &mut Context<Self>,
12322    ) {
12323        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12324            cx.propagate();
12325            return;
12326        }
12327
12328        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12329            s.move_with(|map, selection| {
12330                selection.collapse_to(
12331                    movement::start_of_excerpt(
12332                        map,
12333                        selection.head(),
12334                        workspace::searchable::Direction::Next,
12335                    ),
12336                    SelectionGoal::None,
12337                )
12338            });
12339        })
12340    }
12341
12342    pub fn move_to_end_of_excerpt(
12343        &mut self,
12344        _: &MoveToEndOfExcerpt,
12345        window: &mut Window,
12346        cx: &mut Context<Self>,
12347    ) {
12348        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12349            cx.propagate();
12350            return;
12351        }
12352        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12353        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12354            s.move_with(|map, selection| {
12355                selection.collapse_to(
12356                    movement::end_of_excerpt(
12357                        map,
12358                        selection.head(),
12359                        workspace::searchable::Direction::Next,
12360                    ),
12361                    SelectionGoal::None,
12362                )
12363            });
12364        })
12365    }
12366
12367    pub fn move_to_end_of_previous_excerpt(
12368        &mut self,
12369        _: &MoveToEndOfPreviousExcerpt,
12370        window: &mut Window,
12371        cx: &mut Context<Self>,
12372    ) {
12373        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12374            cx.propagate();
12375            return;
12376        }
12377        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12378        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12379            s.move_with(|map, selection| {
12380                selection.collapse_to(
12381                    movement::end_of_excerpt(
12382                        map,
12383                        selection.head(),
12384                        workspace::searchable::Direction::Prev,
12385                    ),
12386                    SelectionGoal::None,
12387                )
12388            });
12389        })
12390    }
12391
12392    pub fn select_to_start_of_excerpt(
12393        &mut self,
12394        _: &SelectToStartOfExcerpt,
12395        window: &mut Window,
12396        cx: &mut Context<Self>,
12397    ) {
12398        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12399            cx.propagate();
12400            return;
12401        }
12402        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12403        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12404            s.move_heads_with(|map, head, _| {
12405                (
12406                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12407                    SelectionGoal::None,
12408                )
12409            });
12410        })
12411    }
12412
12413    pub fn select_to_start_of_next_excerpt(
12414        &mut self,
12415        _: &SelectToStartOfNextExcerpt,
12416        window: &mut Window,
12417        cx: &mut Context<Self>,
12418    ) {
12419        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12420            cx.propagate();
12421            return;
12422        }
12423        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12424        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12425            s.move_heads_with(|map, head, _| {
12426                (
12427                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12428                    SelectionGoal::None,
12429                )
12430            });
12431        })
12432    }
12433
12434    pub fn select_to_end_of_excerpt(
12435        &mut self,
12436        _: &SelectToEndOfExcerpt,
12437        window: &mut Window,
12438        cx: &mut Context<Self>,
12439    ) {
12440        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12441            cx.propagate();
12442            return;
12443        }
12444        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12445        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12446            s.move_heads_with(|map, head, _| {
12447                (
12448                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12449                    SelectionGoal::None,
12450                )
12451            });
12452        })
12453    }
12454
12455    pub fn select_to_end_of_previous_excerpt(
12456        &mut self,
12457        _: &SelectToEndOfPreviousExcerpt,
12458        window: &mut Window,
12459        cx: &mut Context<Self>,
12460    ) {
12461        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12462            cx.propagate();
12463            return;
12464        }
12465        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12466        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12467            s.move_heads_with(|map, head, _| {
12468                (
12469                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12470                    SelectionGoal::None,
12471                )
12472            });
12473        })
12474    }
12475
12476    pub fn move_to_beginning(
12477        &mut self,
12478        _: &MoveToBeginning,
12479        window: &mut Window,
12480        cx: &mut Context<Self>,
12481    ) {
12482        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12483            cx.propagate();
12484            return;
12485        }
12486        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12487        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12488            s.select_ranges(vec![0..0]);
12489        });
12490    }
12491
12492    pub fn select_to_beginning(
12493        &mut self,
12494        _: &SelectToBeginning,
12495        window: &mut Window,
12496        cx: &mut Context<Self>,
12497    ) {
12498        let mut selection = self.selections.last::<Point>(cx);
12499        selection.set_head(Point::zero(), SelectionGoal::None);
12500        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12501        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12502            s.select(vec![selection]);
12503        });
12504    }
12505
12506    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12507        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12508            cx.propagate();
12509            return;
12510        }
12511        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12512        let cursor = self.buffer.read(cx).read(cx).len();
12513        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12514            s.select_ranges(vec![cursor..cursor])
12515        });
12516    }
12517
12518    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12519        self.nav_history = nav_history;
12520    }
12521
12522    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12523        self.nav_history.as_ref()
12524    }
12525
12526    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12527        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12528    }
12529
12530    fn push_to_nav_history(
12531        &mut self,
12532        cursor_anchor: Anchor,
12533        new_position: Option<Point>,
12534        is_deactivate: bool,
12535        cx: &mut Context<Self>,
12536    ) {
12537        if let Some(nav_history) = self.nav_history.as_mut() {
12538            let buffer = self.buffer.read(cx).read(cx);
12539            let cursor_position = cursor_anchor.to_point(&buffer);
12540            let scroll_state = self.scroll_manager.anchor();
12541            let scroll_top_row = scroll_state.top_row(&buffer);
12542            drop(buffer);
12543
12544            if let Some(new_position) = new_position {
12545                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12546                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12547                    return;
12548                }
12549            }
12550
12551            nav_history.push(
12552                Some(NavigationData {
12553                    cursor_anchor,
12554                    cursor_position,
12555                    scroll_anchor: scroll_state,
12556                    scroll_top_row,
12557                }),
12558                cx,
12559            );
12560            cx.emit(EditorEvent::PushedToNavHistory {
12561                anchor: cursor_anchor,
12562                is_deactivate,
12563            })
12564        }
12565    }
12566
12567    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12568        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12569        let buffer = self.buffer.read(cx).snapshot(cx);
12570        let mut selection = self.selections.first::<usize>(cx);
12571        selection.set_head(buffer.len(), SelectionGoal::None);
12572        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12573            s.select(vec![selection]);
12574        });
12575    }
12576
12577    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12578        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12579        let end = self.buffer.read(cx).read(cx).len();
12580        self.change_selections(None, window, cx, |s| {
12581            s.select_ranges(vec![0..end]);
12582        });
12583    }
12584
12585    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12586        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12587        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12588        let mut selections = self.selections.all::<Point>(cx);
12589        let max_point = display_map.buffer_snapshot.max_point();
12590        for selection in &mut selections {
12591            let rows = selection.spanned_rows(true, &display_map);
12592            selection.start = Point::new(rows.start.0, 0);
12593            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12594            selection.reversed = false;
12595        }
12596        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12597            s.select(selections);
12598        });
12599    }
12600
12601    pub fn split_selection_into_lines(
12602        &mut self,
12603        _: &SplitSelectionIntoLines,
12604        window: &mut Window,
12605        cx: &mut Context<Self>,
12606    ) {
12607        let selections = self
12608            .selections
12609            .all::<Point>(cx)
12610            .into_iter()
12611            .map(|selection| selection.start..selection.end)
12612            .collect::<Vec<_>>();
12613        self.unfold_ranges(&selections, true, true, cx);
12614
12615        let mut new_selection_ranges = Vec::new();
12616        {
12617            let buffer = self.buffer.read(cx).read(cx);
12618            for selection in selections {
12619                for row in selection.start.row..selection.end.row {
12620                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12621                    new_selection_ranges.push(cursor..cursor);
12622                }
12623
12624                let is_multiline_selection = selection.start.row != selection.end.row;
12625                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12626                // so this action feels more ergonomic when paired with other selection operations
12627                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12628                if !should_skip_last {
12629                    new_selection_ranges.push(selection.end..selection.end);
12630                }
12631            }
12632        }
12633        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12634            s.select_ranges(new_selection_ranges);
12635        });
12636    }
12637
12638    pub fn add_selection_above(
12639        &mut self,
12640        _: &AddSelectionAbove,
12641        window: &mut Window,
12642        cx: &mut Context<Self>,
12643    ) {
12644        self.add_selection(true, window, cx);
12645    }
12646
12647    pub fn add_selection_below(
12648        &mut self,
12649        _: &AddSelectionBelow,
12650        window: &mut Window,
12651        cx: &mut Context<Self>,
12652    ) {
12653        self.add_selection(false, window, cx);
12654    }
12655
12656    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12657        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12658
12659        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12660        let mut selections = self.selections.all::<Point>(cx);
12661        let text_layout_details = self.text_layout_details(window);
12662        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12663            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12664            let range = oldest_selection.display_range(&display_map).sorted();
12665
12666            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12667            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12668            let positions = start_x.min(end_x)..start_x.max(end_x);
12669
12670            selections.clear();
12671            let mut stack = Vec::new();
12672            for row in range.start.row().0..=range.end.row().0 {
12673                if let Some(selection) = self.selections.build_columnar_selection(
12674                    &display_map,
12675                    DisplayRow(row),
12676                    &positions,
12677                    oldest_selection.reversed,
12678                    &text_layout_details,
12679                ) {
12680                    stack.push(selection.id);
12681                    selections.push(selection);
12682                }
12683            }
12684
12685            if above {
12686                stack.reverse();
12687            }
12688
12689            AddSelectionsState { above, stack }
12690        });
12691
12692        let last_added_selection = *state.stack.last().unwrap();
12693        let mut new_selections = Vec::new();
12694        if above == state.above {
12695            let end_row = if above {
12696                DisplayRow(0)
12697            } else {
12698                display_map.max_point().row()
12699            };
12700
12701            'outer: for selection in selections {
12702                if selection.id == last_added_selection {
12703                    let range = selection.display_range(&display_map).sorted();
12704                    debug_assert_eq!(range.start.row(), range.end.row());
12705                    let mut row = range.start.row();
12706                    let positions =
12707                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12708                            px(start)..px(end)
12709                        } else {
12710                            let start_x =
12711                                display_map.x_for_display_point(range.start, &text_layout_details);
12712                            let end_x =
12713                                display_map.x_for_display_point(range.end, &text_layout_details);
12714                            start_x.min(end_x)..start_x.max(end_x)
12715                        };
12716
12717                    while row != end_row {
12718                        if above {
12719                            row.0 -= 1;
12720                        } else {
12721                            row.0 += 1;
12722                        }
12723
12724                        if let Some(new_selection) = self.selections.build_columnar_selection(
12725                            &display_map,
12726                            row,
12727                            &positions,
12728                            selection.reversed,
12729                            &text_layout_details,
12730                        ) {
12731                            state.stack.push(new_selection.id);
12732                            if above {
12733                                new_selections.push(new_selection);
12734                                new_selections.push(selection);
12735                            } else {
12736                                new_selections.push(selection);
12737                                new_selections.push(new_selection);
12738                            }
12739
12740                            continue 'outer;
12741                        }
12742                    }
12743                }
12744
12745                new_selections.push(selection);
12746            }
12747        } else {
12748            new_selections = selections;
12749            new_selections.retain(|s| s.id != last_added_selection);
12750            state.stack.pop();
12751        }
12752
12753        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12754            s.select(new_selections);
12755        });
12756        if state.stack.len() > 1 {
12757            self.add_selections_state = Some(state);
12758        }
12759    }
12760
12761    fn select_match_ranges(
12762        &mut self,
12763        range: Range<usize>,
12764        reversed: bool,
12765        replace_newest: bool,
12766        auto_scroll: Option<Autoscroll>,
12767        window: &mut Window,
12768        cx: &mut Context<Editor>,
12769    ) {
12770        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12771        self.change_selections(auto_scroll, window, cx, |s| {
12772            if replace_newest {
12773                s.delete(s.newest_anchor().id);
12774            }
12775            if reversed {
12776                s.insert_range(range.end..range.start);
12777            } else {
12778                s.insert_range(range);
12779            }
12780        });
12781    }
12782
12783    pub fn select_next_match_internal(
12784        &mut self,
12785        display_map: &DisplaySnapshot,
12786        replace_newest: bool,
12787        autoscroll: Option<Autoscroll>,
12788        window: &mut Window,
12789        cx: &mut Context<Self>,
12790    ) -> Result<()> {
12791        let buffer = &display_map.buffer_snapshot;
12792        let mut selections = self.selections.all::<usize>(cx);
12793        if let Some(mut select_next_state) = self.select_next_state.take() {
12794            let query = &select_next_state.query;
12795            if !select_next_state.done {
12796                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12797                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12798                let mut next_selected_range = None;
12799
12800                let bytes_after_last_selection =
12801                    buffer.bytes_in_range(last_selection.end..buffer.len());
12802                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12803                let query_matches = query
12804                    .stream_find_iter(bytes_after_last_selection)
12805                    .map(|result| (last_selection.end, result))
12806                    .chain(
12807                        query
12808                            .stream_find_iter(bytes_before_first_selection)
12809                            .map(|result| (0, result)),
12810                    );
12811
12812                for (start_offset, query_match) in query_matches {
12813                    let query_match = query_match.unwrap(); // can only fail due to I/O
12814                    let offset_range =
12815                        start_offset + query_match.start()..start_offset + query_match.end();
12816                    let display_range = offset_range.start.to_display_point(display_map)
12817                        ..offset_range.end.to_display_point(display_map);
12818
12819                    if !select_next_state.wordwise
12820                        || (!movement::is_inside_word(display_map, display_range.start)
12821                            && !movement::is_inside_word(display_map, display_range.end))
12822                    {
12823                        // TODO: This is n^2, because we might check all the selections
12824                        if !selections
12825                            .iter()
12826                            .any(|selection| selection.range().overlaps(&offset_range))
12827                        {
12828                            next_selected_range = Some(offset_range);
12829                            break;
12830                        }
12831                    }
12832                }
12833
12834                if let Some(next_selected_range) = next_selected_range {
12835                    self.select_match_ranges(
12836                        next_selected_range,
12837                        last_selection.reversed,
12838                        replace_newest,
12839                        autoscroll,
12840                        window,
12841                        cx,
12842                    );
12843                } else {
12844                    select_next_state.done = true;
12845                }
12846            }
12847
12848            self.select_next_state = Some(select_next_state);
12849        } else {
12850            let mut only_carets = true;
12851            let mut same_text_selected = true;
12852            let mut selected_text = None;
12853
12854            let mut selections_iter = selections.iter().peekable();
12855            while let Some(selection) = selections_iter.next() {
12856                if selection.start != selection.end {
12857                    only_carets = false;
12858                }
12859
12860                if same_text_selected {
12861                    if selected_text.is_none() {
12862                        selected_text =
12863                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12864                    }
12865
12866                    if let Some(next_selection) = selections_iter.peek() {
12867                        if next_selection.range().len() == selection.range().len() {
12868                            let next_selected_text = buffer
12869                                .text_for_range(next_selection.range())
12870                                .collect::<String>();
12871                            if Some(next_selected_text) != selected_text {
12872                                same_text_selected = false;
12873                                selected_text = None;
12874                            }
12875                        } else {
12876                            same_text_selected = false;
12877                            selected_text = None;
12878                        }
12879                    }
12880                }
12881            }
12882
12883            if only_carets {
12884                for selection in &mut selections {
12885                    let word_range = movement::surrounding_word(
12886                        display_map,
12887                        selection.start.to_display_point(display_map),
12888                    );
12889                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12890                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12891                    selection.goal = SelectionGoal::None;
12892                    selection.reversed = false;
12893                    self.select_match_ranges(
12894                        selection.start..selection.end,
12895                        selection.reversed,
12896                        replace_newest,
12897                        autoscroll,
12898                        window,
12899                        cx,
12900                    );
12901                }
12902
12903                if selections.len() == 1 {
12904                    let selection = selections
12905                        .last()
12906                        .expect("ensured that there's only one selection");
12907                    let query = buffer
12908                        .text_for_range(selection.start..selection.end)
12909                        .collect::<String>();
12910                    let is_empty = query.is_empty();
12911                    let select_state = SelectNextState {
12912                        query: AhoCorasick::new(&[query])?,
12913                        wordwise: true,
12914                        done: is_empty,
12915                    };
12916                    self.select_next_state = Some(select_state);
12917                } else {
12918                    self.select_next_state = None;
12919                }
12920            } else if let Some(selected_text) = selected_text {
12921                self.select_next_state = Some(SelectNextState {
12922                    query: AhoCorasick::new(&[selected_text])?,
12923                    wordwise: false,
12924                    done: false,
12925                });
12926                self.select_next_match_internal(
12927                    display_map,
12928                    replace_newest,
12929                    autoscroll,
12930                    window,
12931                    cx,
12932                )?;
12933            }
12934        }
12935        Ok(())
12936    }
12937
12938    pub fn select_all_matches(
12939        &mut self,
12940        _action: &SelectAllMatches,
12941        window: &mut Window,
12942        cx: &mut Context<Self>,
12943    ) -> Result<()> {
12944        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12945
12946        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12947
12948        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12949        let Some(select_next_state) = self.select_next_state.as_mut() else {
12950            return Ok(());
12951        };
12952        if select_next_state.done {
12953            return Ok(());
12954        }
12955
12956        let mut new_selections = Vec::new();
12957
12958        let reversed = self.selections.oldest::<usize>(cx).reversed;
12959        let buffer = &display_map.buffer_snapshot;
12960        let query_matches = select_next_state
12961            .query
12962            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12963
12964        for query_match in query_matches.into_iter() {
12965            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12966            let offset_range = if reversed {
12967                query_match.end()..query_match.start()
12968            } else {
12969                query_match.start()..query_match.end()
12970            };
12971            let display_range = offset_range.start.to_display_point(&display_map)
12972                ..offset_range.end.to_display_point(&display_map);
12973
12974            if !select_next_state.wordwise
12975                || (!movement::is_inside_word(&display_map, display_range.start)
12976                    && !movement::is_inside_word(&display_map, display_range.end))
12977            {
12978                new_selections.push(offset_range.start..offset_range.end);
12979            }
12980        }
12981
12982        select_next_state.done = true;
12983        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12984        self.change_selections(None, window, cx, |selections| {
12985            selections.select_ranges(new_selections)
12986        });
12987
12988        Ok(())
12989    }
12990
12991    pub fn select_next(
12992        &mut self,
12993        action: &SelectNext,
12994        window: &mut Window,
12995        cx: &mut Context<Self>,
12996    ) -> Result<()> {
12997        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12998        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12999        self.select_next_match_internal(
13000            &display_map,
13001            action.replace_newest,
13002            Some(Autoscroll::newest()),
13003            window,
13004            cx,
13005        )?;
13006        Ok(())
13007    }
13008
13009    pub fn select_previous(
13010        &mut self,
13011        action: &SelectPrevious,
13012        window: &mut Window,
13013        cx: &mut Context<Self>,
13014    ) -> Result<()> {
13015        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13016        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13017        let buffer = &display_map.buffer_snapshot;
13018        let mut selections = self.selections.all::<usize>(cx);
13019        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13020            let query = &select_prev_state.query;
13021            if !select_prev_state.done {
13022                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13023                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13024                let mut next_selected_range = None;
13025                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13026                let bytes_before_last_selection =
13027                    buffer.reversed_bytes_in_range(0..last_selection.start);
13028                let bytes_after_first_selection =
13029                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13030                let query_matches = query
13031                    .stream_find_iter(bytes_before_last_selection)
13032                    .map(|result| (last_selection.start, result))
13033                    .chain(
13034                        query
13035                            .stream_find_iter(bytes_after_first_selection)
13036                            .map(|result| (buffer.len(), result)),
13037                    );
13038                for (end_offset, query_match) in query_matches {
13039                    let query_match = query_match.unwrap(); // can only fail due to I/O
13040                    let offset_range =
13041                        end_offset - query_match.end()..end_offset - query_match.start();
13042                    let display_range = offset_range.start.to_display_point(&display_map)
13043                        ..offset_range.end.to_display_point(&display_map);
13044
13045                    if !select_prev_state.wordwise
13046                        || (!movement::is_inside_word(&display_map, display_range.start)
13047                            && !movement::is_inside_word(&display_map, display_range.end))
13048                    {
13049                        next_selected_range = Some(offset_range);
13050                        break;
13051                    }
13052                }
13053
13054                if let Some(next_selected_range) = next_selected_range {
13055                    self.select_match_ranges(
13056                        next_selected_range,
13057                        last_selection.reversed,
13058                        action.replace_newest,
13059                        Some(Autoscroll::newest()),
13060                        window,
13061                        cx,
13062                    );
13063                } else {
13064                    select_prev_state.done = true;
13065                }
13066            }
13067
13068            self.select_prev_state = Some(select_prev_state);
13069        } else {
13070            let mut only_carets = true;
13071            let mut same_text_selected = true;
13072            let mut selected_text = None;
13073
13074            let mut selections_iter = selections.iter().peekable();
13075            while let Some(selection) = selections_iter.next() {
13076                if selection.start != selection.end {
13077                    only_carets = false;
13078                }
13079
13080                if same_text_selected {
13081                    if selected_text.is_none() {
13082                        selected_text =
13083                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13084                    }
13085
13086                    if let Some(next_selection) = selections_iter.peek() {
13087                        if next_selection.range().len() == selection.range().len() {
13088                            let next_selected_text = buffer
13089                                .text_for_range(next_selection.range())
13090                                .collect::<String>();
13091                            if Some(next_selected_text) != selected_text {
13092                                same_text_selected = false;
13093                                selected_text = None;
13094                            }
13095                        } else {
13096                            same_text_selected = false;
13097                            selected_text = None;
13098                        }
13099                    }
13100                }
13101            }
13102
13103            if only_carets {
13104                for selection in &mut selections {
13105                    let word_range = movement::surrounding_word(
13106                        &display_map,
13107                        selection.start.to_display_point(&display_map),
13108                    );
13109                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13110                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13111                    selection.goal = SelectionGoal::None;
13112                    selection.reversed = false;
13113                    self.select_match_ranges(
13114                        selection.start..selection.end,
13115                        selection.reversed,
13116                        action.replace_newest,
13117                        Some(Autoscroll::newest()),
13118                        window,
13119                        cx,
13120                    );
13121                }
13122                if selections.len() == 1 {
13123                    let selection = selections
13124                        .last()
13125                        .expect("ensured that there's only one selection");
13126                    let query = buffer
13127                        .text_for_range(selection.start..selection.end)
13128                        .collect::<String>();
13129                    let is_empty = query.is_empty();
13130                    let select_state = SelectNextState {
13131                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13132                        wordwise: true,
13133                        done: is_empty,
13134                    };
13135                    self.select_prev_state = Some(select_state);
13136                } else {
13137                    self.select_prev_state = None;
13138                }
13139            } else if let Some(selected_text) = selected_text {
13140                self.select_prev_state = Some(SelectNextState {
13141                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13142                    wordwise: false,
13143                    done: false,
13144                });
13145                self.select_previous(action, window, cx)?;
13146            }
13147        }
13148        Ok(())
13149    }
13150
13151    pub fn find_next_match(
13152        &mut self,
13153        _: &FindNextMatch,
13154        window: &mut Window,
13155        cx: &mut Context<Self>,
13156    ) -> Result<()> {
13157        let selections = self.selections.disjoint_anchors();
13158        match selections.first() {
13159            Some(first) if selections.len() >= 2 => {
13160                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13161                    s.select_ranges([first.range()]);
13162                });
13163            }
13164            _ => self.select_next(
13165                &SelectNext {
13166                    replace_newest: true,
13167                },
13168                window,
13169                cx,
13170            )?,
13171        }
13172        Ok(())
13173    }
13174
13175    pub fn find_previous_match(
13176        &mut self,
13177        _: &FindPreviousMatch,
13178        window: &mut Window,
13179        cx: &mut Context<Self>,
13180    ) -> Result<()> {
13181        let selections = self.selections.disjoint_anchors();
13182        match selections.last() {
13183            Some(last) if selections.len() >= 2 => {
13184                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13185                    s.select_ranges([last.range()]);
13186                });
13187            }
13188            _ => self.select_previous(
13189                &SelectPrevious {
13190                    replace_newest: true,
13191                },
13192                window,
13193                cx,
13194            )?,
13195        }
13196        Ok(())
13197    }
13198
13199    pub fn toggle_comments(
13200        &mut self,
13201        action: &ToggleComments,
13202        window: &mut Window,
13203        cx: &mut Context<Self>,
13204    ) {
13205        if self.read_only(cx) {
13206            return;
13207        }
13208        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
13209        let text_layout_details = &self.text_layout_details(window);
13210        self.transact(window, cx, |this, window, cx| {
13211            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13212            let mut edits = Vec::new();
13213            let mut selection_edit_ranges = Vec::new();
13214            let mut last_toggled_row = None;
13215            let snapshot = this.buffer.read(cx).read(cx);
13216            let empty_str: Arc<str> = Arc::default();
13217            let mut suffixes_inserted = Vec::new();
13218            let ignore_indent = action.ignore_indent;
13219
13220            fn comment_prefix_range(
13221                snapshot: &MultiBufferSnapshot,
13222                row: MultiBufferRow,
13223                comment_prefix: &str,
13224                comment_prefix_whitespace: &str,
13225                ignore_indent: bool,
13226            ) -> Range<Point> {
13227                let indent_size = if ignore_indent {
13228                    0
13229                } else {
13230                    snapshot.indent_size_for_line(row).len
13231                };
13232
13233                let start = Point::new(row.0, indent_size);
13234
13235                let mut line_bytes = snapshot
13236                    .bytes_in_range(start..snapshot.max_point())
13237                    .flatten()
13238                    .copied();
13239
13240                // If this line currently begins with the line comment prefix, then record
13241                // the range containing the prefix.
13242                if line_bytes
13243                    .by_ref()
13244                    .take(comment_prefix.len())
13245                    .eq(comment_prefix.bytes())
13246                {
13247                    // Include any whitespace that matches the comment prefix.
13248                    let matching_whitespace_len = line_bytes
13249                        .zip(comment_prefix_whitespace.bytes())
13250                        .take_while(|(a, b)| a == b)
13251                        .count() as u32;
13252                    let end = Point::new(
13253                        start.row,
13254                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13255                    );
13256                    start..end
13257                } else {
13258                    start..start
13259                }
13260            }
13261
13262            fn comment_suffix_range(
13263                snapshot: &MultiBufferSnapshot,
13264                row: MultiBufferRow,
13265                comment_suffix: &str,
13266                comment_suffix_has_leading_space: bool,
13267            ) -> Range<Point> {
13268                let end = Point::new(row.0, snapshot.line_len(row));
13269                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13270
13271                let mut line_end_bytes = snapshot
13272                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13273                    .flatten()
13274                    .copied();
13275
13276                let leading_space_len = if suffix_start_column > 0
13277                    && line_end_bytes.next() == Some(b' ')
13278                    && comment_suffix_has_leading_space
13279                {
13280                    1
13281                } else {
13282                    0
13283                };
13284
13285                // If this line currently begins with the line comment prefix, then record
13286                // the range containing the prefix.
13287                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13288                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13289                    start..end
13290                } else {
13291                    end..end
13292                }
13293            }
13294
13295            // TODO: Handle selections that cross excerpts
13296            for selection in &mut selections {
13297                let start_column = snapshot
13298                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13299                    .len;
13300                let language = if let Some(language) =
13301                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13302                {
13303                    language
13304                } else {
13305                    continue;
13306                };
13307
13308                selection_edit_ranges.clear();
13309
13310                // If multiple selections contain a given row, avoid processing that
13311                // row more than once.
13312                let mut start_row = MultiBufferRow(selection.start.row);
13313                if last_toggled_row == Some(start_row) {
13314                    start_row = start_row.next_row();
13315                }
13316                let end_row =
13317                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13318                        MultiBufferRow(selection.end.row - 1)
13319                    } else {
13320                        MultiBufferRow(selection.end.row)
13321                    };
13322                last_toggled_row = Some(end_row);
13323
13324                if start_row > end_row {
13325                    continue;
13326                }
13327
13328                // If the language has line comments, toggle those.
13329                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13330
13331                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13332                if ignore_indent {
13333                    full_comment_prefixes = full_comment_prefixes
13334                        .into_iter()
13335                        .map(|s| Arc::from(s.trim_end()))
13336                        .collect();
13337                }
13338
13339                if !full_comment_prefixes.is_empty() {
13340                    let first_prefix = full_comment_prefixes
13341                        .first()
13342                        .expect("prefixes is non-empty");
13343                    let prefix_trimmed_lengths = full_comment_prefixes
13344                        .iter()
13345                        .map(|p| p.trim_end_matches(' ').len())
13346                        .collect::<SmallVec<[usize; 4]>>();
13347
13348                    let mut all_selection_lines_are_comments = true;
13349
13350                    for row in start_row.0..=end_row.0 {
13351                        let row = MultiBufferRow(row);
13352                        if start_row < end_row && snapshot.is_line_blank(row) {
13353                            continue;
13354                        }
13355
13356                        let prefix_range = full_comment_prefixes
13357                            .iter()
13358                            .zip(prefix_trimmed_lengths.iter().copied())
13359                            .map(|(prefix, trimmed_prefix_len)| {
13360                                comment_prefix_range(
13361                                    snapshot.deref(),
13362                                    row,
13363                                    &prefix[..trimmed_prefix_len],
13364                                    &prefix[trimmed_prefix_len..],
13365                                    ignore_indent,
13366                                )
13367                            })
13368                            .max_by_key(|range| range.end.column - range.start.column)
13369                            .expect("prefixes is non-empty");
13370
13371                        if prefix_range.is_empty() {
13372                            all_selection_lines_are_comments = false;
13373                        }
13374
13375                        selection_edit_ranges.push(prefix_range);
13376                    }
13377
13378                    if all_selection_lines_are_comments {
13379                        edits.extend(
13380                            selection_edit_ranges
13381                                .iter()
13382                                .cloned()
13383                                .map(|range| (range, empty_str.clone())),
13384                        );
13385                    } else {
13386                        let min_column = selection_edit_ranges
13387                            .iter()
13388                            .map(|range| range.start.column)
13389                            .min()
13390                            .unwrap_or(0);
13391                        edits.extend(selection_edit_ranges.iter().map(|range| {
13392                            let position = Point::new(range.start.row, min_column);
13393                            (position..position, first_prefix.clone())
13394                        }));
13395                    }
13396                } else if let Some((full_comment_prefix, comment_suffix)) =
13397                    language.block_comment_delimiters()
13398                {
13399                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13400                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13401                    let prefix_range = comment_prefix_range(
13402                        snapshot.deref(),
13403                        start_row,
13404                        comment_prefix,
13405                        comment_prefix_whitespace,
13406                        ignore_indent,
13407                    );
13408                    let suffix_range = comment_suffix_range(
13409                        snapshot.deref(),
13410                        end_row,
13411                        comment_suffix.trim_start_matches(' '),
13412                        comment_suffix.starts_with(' '),
13413                    );
13414
13415                    if prefix_range.is_empty() || suffix_range.is_empty() {
13416                        edits.push((
13417                            prefix_range.start..prefix_range.start,
13418                            full_comment_prefix.clone(),
13419                        ));
13420                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13421                        suffixes_inserted.push((end_row, comment_suffix.len()));
13422                    } else {
13423                        edits.push((prefix_range, empty_str.clone()));
13424                        edits.push((suffix_range, empty_str.clone()));
13425                    }
13426                } else {
13427                    continue;
13428                }
13429            }
13430
13431            drop(snapshot);
13432            this.buffer.update(cx, |buffer, cx| {
13433                buffer.edit(edits, None, cx);
13434            });
13435
13436            // Adjust selections so that they end before any comment suffixes that
13437            // were inserted.
13438            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13439            let mut selections = this.selections.all::<Point>(cx);
13440            let snapshot = this.buffer.read(cx).read(cx);
13441            for selection in &mut selections {
13442                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13443                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13444                        Ordering::Less => {
13445                            suffixes_inserted.next();
13446                            continue;
13447                        }
13448                        Ordering::Greater => break,
13449                        Ordering::Equal => {
13450                            if selection.end.column == snapshot.line_len(row) {
13451                                if selection.is_empty() {
13452                                    selection.start.column -= suffix_len as u32;
13453                                }
13454                                selection.end.column -= suffix_len as u32;
13455                            }
13456                            break;
13457                        }
13458                    }
13459                }
13460            }
13461
13462            drop(snapshot);
13463            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13464                s.select(selections)
13465            });
13466
13467            let selections = this.selections.all::<Point>(cx);
13468            let selections_on_single_row = selections.windows(2).all(|selections| {
13469                selections[0].start.row == selections[1].start.row
13470                    && selections[0].end.row == selections[1].end.row
13471                    && selections[0].start.row == selections[0].end.row
13472            });
13473            let selections_selecting = selections
13474                .iter()
13475                .any(|selection| selection.start != selection.end);
13476            let advance_downwards = action.advance_downwards
13477                && selections_on_single_row
13478                && !selections_selecting
13479                && !matches!(this.mode, EditorMode::SingleLine { .. });
13480
13481            if advance_downwards {
13482                let snapshot = this.buffer.read(cx).snapshot(cx);
13483
13484                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13485                    s.move_cursors_with(|display_snapshot, display_point, _| {
13486                        let mut point = display_point.to_point(display_snapshot);
13487                        point.row += 1;
13488                        point = snapshot.clip_point(point, Bias::Left);
13489                        let display_point = point.to_display_point(display_snapshot);
13490                        let goal = SelectionGoal::HorizontalPosition(
13491                            display_snapshot
13492                                .x_for_display_point(display_point, text_layout_details)
13493                                .into(),
13494                        );
13495                        (display_point, goal)
13496                    })
13497                });
13498            }
13499        });
13500    }
13501
13502    pub fn select_enclosing_symbol(
13503        &mut self,
13504        _: &SelectEnclosingSymbol,
13505        window: &mut Window,
13506        cx: &mut Context<Self>,
13507    ) {
13508        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13509
13510        let buffer = self.buffer.read(cx).snapshot(cx);
13511        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13512
13513        fn update_selection(
13514            selection: &Selection<usize>,
13515            buffer_snap: &MultiBufferSnapshot,
13516        ) -> Option<Selection<usize>> {
13517            let cursor = selection.head();
13518            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13519            for symbol in symbols.iter().rev() {
13520                let start = symbol.range.start.to_offset(buffer_snap);
13521                let end = symbol.range.end.to_offset(buffer_snap);
13522                let new_range = start..end;
13523                if start < selection.start || end > selection.end {
13524                    return Some(Selection {
13525                        id: selection.id,
13526                        start: new_range.start,
13527                        end: new_range.end,
13528                        goal: SelectionGoal::None,
13529                        reversed: selection.reversed,
13530                    });
13531                }
13532            }
13533            None
13534        }
13535
13536        let mut selected_larger_symbol = false;
13537        let new_selections = old_selections
13538            .iter()
13539            .map(|selection| match update_selection(selection, &buffer) {
13540                Some(new_selection) => {
13541                    if new_selection.range() != selection.range() {
13542                        selected_larger_symbol = true;
13543                    }
13544                    new_selection
13545                }
13546                None => selection.clone(),
13547            })
13548            .collect::<Vec<_>>();
13549
13550        if selected_larger_symbol {
13551            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13552                s.select(new_selections);
13553            });
13554        }
13555    }
13556
13557    pub fn select_larger_syntax_node(
13558        &mut self,
13559        _: &SelectLargerSyntaxNode,
13560        window: &mut Window,
13561        cx: &mut Context<Self>,
13562    ) {
13563        let Some(visible_row_count) = self.visible_row_count() else {
13564            return;
13565        };
13566        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13567        if old_selections.is_empty() {
13568            return;
13569        }
13570
13571        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13572
13573        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13574        let buffer = self.buffer.read(cx).snapshot(cx);
13575
13576        let mut selected_larger_node = false;
13577        let mut new_selections = old_selections
13578            .iter()
13579            .map(|selection| {
13580                let old_range = selection.start..selection.end;
13581
13582                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13583                    // manually select word at selection
13584                    if ["string_content", "inline"].contains(&node.kind()) {
13585                        let word_range = {
13586                            let display_point = buffer
13587                                .offset_to_point(old_range.start)
13588                                .to_display_point(&display_map);
13589                            let Range { start, end } =
13590                                movement::surrounding_word(&display_map, display_point);
13591                            start.to_point(&display_map).to_offset(&buffer)
13592                                ..end.to_point(&display_map).to_offset(&buffer)
13593                        };
13594                        // ignore if word is already selected
13595                        if !word_range.is_empty() && old_range != word_range {
13596                            let last_word_range = {
13597                                let display_point = buffer
13598                                    .offset_to_point(old_range.end)
13599                                    .to_display_point(&display_map);
13600                                let Range { start, end } =
13601                                    movement::surrounding_word(&display_map, display_point);
13602                                start.to_point(&display_map).to_offset(&buffer)
13603                                    ..end.to_point(&display_map).to_offset(&buffer)
13604                            };
13605                            // only select word if start and end point belongs to same word
13606                            if word_range == last_word_range {
13607                                selected_larger_node = true;
13608                                return Selection {
13609                                    id: selection.id,
13610                                    start: word_range.start,
13611                                    end: word_range.end,
13612                                    goal: SelectionGoal::None,
13613                                    reversed: selection.reversed,
13614                                };
13615                            }
13616                        }
13617                    }
13618                }
13619
13620                let mut new_range = old_range.clone();
13621                while let Some((_node, containing_range)) =
13622                    buffer.syntax_ancestor(new_range.clone())
13623                {
13624                    new_range = match containing_range {
13625                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13626                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13627                    };
13628                    if !display_map.intersects_fold(new_range.start)
13629                        && !display_map.intersects_fold(new_range.end)
13630                    {
13631                        break;
13632                    }
13633                }
13634
13635                selected_larger_node |= new_range != old_range;
13636                Selection {
13637                    id: selection.id,
13638                    start: new_range.start,
13639                    end: new_range.end,
13640                    goal: SelectionGoal::None,
13641                    reversed: selection.reversed,
13642                }
13643            })
13644            .collect::<Vec<_>>();
13645
13646        if !selected_larger_node {
13647            return; // don't put this call in the history
13648        }
13649
13650        // scroll based on transformation done to the last selection created by the user
13651        let (last_old, last_new) = old_selections
13652            .last()
13653            .zip(new_selections.last().cloned())
13654            .expect("old_selections isn't empty");
13655
13656        // revert selection
13657        let is_selection_reversed = {
13658            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13659            new_selections.last_mut().expect("checked above").reversed =
13660                should_newest_selection_be_reversed;
13661            should_newest_selection_be_reversed
13662        };
13663
13664        if selected_larger_node {
13665            self.select_syntax_node_history.disable_clearing = true;
13666            self.change_selections(None, window, cx, |s| {
13667                s.select(new_selections.clone());
13668            });
13669            self.select_syntax_node_history.disable_clearing = false;
13670        }
13671
13672        let start_row = last_new.start.to_display_point(&display_map).row().0;
13673        let end_row = last_new.end.to_display_point(&display_map).row().0;
13674        let selection_height = end_row - start_row + 1;
13675        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13676
13677        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13678        let scroll_behavior = if fits_on_the_screen {
13679            self.request_autoscroll(Autoscroll::fit(), cx);
13680            SelectSyntaxNodeScrollBehavior::FitSelection
13681        } else if is_selection_reversed {
13682            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13683            SelectSyntaxNodeScrollBehavior::CursorTop
13684        } else {
13685            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13686            SelectSyntaxNodeScrollBehavior::CursorBottom
13687        };
13688
13689        self.select_syntax_node_history.push((
13690            old_selections,
13691            scroll_behavior,
13692            is_selection_reversed,
13693        ));
13694    }
13695
13696    pub fn select_smaller_syntax_node(
13697        &mut self,
13698        _: &SelectSmallerSyntaxNode,
13699        window: &mut Window,
13700        cx: &mut Context<Self>,
13701    ) {
13702        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13703
13704        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13705            self.select_syntax_node_history.pop()
13706        {
13707            if let Some(selection) = selections.last_mut() {
13708                selection.reversed = is_selection_reversed;
13709            }
13710
13711            self.select_syntax_node_history.disable_clearing = true;
13712            self.change_selections(None, window, cx, |s| {
13713                s.select(selections.to_vec());
13714            });
13715            self.select_syntax_node_history.disable_clearing = false;
13716
13717            match scroll_behavior {
13718                SelectSyntaxNodeScrollBehavior::CursorTop => {
13719                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13720                }
13721                SelectSyntaxNodeScrollBehavior::FitSelection => {
13722                    self.request_autoscroll(Autoscroll::fit(), cx);
13723                }
13724                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13725                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13726                }
13727            }
13728        }
13729    }
13730
13731    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13732        if !EditorSettings::get_global(cx).gutter.runnables {
13733            self.clear_tasks();
13734            return Task::ready(());
13735        }
13736        let project = self.project.as_ref().map(Entity::downgrade);
13737        let task_sources = self.lsp_task_sources(cx);
13738        let multi_buffer = self.buffer.downgrade();
13739        cx.spawn_in(window, async move |editor, cx| {
13740            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13741            let Some(project) = project.and_then(|p| p.upgrade()) else {
13742                return;
13743            };
13744            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13745                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13746            }) else {
13747                return;
13748            };
13749
13750            let hide_runnables = project
13751                .update(cx, |project, cx| {
13752                    // Do not display any test indicators in non-dev server remote projects.
13753                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13754                })
13755                .unwrap_or(true);
13756            if hide_runnables {
13757                return;
13758            }
13759            let new_rows =
13760                cx.background_spawn({
13761                    let snapshot = display_snapshot.clone();
13762                    async move {
13763                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13764                    }
13765                })
13766                    .await;
13767            let Ok(lsp_tasks) =
13768                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13769            else {
13770                return;
13771            };
13772            let lsp_tasks = lsp_tasks.await;
13773
13774            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13775                lsp_tasks
13776                    .into_iter()
13777                    .flat_map(|(kind, tasks)| {
13778                        tasks.into_iter().filter_map(move |(location, task)| {
13779                            Some((kind.clone(), location?, task))
13780                        })
13781                    })
13782                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13783                        let buffer = location.target.buffer;
13784                        let buffer_snapshot = buffer.read(cx).snapshot();
13785                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13786                            |(excerpt_id, snapshot, _)| {
13787                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13788                                    display_snapshot
13789                                        .buffer_snapshot
13790                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13791                                } else {
13792                                    None
13793                                }
13794                            },
13795                        );
13796                        if let Some(offset) = offset {
13797                            let task_buffer_range =
13798                                location.target.range.to_point(&buffer_snapshot);
13799                            let context_buffer_range =
13800                                task_buffer_range.to_offset(&buffer_snapshot);
13801                            let context_range = BufferOffset(context_buffer_range.start)
13802                                ..BufferOffset(context_buffer_range.end);
13803
13804                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13805                                .or_insert_with(|| RunnableTasks {
13806                                    templates: Vec::new(),
13807                                    offset,
13808                                    column: task_buffer_range.start.column,
13809                                    extra_variables: HashMap::default(),
13810                                    context_range,
13811                                })
13812                                .templates
13813                                .push((kind, task.original_task().clone()));
13814                        }
13815
13816                        acc
13817                    })
13818            }) else {
13819                return;
13820            };
13821
13822            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
13823                buffer.language_settings(cx).tasks.prefer_lsp
13824            }) else {
13825                return;
13826            };
13827
13828            let rows = Self::runnable_rows(
13829                project,
13830                display_snapshot,
13831                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
13832                new_rows,
13833                cx.clone(),
13834            );
13835            editor
13836                .update(cx, |editor, _| {
13837                    editor.clear_tasks();
13838                    for (key, mut value) in rows {
13839                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13840                            value.templates.extend(lsp_tasks.templates);
13841                        }
13842
13843                        editor.insert_tasks(key, value);
13844                    }
13845                    for (key, value) in lsp_tasks_by_rows {
13846                        editor.insert_tasks(key, value);
13847                    }
13848                })
13849                .ok();
13850        })
13851    }
13852    fn fetch_runnable_ranges(
13853        snapshot: &DisplaySnapshot,
13854        range: Range<Anchor>,
13855    ) -> Vec<language::RunnableRange> {
13856        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13857    }
13858
13859    fn runnable_rows(
13860        project: Entity<Project>,
13861        snapshot: DisplaySnapshot,
13862        prefer_lsp: bool,
13863        runnable_ranges: Vec<RunnableRange>,
13864        mut cx: AsyncWindowContext,
13865    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13866        runnable_ranges
13867            .into_iter()
13868            .filter_map(|mut runnable| {
13869                let mut tasks = cx
13870                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13871                    .ok()?;
13872                if prefer_lsp {
13873                    tasks.retain(|(task_kind, _)| {
13874                        !matches!(task_kind, TaskSourceKind::Language { .. })
13875                    });
13876                }
13877                if tasks.is_empty() {
13878                    return None;
13879                }
13880
13881                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13882
13883                let row = snapshot
13884                    .buffer_snapshot
13885                    .buffer_line_for_row(MultiBufferRow(point.row))?
13886                    .1
13887                    .start
13888                    .row;
13889
13890                let context_range =
13891                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13892                Some((
13893                    (runnable.buffer_id, row),
13894                    RunnableTasks {
13895                        templates: tasks,
13896                        offset: snapshot
13897                            .buffer_snapshot
13898                            .anchor_before(runnable.run_range.start),
13899                        context_range,
13900                        column: point.column,
13901                        extra_variables: runnable.extra_captures,
13902                    },
13903                ))
13904            })
13905            .collect()
13906    }
13907
13908    fn templates_with_tags(
13909        project: &Entity<Project>,
13910        runnable: &mut Runnable,
13911        cx: &mut App,
13912    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13913        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13914            let (worktree_id, file) = project
13915                .buffer_for_id(runnable.buffer, cx)
13916                .and_then(|buffer| buffer.read(cx).file())
13917                .map(|file| (file.worktree_id(cx), file.clone()))
13918                .unzip();
13919
13920            (
13921                project.task_store().read(cx).task_inventory().cloned(),
13922                worktree_id,
13923                file,
13924            )
13925        });
13926
13927        let mut templates_with_tags = mem::take(&mut runnable.tags)
13928            .into_iter()
13929            .flat_map(|RunnableTag(tag)| {
13930                inventory
13931                    .as_ref()
13932                    .into_iter()
13933                    .flat_map(|inventory| {
13934                        inventory.read(cx).list_tasks(
13935                            file.clone(),
13936                            Some(runnable.language.clone()),
13937                            worktree_id,
13938                            cx,
13939                        )
13940                    })
13941                    .filter(move |(_, template)| {
13942                        template.tags.iter().any(|source_tag| source_tag == &tag)
13943                    })
13944            })
13945            .sorted_by_key(|(kind, _)| kind.to_owned())
13946            .collect::<Vec<_>>();
13947        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13948            // Strongest source wins; if we have worktree tag binding, prefer that to
13949            // global and language bindings;
13950            // if we have a global binding, prefer that to language binding.
13951            let first_mismatch = templates_with_tags
13952                .iter()
13953                .position(|(tag_source, _)| tag_source != leading_tag_source);
13954            if let Some(index) = first_mismatch {
13955                templates_with_tags.truncate(index);
13956            }
13957        }
13958
13959        templates_with_tags
13960    }
13961
13962    pub fn move_to_enclosing_bracket(
13963        &mut self,
13964        _: &MoveToEnclosingBracket,
13965        window: &mut Window,
13966        cx: &mut Context<Self>,
13967    ) {
13968        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13969        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13970            s.move_offsets_with(|snapshot, selection| {
13971                let Some(enclosing_bracket_ranges) =
13972                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13973                else {
13974                    return;
13975                };
13976
13977                let mut best_length = usize::MAX;
13978                let mut best_inside = false;
13979                let mut best_in_bracket_range = false;
13980                let mut best_destination = None;
13981                for (open, close) in enclosing_bracket_ranges {
13982                    let close = close.to_inclusive();
13983                    let length = close.end() - open.start;
13984                    let inside = selection.start >= open.end && selection.end <= *close.start();
13985                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13986                        || close.contains(&selection.head());
13987
13988                    // If best is next to a bracket and current isn't, skip
13989                    if !in_bracket_range && best_in_bracket_range {
13990                        continue;
13991                    }
13992
13993                    // Prefer smaller lengths unless best is inside and current isn't
13994                    if length > best_length && (best_inside || !inside) {
13995                        continue;
13996                    }
13997
13998                    best_length = length;
13999                    best_inside = inside;
14000                    best_in_bracket_range = in_bracket_range;
14001                    best_destination = Some(
14002                        if close.contains(&selection.start) && close.contains(&selection.end) {
14003                            if inside { open.end } else { open.start }
14004                        } else if inside {
14005                            *close.start()
14006                        } else {
14007                            *close.end()
14008                        },
14009                    );
14010                }
14011
14012                if let Some(destination) = best_destination {
14013                    selection.collapse_to(destination, SelectionGoal::None);
14014                }
14015            })
14016        });
14017    }
14018
14019    pub fn undo_selection(
14020        &mut self,
14021        _: &UndoSelection,
14022        window: &mut Window,
14023        cx: &mut Context<Self>,
14024    ) {
14025        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14026        self.end_selection(window, cx);
14027        self.selection_history.mode = SelectionHistoryMode::Undoing;
14028        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14029            self.change_selections(None, window, cx, |s| {
14030                s.select_anchors(entry.selections.to_vec())
14031            });
14032            self.select_next_state = entry.select_next_state;
14033            self.select_prev_state = entry.select_prev_state;
14034            self.add_selections_state = entry.add_selections_state;
14035            self.request_autoscroll(Autoscroll::newest(), cx);
14036        }
14037        self.selection_history.mode = SelectionHistoryMode::Normal;
14038    }
14039
14040    pub fn redo_selection(
14041        &mut self,
14042        _: &RedoSelection,
14043        window: &mut Window,
14044        cx: &mut Context<Self>,
14045    ) {
14046        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14047        self.end_selection(window, cx);
14048        self.selection_history.mode = SelectionHistoryMode::Redoing;
14049        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14050            self.change_selections(None, window, cx, |s| {
14051                s.select_anchors(entry.selections.to_vec())
14052            });
14053            self.select_next_state = entry.select_next_state;
14054            self.select_prev_state = entry.select_prev_state;
14055            self.add_selections_state = entry.add_selections_state;
14056            self.request_autoscroll(Autoscroll::newest(), cx);
14057        }
14058        self.selection_history.mode = SelectionHistoryMode::Normal;
14059    }
14060
14061    pub fn expand_excerpts(
14062        &mut self,
14063        action: &ExpandExcerpts,
14064        _: &mut Window,
14065        cx: &mut Context<Self>,
14066    ) {
14067        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14068    }
14069
14070    pub fn expand_excerpts_down(
14071        &mut self,
14072        action: &ExpandExcerptsDown,
14073        _: &mut Window,
14074        cx: &mut Context<Self>,
14075    ) {
14076        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14077    }
14078
14079    pub fn expand_excerpts_up(
14080        &mut self,
14081        action: &ExpandExcerptsUp,
14082        _: &mut Window,
14083        cx: &mut Context<Self>,
14084    ) {
14085        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14086    }
14087
14088    pub fn expand_excerpts_for_direction(
14089        &mut self,
14090        lines: u32,
14091        direction: ExpandExcerptDirection,
14092
14093        cx: &mut Context<Self>,
14094    ) {
14095        let selections = self.selections.disjoint_anchors();
14096
14097        let lines = if lines == 0 {
14098            EditorSettings::get_global(cx).expand_excerpt_lines
14099        } else {
14100            lines
14101        };
14102
14103        self.buffer.update(cx, |buffer, cx| {
14104            let snapshot = buffer.snapshot(cx);
14105            let mut excerpt_ids = selections
14106                .iter()
14107                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14108                .collect::<Vec<_>>();
14109            excerpt_ids.sort();
14110            excerpt_ids.dedup();
14111            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14112        })
14113    }
14114
14115    pub fn expand_excerpt(
14116        &mut self,
14117        excerpt: ExcerptId,
14118        direction: ExpandExcerptDirection,
14119        window: &mut Window,
14120        cx: &mut Context<Self>,
14121    ) {
14122        let current_scroll_position = self.scroll_position(cx);
14123        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14124        let mut should_scroll_up = false;
14125
14126        if direction == ExpandExcerptDirection::Down {
14127            let multi_buffer = self.buffer.read(cx);
14128            let snapshot = multi_buffer.snapshot(cx);
14129            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14130                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14131                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14132                        let buffer_snapshot = buffer.read(cx).snapshot();
14133                        let excerpt_end_row =
14134                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14135                        let last_row = buffer_snapshot.max_point().row;
14136                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14137                        should_scroll_up = lines_below >= lines_to_expand;
14138                    }
14139                }
14140            }
14141        }
14142
14143        self.buffer.update(cx, |buffer, cx| {
14144            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14145        });
14146
14147        if should_scroll_up {
14148            let new_scroll_position =
14149                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14150            self.set_scroll_position(new_scroll_position, window, cx);
14151        }
14152    }
14153
14154    pub fn go_to_singleton_buffer_point(
14155        &mut self,
14156        point: Point,
14157        window: &mut Window,
14158        cx: &mut Context<Self>,
14159    ) {
14160        self.go_to_singleton_buffer_range(point..point, window, cx);
14161    }
14162
14163    pub fn go_to_singleton_buffer_range(
14164        &mut self,
14165        range: Range<Point>,
14166        window: &mut Window,
14167        cx: &mut Context<Self>,
14168    ) {
14169        let multibuffer = self.buffer().read(cx);
14170        let Some(buffer) = multibuffer.as_singleton() else {
14171            return;
14172        };
14173        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14174            return;
14175        };
14176        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14177            return;
14178        };
14179        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14180            s.select_anchor_ranges([start..end])
14181        });
14182    }
14183
14184    pub fn go_to_diagnostic(
14185        &mut self,
14186        _: &GoToDiagnostic,
14187        window: &mut Window,
14188        cx: &mut Context<Self>,
14189    ) {
14190        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14191        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14192    }
14193
14194    pub fn go_to_prev_diagnostic(
14195        &mut self,
14196        _: &GoToPreviousDiagnostic,
14197        window: &mut Window,
14198        cx: &mut Context<Self>,
14199    ) {
14200        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14201        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14202    }
14203
14204    pub fn go_to_diagnostic_impl(
14205        &mut self,
14206        direction: Direction,
14207        window: &mut Window,
14208        cx: &mut Context<Self>,
14209    ) {
14210        let buffer = self.buffer.read(cx).snapshot(cx);
14211        let selection = self.selections.newest::<usize>(cx);
14212
14213        let mut active_group_id = None;
14214        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14215            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14216                active_group_id = Some(active_group.group_id);
14217            }
14218        }
14219
14220        fn filtered(
14221            snapshot: EditorSnapshot,
14222            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14223        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14224            diagnostics
14225                .filter(|entry| entry.range.start != entry.range.end)
14226                .filter(|entry| !entry.diagnostic.is_unnecessary)
14227                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14228        }
14229
14230        let snapshot = self.snapshot(window, cx);
14231        let before = filtered(
14232            snapshot.clone(),
14233            buffer
14234                .diagnostics_in_range(0..selection.start)
14235                .filter(|entry| entry.range.start <= selection.start),
14236        );
14237        let after = filtered(
14238            snapshot,
14239            buffer
14240                .diagnostics_in_range(selection.start..buffer.len())
14241                .filter(|entry| entry.range.start >= selection.start),
14242        );
14243
14244        let mut found: Option<DiagnosticEntry<usize>> = None;
14245        if direction == Direction::Prev {
14246            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14247            {
14248                for diagnostic in prev_diagnostics.into_iter().rev() {
14249                    if diagnostic.range.start != selection.start
14250                        || active_group_id
14251                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14252                    {
14253                        found = Some(diagnostic);
14254                        break 'outer;
14255                    }
14256                }
14257            }
14258        } else {
14259            for diagnostic in after.chain(before) {
14260                if diagnostic.range.start != selection.start
14261                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14262                {
14263                    found = Some(diagnostic);
14264                    break;
14265                }
14266            }
14267        }
14268        let Some(next_diagnostic) = found else {
14269            return;
14270        };
14271
14272        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14273            return;
14274        };
14275        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14276            s.select_ranges(vec![
14277                next_diagnostic.range.start..next_diagnostic.range.start,
14278            ])
14279        });
14280        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14281        self.refresh_inline_completion(false, true, window, cx);
14282    }
14283
14284    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14285        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14286        let snapshot = self.snapshot(window, cx);
14287        let selection = self.selections.newest::<Point>(cx);
14288        self.go_to_hunk_before_or_after_position(
14289            &snapshot,
14290            selection.head(),
14291            Direction::Next,
14292            window,
14293            cx,
14294        );
14295    }
14296
14297    pub fn go_to_hunk_before_or_after_position(
14298        &mut self,
14299        snapshot: &EditorSnapshot,
14300        position: Point,
14301        direction: Direction,
14302        window: &mut Window,
14303        cx: &mut Context<Editor>,
14304    ) {
14305        let row = if direction == Direction::Next {
14306            self.hunk_after_position(snapshot, position)
14307                .map(|hunk| hunk.row_range.start)
14308        } else {
14309            self.hunk_before_position(snapshot, position)
14310        };
14311
14312        if let Some(row) = row {
14313            let destination = Point::new(row.0, 0);
14314            let autoscroll = Autoscroll::center();
14315
14316            self.unfold_ranges(&[destination..destination], false, false, cx);
14317            self.change_selections(Some(autoscroll), window, cx, |s| {
14318                s.select_ranges([destination..destination]);
14319            });
14320        }
14321    }
14322
14323    fn hunk_after_position(
14324        &mut self,
14325        snapshot: &EditorSnapshot,
14326        position: Point,
14327    ) -> Option<MultiBufferDiffHunk> {
14328        snapshot
14329            .buffer_snapshot
14330            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14331            .find(|hunk| hunk.row_range.start.0 > position.row)
14332            .or_else(|| {
14333                snapshot
14334                    .buffer_snapshot
14335                    .diff_hunks_in_range(Point::zero()..position)
14336                    .find(|hunk| hunk.row_range.end.0 < position.row)
14337            })
14338    }
14339
14340    fn go_to_prev_hunk(
14341        &mut self,
14342        _: &GoToPreviousHunk,
14343        window: &mut Window,
14344        cx: &mut Context<Self>,
14345    ) {
14346        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14347        let snapshot = self.snapshot(window, cx);
14348        let selection = self.selections.newest::<Point>(cx);
14349        self.go_to_hunk_before_or_after_position(
14350            &snapshot,
14351            selection.head(),
14352            Direction::Prev,
14353            window,
14354            cx,
14355        );
14356    }
14357
14358    fn hunk_before_position(
14359        &mut self,
14360        snapshot: &EditorSnapshot,
14361        position: Point,
14362    ) -> Option<MultiBufferRow> {
14363        snapshot
14364            .buffer_snapshot
14365            .diff_hunk_before(position)
14366            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14367    }
14368
14369    fn go_to_next_change(
14370        &mut self,
14371        _: &GoToNextChange,
14372        window: &mut Window,
14373        cx: &mut Context<Self>,
14374    ) {
14375        if let Some(selections) = self
14376            .change_list
14377            .next_change(1, Direction::Next)
14378            .map(|s| s.to_vec())
14379        {
14380            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14381                let map = s.display_map();
14382                s.select_display_ranges(selections.iter().map(|a| {
14383                    let point = a.to_display_point(&map);
14384                    point..point
14385                }))
14386            })
14387        }
14388    }
14389
14390    fn go_to_previous_change(
14391        &mut self,
14392        _: &GoToPreviousChange,
14393        window: &mut Window,
14394        cx: &mut Context<Self>,
14395    ) {
14396        if let Some(selections) = self
14397            .change_list
14398            .next_change(1, Direction::Prev)
14399            .map(|s| s.to_vec())
14400        {
14401            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14402                let map = s.display_map();
14403                s.select_display_ranges(selections.iter().map(|a| {
14404                    let point = a.to_display_point(&map);
14405                    point..point
14406                }))
14407            })
14408        }
14409    }
14410
14411    fn go_to_line<T: 'static>(
14412        &mut self,
14413        position: Anchor,
14414        highlight_color: Option<Hsla>,
14415        window: &mut Window,
14416        cx: &mut Context<Self>,
14417    ) {
14418        let snapshot = self.snapshot(window, cx).display_snapshot;
14419        let position = position.to_point(&snapshot.buffer_snapshot);
14420        let start = snapshot
14421            .buffer_snapshot
14422            .clip_point(Point::new(position.row, 0), Bias::Left);
14423        let end = start + Point::new(1, 0);
14424        let start = snapshot.buffer_snapshot.anchor_before(start);
14425        let end = snapshot.buffer_snapshot.anchor_before(end);
14426
14427        self.highlight_rows::<T>(
14428            start..end,
14429            highlight_color
14430                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14431            Default::default(),
14432            cx,
14433        );
14434
14435        if self.buffer.read(cx).is_singleton() {
14436            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14437        }
14438    }
14439
14440    pub fn go_to_definition(
14441        &mut self,
14442        _: &GoToDefinition,
14443        window: &mut Window,
14444        cx: &mut Context<Self>,
14445    ) -> Task<Result<Navigated>> {
14446        let definition =
14447            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14448        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14449        cx.spawn_in(window, async move |editor, cx| {
14450            if definition.await? == Navigated::Yes {
14451                return Ok(Navigated::Yes);
14452            }
14453            match fallback_strategy {
14454                GoToDefinitionFallback::None => Ok(Navigated::No),
14455                GoToDefinitionFallback::FindAllReferences => {
14456                    match editor.update_in(cx, |editor, window, cx| {
14457                        editor.find_all_references(&FindAllReferences, window, cx)
14458                    })? {
14459                        Some(references) => references.await,
14460                        None => Ok(Navigated::No),
14461                    }
14462                }
14463            }
14464        })
14465    }
14466
14467    pub fn go_to_declaration(
14468        &mut self,
14469        _: &GoToDeclaration,
14470        window: &mut Window,
14471        cx: &mut Context<Self>,
14472    ) -> Task<Result<Navigated>> {
14473        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14474    }
14475
14476    pub fn go_to_declaration_split(
14477        &mut self,
14478        _: &GoToDeclaration,
14479        window: &mut Window,
14480        cx: &mut Context<Self>,
14481    ) -> Task<Result<Navigated>> {
14482        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14483    }
14484
14485    pub fn go_to_implementation(
14486        &mut self,
14487        _: &GoToImplementation,
14488        window: &mut Window,
14489        cx: &mut Context<Self>,
14490    ) -> Task<Result<Navigated>> {
14491        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14492    }
14493
14494    pub fn go_to_implementation_split(
14495        &mut self,
14496        _: &GoToImplementationSplit,
14497        window: &mut Window,
14498        cx: &mut Context<Self>,
14499    ) -> Task<Result<Navigated>> {
14500        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14501    }
14502
14503    pub fn go_to_type_definition(
14504        &mut self,
14505        _: &GoToTypeDefinition,
14506        window: &mut Window,
14507        cx: &mut Context<Self>,
14508    ) -> Task<Result<Navigated>> {
14509        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14510    }
14511
14512    pub fn go_to_definition_split(
14513        &mut self,
14514        _: &GoToDefinitionSplit,
14515        window: &mut Window,
14516        cx: &mut Context<Self>,
14517    ) -> Task<Result<Navigated>> {
14518        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14519    }
14520
14521    pub fn go_to_type_definition_split(
14522        &mut self,
14523        _: &GoToTypeDefinitionSplit,
14524        window: &mut Window,
14525        cx: &mut Context<Self>,
14526    ) -> Task<Result<Navigated>> {
14527        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14528    }
14529
14530    fn go_to_definition_of_kind(
14531        &mut self,
14532        kind: GotoDefinitionKind,
14533        split: bool,
14534        window: &mut Window,
14535        cx: &mut Context<Self>,
14536    ) -> Task<Result<Navigated>> {
14537        let Some(provider) = self.semantics_provider.clone() else {
14538            return Task::ready(Ok(Navigated::No));
14539        };
14540        let head = self.selections.newest::<usize>(cx).head();
14541        let buffer = self.buffer.read(cx);
14542        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14543            text_anchor
14544        } else {
14545            return Task::ready(Ok(Navigated::No));
14546        };
14547
14548        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14549            return Task::ready(Ok(Navigated::No));
14550        };
14551
14552        cx.spawn_in(window, async move |editor, cx| {
14553            let definitions = definitions.await?;
14554            let navigated = editor
14555                .update_in(cx, |editor, window, cx| {
14556                    editor.navigate_to_hover_links(
14557                        Some(kind),
14558                        definitions
14559                            .into_iter()
14560                            .filter(|location| {
14561                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14562                            })
14563                            .map(HoverLink::Text)
14564                            .collect::<Vec<_>>(),
14565                        split,
14566                        window,
14567                        cx,
14568                    )
14569                })?
14570                .await?;
14571            anyhow::Ok(navigated)
14572        })
14573    }
14574
14575    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14576        let selection = self.selections.newest_anchor();
14577        let head = selection.head();
14578        let tail = selection.tail();
14579
14580        let Some((buffer, start_position)) =
14581            self.buffer.read(cx).text_anchor_for_position(head, cx)
14582        else {
14583            return;
14584        };
14585
14586        let end_position = if head != tail {
14587            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14588                return;
14589            };
14590            Some(pos)
14591        } else {
14592            None
14593        };
14594
14595        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14596            let url = if let Some(end_pos) = end_position {
14597                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14598            } else {
14599                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14600            };
14601
14602            if let Some(url) = url {
14603                editor.update(cx, |_, cx| {
14604                    cx.open_url(&url);
14605                })
14606            } else {
14607                Ok(())
14608            }
14609        });
14610
14611        url_finder.detach();
14612    }
14613
14614    pub fn open_selected_filename(
14615        &mut self,
14616        _: &OpenSelectedFilename,
14617        window: &mut Window,
14618        cx: &mut Context<Self>,
14619    ) {
14620        let Some(workspace) = self.workspace() else {
14621            return;
14622        };
14623
14624        let position = self.selections.newest_anchor().head();
14625
14626        let Some((buffer, buffer_position)) =
14627            self.buffer.read(cx).text_anchor_for_position(position, cx)
14628        else {
14629            return;
14630        };
14631
14632        let project = self.project.clone();
14633
14634        cx.spawn_in(window, async move |_, cx| {
14635            let result = find_file(&buffer, project, buffer_position, cx).await;
14636
14637            if let Some((_, path)) = result {
14638                workspace
14639                    .update_in(cx, |workspace, window, cx| {
14640                        workspace.open_resolved_path(path, window, cx)
14641                    })?
14642                    .await?;
14643            }
14644            anyhow::Ok(())
14645        })
14646        .detach();
14647    }
14648
14649    pub(crate) fn navigate_to_hover_links(
14650        &mut self,
14651        kind: Option<GotoDefinitionKind>,
14652        mut definitions: Vec<HoverLink>,
14653        split: bool,
14654        window: &mut Window,
14655        cx: &mut Context<Editor>,
14656    ) -> Task<Result<Navigated>> {
14657        // If there is one definition, just open it directly
14658        if definitions.len() == 1 {
14659            let definition = definitions.pop().unwrap();
14660
14661            enum TargetTaskResult {
14662                Location(Option<Location>),
14663                AlreadyNavigated,
14664            }
14665
14666            let target_task = match definition {
14667                HoverLink::Text(link) => {
14668                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14669                }
14670                HoverLink::InlayHint(lsp_location, server_id) => {
14671                    let computation =
14672                        self.compute_target_location(lsp_location, server_id, window, cx);
14673                    cx.background_spawn(async move {
14674                        let location = computation.await?;
14675                        Ok(TargetTaskResult::Location(location))
14676                    })
14677                }
14678                HoverLink::Url(url) => {
14679                    cx.open_url(&url);
14680                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14681                }
14682                HoverLink::File(path) => {
14683                    if let Some(workspace) = self.workspace() {
14684                        cx.spawn_in(window, async move |_, cx| {
14685                            workspace
14686                                .update_in(cx, |workspace, window, cx| {
14687                                    workspace.open_resolved_path(path, window, cx)
14688                                })?
14689                                .await
14690                                .map(|_| TargetTaskResult::AlreadyNavigated)
14691                        })
14692                    } else {
14693                        Task::ready(Ok(TargetTaskResult::Location(None)))
14694                    }
14695                }
14696            };
14697            cx.spawn_in(window, async move |editor, cx| {
14698                let target = match target_task.await.context("target resolution task")? {
14699                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14700                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14701                    TargetTaskResult::Location(Some(target)) => target,
14702                };
14703
14704                editor.update_in(cx, |editor, window, cx| {
14705                    let Some(workspace) = editor.workspace() else {
14706                        return Navigated::No;
14707                    };
14708                    let pane = workspace.read(cx).active_pane().clone();
14709
14710                    let range = target.range.to_point(target.buffer.read(cx));
14711                    let range = editor.range_for_match(&range);
14712                    let range = collapse_multiline_range(range);
14713
14714                    if !split
14715                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14716                    {
14717                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14718                    } else {
14719                        window.defer(cx, move |window, cx| {
14720                            let target_editor: Entity<Self> =
14721                                workspace.update(cx, |workspace, cx| {
14722                                    let pane = if split {
14723                                        workspace.adjacent_pane(window, cx)
14724                                    } else {
14725                                        workspace.active_pane().clone()
14726                                    };
14727
14728                                    workspace.open_project_item(
14729                                        pane,
14730                                        target.buffer.clone(),
14731                                        true,
14732                                        true,
14733                                        window,
14734                                        cx,
14735                                    )
14736                                });
14737                            target_editor.update(cx, |target_editor, cx| {
14738                                // When selecting a definition in a different buffer, disable the nav history
14739                                // to avoid creating a history entry at the previous cursor location.
14740                                pane.update(cx, |pane, _| pane.disable_history());
14741                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14742                                pane.update(cx, |pane, _| pane.enable_history());
14743                            });
14744                        });
14745                    }
14746                    Navigated::Yes
14747                })
14748            })
14749        } else if !definitions.is_empty() {
14750            cx.spawn_in(window, async move |editor, cx| {
14751                let (title, location_tasks, workspace) = editor
14752                    .update_in(cx, |editor, window, cx| {
14753                        let tab_kind = match kind {
14754                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14755                            _ => "Definitions",
14756                        };
14757                        let title = definitions
14758                            .iter()
14759                            .find_map(|definition| match definition {
14760                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14761                                    let buffer = origin.buffer.read(cx);
14762                                    format!(
14763                                        "{} for {}",
14764                                        tab_kind,
14765                                        buffer
14766                                            .text_for_range(origin.range.clone())
14767                                            .collect::<String>()
14768                                    )
14769                                }),
14770                                HoverLink::InlayHint(_, _) => None,
14771                                HoverLink::Url(_) => None,
14772                                HoverLink::File(_) => None,
14773                            })
14774                            .unwrap_or(tab_kind.to_string());
14775                        let location_tasks = definitions
14776                            .into_iter()
14777                            .map(|definition| match definition {
14778                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14779                                HoverLink::InlayHint(lsp_location, server_id) => editor
14780                                    .compute_target_location(lsp_location, server_id, window, cx),
14781                                HoverLink::Url(_) => Task::ready(Ok(None)),
14782                                HoverLink::File(_) => Task::ready(Ok(None)),
14783                            })
14784                            .collect::<Vec<_>>();
14785                        (title, location_tasks, editor.workspace().clone())
14786                    })
14787                    .context("location tasks preparation")?;
14788
14789                let locations = future::join_all(location_tasks)
14790                    .await
14791                    .into_iter()
14792                    .filter_map(|location| location.transpose())
14793                    .collect::<Result<_>>()
14794                    .context("location tasks")?;
14795
14796                let Some(workspace) = workspace else {
14797                    return Ok(Navigated::No);
14798                };
14799                let opened = workspace
14800                    .update_in(cx, |workspace, window, cx| {
14801                        Self::open_locations_in_multibuffer(
14802                            workspace,
14803                            locations,
14804                            title,
14805                            split,
14806                            MultibufferSelectionMode::First,
14807                            window,
14808                            cx,
14809                        )
14810                    })
14811                    .ok();
14812
14813                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14814            })
14815        } else {
14816            Task::ready(Ok(Navigated::No))
14817        }
14818    }
14819
14820    fn compute_target_location(
14821        &self,
14822        lsp_location: lsp::Location,
14823        server_id: LanguageServerId,
14824        window: &mut Window,
14825        cx: &mut Context<Self>,
14826    ) -> Task<anyhow::Result<Option<Location>>> {
14827        let Some(project) = self.project.clone() else {
14828            return Task::ready(Ok(None));
14829        };
14830
14831        cx.spawn_in(window, async move |editor, cx| {
14832            let location_task = editor.update(cx, |_, cx| {
14833                project.update(cx, |project, cx| {
14834                    let language_server_name = project
14835                        .language_server_statuses(cx)
14836                        .find(|(id, _)| server_id == *id)
14837                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14838                    language_server_name.map(|language_server_name| {
14839                        project.open_local_buffer_via_lsp(
14840                            lsp_location.uri.clone(),
14841                            server_id,
14842                            language_server_name,
14843                            cx,
14844                        )
14845                    })
14846                })
14847            })?;
14848            let location = match location_task {
14849                Some(task) => Some({
14850                    let target_buffer_handle = task.await.context("open local buffer")?;
14851                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
14852                        let target_start = target_buffer
14853                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14854                        let target_end = target_buffer
14855                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14856                        target_buffer.anchor_after(target_start)
14857                            ..target_buffer.anchor_before(target_end)
14858                    })?;
14859                    Location {
14860                        buffer: target_buffer_handle,
14861                        range,
14862                    }
14863                }),
14864                None => None,
14865            };
14866            Ok(location)
14867        })
14868    }
14869
14870    pub fn find_all_references(
14871        &mut self,
14872        _: &FindAllReferences,
14873        window: &mut Window,
14874        cx: &mut Context<Self>,
14875    ) -> Option<Task<Result<Navigated>>> {
14876        let selection = self.selections.newest::<usize>(cx);
14877        let multi_buffer = self.buffer.read(cx);
14878        let head = selection.head();
14879
14880        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14881        let head_anchor = multi_buffer_snapshot.anchor_at(
14882            head,
14883            if head < selection.tail() {
14884                Bias::Right
14885            } else {
14886                Bias::Left
14887            },
14888        );
14889
14890        match self
14891            .find_all_references_task_sources
14892            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14893        {
14894            Ok(_) => {
14895                log::info!(
14896                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14897                );
14898                return None;
14899            }
14900            Err(i) => {
14901                self.find_all_references_task_sources.insert(i, head_anchor);
14902            }
14903        }
14904
14905        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14906        let workspace = self.workspace()?;
14907        let project = workspace.read(cx).project().clone();
14908        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14909        Some(cx.spawn_in(window, async move |editor, cx| {
14910            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14911                if let Ok(i) = editor
14912                    .find_all_references_task_sources
14913                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14914                {
14915                    editor.find_all_references_task_sources.remove(i);
14916                }
14917            });
14918
14919            let locations = references.await?;
14920            if locations.is_empty() {
14921                return anyhow::Ok(Navigated::No);
14922            }
14923
14924            workspace.update_in(cx, |workspace, window, cx| {
14925                let title = locations
14926                    .first()
14927                    .as_ref()
14928                    .map(|location| {
14929                        let buffer = location.buffer.read(cx);
14930                        format!(
14931                            "References to `{}`",
14932                            buffer
14933                                .text_for_range(location.range.clone())
14934                                .collect::<String>()
14935                        )
14936                    })
14937                    .unwrap();
14938                Self::open_locations_in_multibuffer(
14939                    workspace,
14940                    locations,
14941                    title,
14942                    false,
14943                    MultibufferSelectionMode::First,
14944                    window,
14945                    cx,
14946                );
14947                Navigated::Yes
14948            })
14949        }))
14950    }
14951
14952    /// Opens a multibuffer with the given project locations in it
14953    pub fn open_locations_in_multibuffer(
14954        workspace: &mut Workspace,
14955        mut locations: Vec<Location>,
14956        title: String,
14957        split: bool,
14958        multibuffer_selection_mode: MultibufferSelectionMode,
14959        window: &mut Window,
14960        cx: &mut Context<Workspace>,
14961    ) {
14962        // If there are multiple definitions, open them in a multibuffer
14963        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14964        let mut locations = locations.into_iter().peekable();
14965        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14966        let capability = workspace.project().read(cx).capability();
14967
14968        let excerpt_buffer = cx.new(|cx| {
14969            let mut multibuffer = MultiBuffer::new(capability);
14970            while let Some(location) = locations.next() {
14971                let buffer = location.buffer.read(cx);
14972                let mut ranges_for_buffer = Vec::new();
14973                let range = location.range.to_point(buffer);
14974                ranges_for_buffer.push(range.clone());
14975
14976                while let Some(next_location) = locations.peek() {
14977                    if next_location.buffer == location.buffer {
14978                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14979                        locations.next();
14980                    } else {
14981                        break;
14982                    }
14983                }
14984
14985                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14986                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14987                    PathKey::for_buffer(&location.buffer, cx),
14988                    location.buffer.clone(),
14989                    ranges_for_buffer,
14990                    DEFAULT_MULTIBUFFER_CONTEXT,
14991                    cx,
14992                );
14993                ranges.extend(new_ranges)
14994            }
14995
14996            multibuffer.with_title(title)
14997        });
14998
14999        let editor = cx.new(|cx| {
15000            Editor::for_multibuffer(
15001                excerpt_buffer,
15002                Some(workspace.project().clone()),
15003                window,
15004                cx,
15005            )
15006        });
15007        editor.update(cx, |editor, cx| {
15008            match multibuffer_selection_mode {
15009                MultibufferSelectionMode::First => {
15010                    if let Some(first_range) = ranges.first() {
15011                        editor.change_selections(None, window, cx, |selections| {
15012                            selections.clear_disjoint();
15013                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15014                        });
15015                    }
15016                    editor.highlight_background::<Self>(
15017                        &ranges,
15018                        |theme| theme.editor_highlighted_line_background,
15019                        cx,
15020                    );
15021                }
15022                MultibufferSelectionMode::All => {
15023                    editor.change_selections(None, window, cx, |selections| {
15024                        selections.clear_disjoint();
15025                        selections.select_anchor_ranges(ranges);
15026                    });
15027                }
15028            }
15029            editor.register_buffers_with_language_servers(cx);
15030        });
15031
15032        let item = Box::new(editor);
15033        let item_id = item.item_id();
15034
15035        if split {
15036            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15037        } else {
15038            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15039                let (preview_item_id, preview_item_idx) =
15040                    workspace.active_pane().read_with(cx, |pane, _| {
15041                        (pane.preview_item_id(), pane.preview_item_idx())
15042                    });
15043
15044                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15045
15046                if let Some(preview_item_id) = preview_item_id {
15047                    workspace.active_pane().update(cx, |pane, cx| {
15048                        pane.remove_item(preview_item_id, false, false, window, cx);
15049                    });
15050                }
15051            } else {
15052                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15053            }
15054        }
15055        workspace.active_pane().update(cx, |pane, cx| {
15056            pane.set_preview_item_id(Some(item_id), cx);
15057        });
15058    }
15059
15060    pub fn rename(
15061        &mut self,
15062        _: &Rename,
15063        window: &mut Window,
15064        cx: &mut Context<Self>,
15065    ) -> Option<Task<Result<()>>> {
15066        use language::ToOffset as _;
15067
15068        let provider = self.semantics_provider.clone()?;
15069        let selection = self.selections.newest_anchor().clone();
15070        let (cursor_buffer, cursor_buffer_position) = self
15071            .buffer
15072            .read(cx)
15073            .text_anchor_for_position(selection.head(), cx)?;
15074        let (tail_buffer, cursor_buffer_position_end) = self
15075            .buffer
15076            .read(cx)
15077            .text_anchor_for_position(selection.tail(), cx)?;
15078        if tail_buffer != cursor_buffer {
15079            return None;
15080        }
15081
15082        let snapshot = cursor_buffer.read(cx).snapshot();
15083        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15084        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15085        let prepare_rename = provider
15086            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15087            .unwrap_or_else(|| Task::ready(Ok(None)));
15088        drop(snapshot);
15089
15090        Some(cx.spawn_in(window, async move |this, cx| {
15091            let rename_range = if let Some(range) = prepare_rename.await? {
15092                Some(range)
15093            } else {
15094                this.update(cx, |this, cx| {
15095                    let buffer = this.buffer.read(cx).snapshot(cx);
15096                    let mut buffer_highlights = this
15097                        .document_highlights_for_position(selection.head(), &buffer)
15098                        .filter(|highlight| {
15099                            highlight.start.excerpt_id == selection.head().excerpt_id
15100                                && highlight.end.excerpt_id == selection.head().excerpt_id
15101                        });
15102                    buffer_highlights
15103                        .next()
15104                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15105                })?
15106            };
15107            if let Some(rename_range) = rename_range {
15108                this.update_in(cx, |this, window, cx| {
15109                    let snapshot = cursor_buffer.read(cx).snapshot();
15110                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15111                    let cursor_offset_in_rename_range =
15112                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15113                    let cursor_offset_in_rename_range_end =
15114                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15115
15116                    this.take_rename(false, window, cx);
15117                    let buffer = this.buffer.read(cx).read(cx);
15118                    let cursor_offset = selection.head().to_offset(&buffer);
15119                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15120                    let rename_end = rename_start + rename_buffer_range.len();
15121                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15122                    let mut old_highlight_id = None;
15123                    let old_name: Arc<str> = buffer
15124                        .chunks(rename_start..rename_end, true)
15125                        .map(|chunk| {
15126                            if old_highlight_id.is_none() {
15127                                old_highlight_id = chunk.syntax_highlight_id;
15128                            }
15129                            chunk.text
15130                        })
15131                        .collect::<String>()
15132                        .into();
15133
15134                    drop(buffer);
15135
15136                    // Position the selection in the rename editor so that it matches the current selection.
15137                    this.show_local_selections = false;
15138                    let rename_editor = cx.new(|cx| {
15139                        let mut editor = Editor::single_line(window, cx);
15140                        editor.buffer.update(cx, |buffer, cx| {
15141                            buffer.edit([(0..0, old_name.clone())], None, cx)
15142                        });
15143                        let rename_selection_range = match cursor_offset_in_rename_range
15144                            .cmp(&cursor_offset_in_rename_range_end)
15145                        {
15146                            Ordering::Equal => {
15147                                editor.select_all(&SelectAll, window, cx);
15148                                return editor;
15149                            }
15150                            Ordering::Less => {
15151                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15152                            }
15153                            Ordering::Greater => {
15154                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15155                            }
15156                        };
15157                        if rename_selection_range.end > old_name.len() {
15158                            editor.select_all(&SelectAll, window, cx);
15159                        } else {
15160                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15161                                s.select_ranges([rename_selection_range]);
15162                            });
15163                        }
15164                        editor
15165                    });
15166                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15167                        if e == &EditorEvent::Focused {
15168                            cx.emit(EditorEvent::FocusedIn)
15169                        }
15170                    })
15171                    .detach();
15172
15173                    let write_highlights =
15174                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15175                    let read_highlights =
15176                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15177                    let ranges = write_highlights
15178                        .iter()
15179                        .flat_map(|(_, ranges)| ranges.iter())
15180                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15181                        .cloned()
15182                        .collect();
15183
15184                    this.highlight_text::<Rename>(
15185                        ranges,
15186                        HighlightStyle {
15187                            fade_out: Some(0.6),
15188                            ..Default::default()
15189                        },
15190                        cx,
15191                    );
15192                    let rename_focus_handle = rename_editor.focus_handle(cx);
15193                    window.focus(&rename_focus_handle);
15194                    let block_id = this.insert_blocks(
15195                        [BlockProperties {
15196                            style: BlockStyle::Flex,
15197                            placement: BlockPlacement::Below(range.start),
15198                            height: Some(1),
15199                            render: Arc::new({
15200                                let rename_editor = rename_editor.clone();
15201                                move |cx: &mut BlockContext| {
15202                                    let mut text_style = cx.editor_style.text.clone();
15203                                    if let Some(highlight_style) = old_highlight_id
15204                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15205                                    {
15206                                        text_style = text_style.highlight(highlight_style);
15207                                    }
15208                                    div()
15209                                        .block_mouse_except_scroll()
15210                                        .pl(cx.anchor_x)
15211                                        .child(EditorElement::new(
15212                                            &rename_editor,
15213                                            EditorStyle {
15214                                                background: cx.theme().system().transparent,
15215                                                local_player: cx.editor_style.local_player,
15216                                                text: text_style,
15217                                                scrollbar_width: cx.editor_style.scrollbar_width,
15218                                                syntax: cx.editor_style.syntax.clone(),
15219                                                status: cx.editor_style.status.clone(),
15220                                                inlay_hints_style: HighlightStyle {
15221                                                    font_weight: Some(FontWeight::BOLD),
15222                                                    ..make_inlay_hints_style(cx.app)
15223                                                },
15224                                                inline_completion_styles: make_suggestion_styles(
15225                                                    cx.app,
15226                                                ),
15227                                                ..EditorStyle::default()
15228                                            },
15229                                        ))
15230                                        .into_any_element()
15231                                }
15232                            }),
15233                            priority: 0,
15234                            render_in_minimap: true,
15235                        }],
15236                        Some(Autoscroll::fit()),
15237                        cx,
15238                    )[0];
15239                    this.pending_rename = Some(RenameState {
15240                        range,
15241                        old_name,
15242                        editor: rename_editor,
15243                        block_id,
15244                    });
15245                })?;
15246            }
15247
15248            Ok(())
15249        }))
15250    }
15251
15252    pub fn confirm_rename(
15253        &mut self,
15254        _: &ConfirmRename,
15255        window: &mut Window,
15256        cx: &mut Context<Self>,
15257    ) -> Option<Task<Result<()>>> {
15258        let rename = self.take_rename(false, window, cx)?;
15259        let workspace = self.workspace()?.downgrade();
15260        let (buffer, start) = self
15261            .buffer
15262            .read(cx)
15263            .text_anchor_for_position(rename.range.start, cx)?;
15264        let (end_buffer, _) = self
15265            .buffer
15266            .read(cx)
15267            .text_anchor_for_position(rename.range.end, cx)?;
15268        if buffer != end_buffer {
15269            return None;
15270        }
15271
15272        let old_name = rename.old_name;
15273        let new_name = rename.editor.read(cx).text(cx);
15274
15275        let rename = self.semantics_provider.as_ref()?.perform_rename(
15276            &buffer,
15277            start,
15278            new_name.clone(),
15279            cx,
15280        )?;
15281
15282        Some(cx.spawn_in(window, async move |editor, cx| {
15283            let project_transaction = rename.await?;
15284            Self::open_project_transaction(
15285                &editor,
15286                workspace,
15287                project_transaction,
15288                format!("Rename: {}{}", old_name, new_name),
15289                cx,
15290            )
15291            .await?;
15292
15293            editor.update(cx, |editor, cx| {
15294                editor.refresh_document_highlights(cx);
15295            })?;
15296            Ok(())
15297        }))
15298    }
15299
15300    fn take_rename(
15301        &mut self,
15302        moving_cursor: bool,
15303        window: &mut Window,
15304        cx: &mut Context<Self>,
15305    ) -> Option<RenameState> {
15306        let rename = self.pending_rename.take()?;
15307        if rename.editor.focus_handle(cx).is_focused(window) {
15308            window.focus(&self.focus_handle);
15309        }
15310
15311        self.remove_blocks(
15312            [rename.block_id].into_iter().collect(),
15313            Some(Autoscroll::fit()),
15314            cx,
15315        );
15316        self.clear_highlights::<Rename>(cx);
15317        self.show_local_selections = true;
15318
15319        if moving_cursor {
15320            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15321                editor.selections.newest::<usize>(cx).head()
15322            });
15323
15324            // Update the selection to match the position of the selection inside
15325            // the rename editor.
15326            let snapshot = self.buffer.read(cx).read(cx);
15327            let rename_range = rename.range.to_offset(&snapshot);
15328            let cursor_in_editor = snapshot
15329                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15330                .min(rename_range.end);
15331            drop(snapshot);
15332
15333            self.change_selections(None, window, cx, |s| {
15334                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15335            });
15336        } else {
15337            self.refresh_document_highlights(cx);
15338        }
15339
15340        Some(rename)
15341    }
15342
15343    pub fn pending_rename(&self) -> Option<&RenameState> {
15344        self.pending_rename.as_ref()
15345    }
15346
15347    fn format(
15348        &mut self,
15349        _: &Format,
15350        window: &mut Window,
15351        cx: &mut Context<Self>,
15352    ) -> Option<Task<Result<()>>> {
15353        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15354
15355        let project = match &self.project {
15356            Some(project) => project.clone(),
15357            None => return None,
15358        };
15359
15360        Some(self.perform_format(
15361            project,
15362            FormatTrigger::Manual,
15363            FormatTarget::Buffers,
15364            window,
15365            cx,
15366        ))
15367    }
15368
15369    fn format_selections(
15370        &mut self,
15371        _: &FormatSelections,
15372        window: &mut Window,
15373        cx: &mut Context<Self>,
15374    ) -> Option<Task<Result<()>>> {
15375        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15376
15377        let project = match &self.project {
15378            Some(project) => project.clone(),
15379            None => return None,
15380        };
15381
15382        let ranges = self
15383            .selections
15384            .all_adjusted(cx)
15385            .into_iter()
15386            .map(|selection| selection.range())
15387            .collect_vec();
15388
15389        Some(self.perform_format(
15390            project,
15391            FormatTrigger::Manual,
15392            FormatTarget::Ranges(ranges),
15393            window,
15394            cx,
15395        ))
15396    }
15397
15398    fn perform_format(
15399        &mut self,
15400        project: Entity<Project>,
15401        trigger: FormatTrigger,
15402        target: FormatTarget,
15403        window: &mut Window,
15404        cx: &mut Context<Self>,
15405    ) -> Task<Result<()>> {
15406        let buffer = self.buffer.clone();
15407        let (buffers, target) = match target {
15408            FormatTarget::Buffers => {
15409                let mut buffers = buffer.read(cx).all_buffers();
15410                if trigger == FormatTrigger::Save {
15411                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15412                }
15413                (buffers, LspFormatTarget::Buffers)
15414            }
15415            FormatTarget::Ranges(selection_ranges) => {
15416                let multi_buffer = buffer.read(cx);
15417                let snapshot = multi_buffer.read(cx);
15418                let mut buffers = HashSet::default();
15419                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15420                    BTreeMap::new();
15421                for selection_range in selection_ranges {
15422                    for (buffer, buffer_range, _) in
15423                        snapshot.range_to_buffer_ranges(selection_range)
15424                    {
15425                        let buffer_id = buffer.remote_id();
15426                        let start = buffer.anchor_before(buffer_range.start);
15427                        let end = buffer.anchor_after(buffer_range.end);
15428                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15429                        buffer_id_to_ranges
15430                            .entry(buffer_id)
15431                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15432                            .or_insert_with(|| vec![start..end]);
15433                    }
15434                }
15435                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15436            }
15437        };
15438
15439        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15440        let selections_prev = transaction_id_prev
15441            .and_then(|transaction_id_prev| {
15442                // default to selections as they were after the last edit, if we have them,
15443                // instead of how they are now.
15444                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15445                // will take you back to where you made the last edit, instead of staying where you scrolled
15446                self.selection_history
15447                    .transaction(transaction_id_prev)
15448                    .map(|t| t.0.clone())
15449            })
15450            .unwrap_or_else(|| {
15451                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15452                self.selections.disjoint_anchors()
15453            });
15454
15455        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15456        let format = project.update(cx, |project, cx| {
15457            project.format(buffers, target, true, trigger, cx)
15458        });
15459
15460        cx.spawn_in(window, async move |editor, cx| {
15461            let transaction = futures::select_biased! {
15462                transaction = format.log_err().fuse() => transaction,
15463                () = timeout => {
15464                    log::warn!("timed out waiting for formatting");
15465                    None
15466                }
15467            };
15468
15469            buffer
15470                .update(cx, |buffer, cx| {
15471                    if let Some(transaction) = transaction {
15472                        if !buffer.is_singleton() {
15473                            buffer.push_transaction(&transaction.0, cx);
15474                        }
15475                    }
15476                    cx.notify();
15477                })
15478                .ok();
15479
15480            if let Some(transaction_id_now) =
15481                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15482            {
15483                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15484                if has_new_transaction {
15485                    _ = editor.update(cx, |editor, _| {
15486                        editor
15487                            .selection_history
15488                            .insert_transaction(transaction_id_now, selections_prev);
15489                    });
15490                }
15491            }
15492
15493            Ok(())
15494        })
15495    }
15496
15497    fn organize_imports(
15498        &mut self,
15499        _: &OrganizeImports,
15500        window: &mut Window,
15501        cx: &mut Context<Self>,
15502    ) -> Option<Task<Result<()>>> {
15503        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15504        let project = match &self.project {
15505            Some(project) => project.clone(),
15506            None => return None,
15507        };
15508        Some(self.perform_code_action_kind(
15509            project,
15510            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15511            window,
15512            cx,
15513        ))
15514    }
15515
15516    fn perform_code_action_kind(
15517        &mut self,
15518        project: Entity<Project>,
15519        kind: CodeActionKind,
15520        window: &mut Window,
15521        cx: &mut Context<Self>,
15522    ) -> Task<Result<()>> {
15523        let buffer = self.buffer.clone();
15524        let buffers = buffer.read(cx).all_buffers();
15525        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15526        let apply_action = project.update(cx, |project, cx| {
15527            project.apply_code_action_kind(buffers, kind, true, cx)
15528        });
15529        cx.spawn_in(window, async move |_, cx| {
15530            let transaction = futures::select_biased! {
15531                () = timeout => {
15532                    log::warn!("timed out waiting for executing code action");
15533                    None
15534                }
15535                transaction = apply_action.log_err().fuse() => transaction,
15536            };
15537            buffer
15538                .update(cx, |buffer, cx| {
15539                    // check if we need this
15540                    if let Some(transaction) = transaction {
15541                        if !buffer.is_singleton() {
15542                            buffer.push_transaction(&transaction.0, cx);
15543                        }
15544                    }
15545                    cx.notify();
15546                })
15547                .ok();
15548            Ok(())
15549        })
15550    }
15551
15552    fn restart_language_server(
15553        &mut self,
15554        _: &RestartLanguageServer,
15555        _: &mut Window,
15556        cx: &mut Context<Self>,
15557    ) {
15558        if let Some(project) = self.project.clone() {
15559            self.buffer.update(cx, |multi_buffer, cx| {
15560                project.update(cx, |project, cx| {
15561                    project.restart_language_servers_for_buffers(
15562                        multi_buffer.all_buffers().into_iter().collect(),
15563                        cx,
15564                    );
15565                });
15566            })
15567        }
15568    }
15569
15570    fn stop_language_server(
15571        &mut self,
15572        _: &StopLanguageServer,
15573        _: &mut Window,
15574        cx: &mut Context<Self>,
15575    ) {
15576        if let Some(project) = self.project.clone() {
15577            self.buffer.update(cx, |multi_buffer, cx| {
15578                project.update(cx, |project, cx| {
15579                    project.stop_language_servers_for_buffers(
15580                        multi_buffer.all_buffers().into_iter().collect(),
15581                        cx,
15582                    );
15583                    cx.emit(project::Event::RefreshInlayHints);
15584                });
15585            });
15586        }
15587    }
15588
15589    fn cancel_language_server_work(
15590        workspace: &mut Workspace,
15591        _: &actions::CancelLanguageServerWork,
15592        _: &mut Window,
15593        cx: &mut Context<Workspace>,
15594    ) {
15595        let project = workspace.project();
15596        let buffers = workspace
15597            .active_item(cx)
15598            .and_then(|item| item.act_as::<Editor>(cx))
15599            .map_or(HashSet::default(), |editor| {
15600                editor.read(cx).buffer.read(cx).all_buffers()
15601            });
15602        project.update(cx, |project, cx| {
15603            project.cancel_language_server_work_for_buffers(buffers, cx);
15604        });
15605    }
15606
15607    fn show_character_palette(
15608        &mut self,
15609        _: &ShowCharacterPalette,
15610        window: &mut Window,
15611        _: &mut Context<Self>,
15612    ) {
15613        window.show_character_palette();
15614    }
15615
15616    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15617        if self.mode.is_minimap() {
15618            return;
15619        }
15620
15621        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15622            let buffer = self.buffer.read(cx).snapshot(cx);
15623            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15624            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15625            let is_valid = buffer
15626                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15627                .any(|entry| {
15628                    entry.diagnostic.is_primary
15629                        && !entry.range.is_empty()
15630                        && entry.range.start == primary_range_start
15631                        && entry.diagnostic.message == active_diagnostics.active_message
15632                });
15633
15634            if !is_valid {
15635                self.dismiss_diagnostics(cx);
15636            }
15637        }
15638    }
15639
15640    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15641        match &self.active_diagnostics {
15642            ActiveDiagnostic::Group(group) => Some(group),
15643            _ => None,
15644        }
15645    }
15646
15647    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15648        self.dismiss_diagnostics(cx);
15649        self.active_diagnostics = ActiveDiagnostic::All;
15650    }
15651
15652    fn activate_diagnostics(
15653        &mut self,
15654        buffer_id: BufferId,
15655        diagnostic: DiagnosticEntry<usize>,
15656        window: &mut Window,
15657        cx: &mut Context<Self>,
15658    ) {
15659        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15660            return;
15661        }
15662        self.dismiss_diagnostics(cx);
15663        let snapshot = self.snapshot(window, cx);
15664        let buffer = self.buffer.read(cx).snapshot(cx);
15665        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15666            return;
15667        };
15668
15669        let diagnostic_group = buffer
15670            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15671            .collect::<Vec<_>>();
15672
15673        let blocks =
15674            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15675
15676        let blocks = self.display_map.update(cx, |display_map, cx| {
15677            display_map.insert_blocks(blocks, cx).into_iter().collect()
15678        });
15679        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15680            active_range: buffer.anchor_before(diagnostic.range.start)
15681                ..buffer.anchor_after(diagnostic.range.end),
15682            active_message: diagnostic.diagnostic.message.clone(),
15683            group_id: diagnostic.diagnostic.group_id,
15684            blocks,
15685        });
15686        cx.notify();
15687    }
15688
15689    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15690        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15691            return;
15692        };
15693
15694        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15695        if let ActiveDiagnostic::Group(group) = prev {
15696            self.display_map.update(cx, |display_map, cx| {
15697                display_map.remove_blocks(group.blocks, cx);
15698            });
15699            cx.notify();
15700        }
15701    }
15702
15703    /// Disable inline diagnostics rendering for this editor.
15704    pub fn disable_inline_diagnostics(&mut self) {
15705        self.inline_diagnostics_enabled = false;
15706        self.inline_diagnostics_update = Task::ready(());
15707        self.inline_diagnostics.clear();
15708    }
15709
15710    pub fn diagnostics_enabled(&self) -> bool {
15711        self.mode.is_full()
15712    }
15713
15714    pub fn inline_diagnostics_enabled(&self) -> bool {
15715        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15716    }
15717
15718    pub fn show_inline_diagnostics(&self) -> bool {
15719        self.show_inline_diagnostics
15720    }
15721
15722    pub fn toggle_inline_diagnostics(
15723        &mut self,
15724        _: &ToggleInlineDiagnostics,
15725        window: &mut Window,
15726        cx: &mut Context<Editor>,
15727    ) {
15728        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15729        self.refresh_inline_diagnostics(false, window, cx);
15730    }
15731
15732    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15733        self.diagnostics_max_severity = severity;
15734        self.display_map.update(cx, |display_map, _| {
15735            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15736        });
15737    }
15738
15739    pub fn toggle_diagnostics(
15740        &mut self,
15741        _: &ToggleDiagnostics,
15742        window: &mut Window,
15743        cx: &mut Context<Editor>,
15744    ) {
15745        if !self.diagnostics_enabled() {
15746            return;
15747        }
15748
15749        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15750            EditorSettings::get_global(cx)
15751                .diagnostics_max_severity
15752                .filter(|severity| severity != &DiagnosticSeverity::Off)
15753                .unwrap_or(DiagnosticSeverity::Hint)
15754        } else {
15755            DiagnosticSeverity::Off
15756        };
15757        self.set_max_diagnostics_severity(new_severity, cx);
15758        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15759            self.active_diagnostics = ActiveDiagnostic::None;
15760            self.inline_diagnostics_update = Task::ready(());
15761            self.inline_diagnostics.clear();
15762        } else {
15763            self.refresh_inline_diagnostics(false, window, cx);
15764        }
15765
15766        cx.notify();
15767    }
15768
15769    pub fn toggle_minimap(
15770        &mut self,
15771        _: &ToggleMinimap,
15772        window: &mut Window,
15773        cx: &mut Context<Editor>,
15774    ) {
15775        if self.supports_minimap(cx) {
15776            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15777        }
15778    }
15779
15780    fn refresh_inline_diagnostics(
15781        &mut self,
15782        debounce: bool,
15783        window: &mut Window,
15784        cx: &mut Context<Self>,
15785    ) {
15786        let max_severity = ProjectSettings::get_global(cx)
15787            .diagnostics
15788            .inline
15789            .max_severity
15790            .unwrap_or(self.diagnostics_max_severity);
15791
15792        if !self.inline_diagnostics_enabled()
15793            || !self.show_inline_diagnostics
15794            || max_severity == DiagnosticSeverity::Off
15795        {
15796            self.inline_diagnostics_update = Task::ready(());
15797            self.inline_diagnostics.clear();
15798            return;
15799        }
15800
15801        let debounce_ms = ProjectSettings::get_global(cx)
15802            .diagnostics
15803            .inline
15804            .update_debounce_ms;
15805        let debounce = if debounce && debounce_ms > 0 {
15806            Some(Duration::from_millis(debounce_ms))
15807        } else {
15808            None
15809        };
15810        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15811            if let Some(debounce) = debounce {
15812                cx.background_executor().timer(debounce).await;
15813            }
15814            let Some(snapshot) = editor.upgrade().and_then(|editor| {
15815                editor
15816                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15817                    .ok()
15818            }) else {
15819                return;
15820            };
15821
15822            let new_inline_diagnostics = cx
15823                .background_spawn(async move {
15824                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15825                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15826                        let message = diagnostic_entry
15827                            .diagnostic
15828                            .message
15829                            .split_once('\n')
15830                            .map(|(line, _)| line)
15831                            .map(SharedString::new)
15832                            .unwrap_or_else(|| {
15833                                SharedString::from(diagnostic_entry.diagnostic.message)
15834                            });
15835                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15836                        let (Ok(i) | Err(i)) = inline_diagnostics
15837                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15838                        inline_diagnostics.insert(
15839                            i,
15840                            (
15841                                start_anchor,
15842                                InlineDiagnostic {
15843                                    message,
15844                                    group_id: diagnostic_entry.diagnostic.group_id,
15845                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15846                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15847                                    severity: diagnostic_entry.diagnostic.severity,
15848                                },
15849                            ),
15850                        );
15851                    }
15852                    inline_diagnostics
15853                })
15854                .await;
15855
15856            editor
15857                .update(cx, |editor, cx| {
15858                    editor.inline_diagnostics = new_inline_diagnostics;
15859                    cx.notify();
15860                })
15861                .ok();
15862        });
15863    }
15864
15865    pub fn set_selections_from_remote(
15866        &mut self,
15867        selections: Vec<Selection<Anchor>>,
15868        pending_selection: Option<Selection<Anchor>>,
15869        window: &mut Window,
15870        cx: &mut Context<Self>,
15871    ) {
15872        let old_cursor_position = self.selections.newest_anchor().head();
15873        self.selections.change_with(cx, |s| {
15874            s.select_anchors(selections);
15875            if let Some(pending_selection) = pending_selection {
15876                s.set_pending(pending_selection, SelectMode::Character);
15877            } else {
15878                s.clear_pending();
15879            }
15880        });
15881        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15882    }
15883
15884    pub fn transact(
15885        &mut self,
15886        window: &mut Window,
15887        cx: &mut Context<Self>,
15888        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15889    ) -> Option<TransactionId> {
15890        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15891            this.start_transaction_at(Instant::now(), window, cx);
15892            update(this, window, cx);
15893            this.end_transaction_at(Instant::now(), cx)
15894        })
15895    }
15896
15897    pub fn start_transaction_at(
15898        &mut self,
15899        now: Instant,
15900        window: &mut Window,
15901        cx: &mut Context<Self>,
15902    ) {
15903        self.end_selection(window, cx);
15904        if let Some(tx_id) = self
15905            .buffer
15906            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15907        {
15908            self.selection_history
15909                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15910            cx.emit(EditorEvent::TransactionBegun {
15911                transaction_id: tx_id,
15912            })
15913        }
15914    }
15915
15916    pub fn end_transaction_at(
15917        &mut self,
15918        now: Instant,
15919        cx: &mut Context<Self>,
15920    ) -> Option<TransactionId> {
15921        if let Some(transaction_id) = self
15922            .buffer
15923            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15924        {
15925            if let Some((_, end_selections)) =
15926                self.selection_history.transaction_mut(transaction_id)
15927            {
15928                *end_selections = Some(self.selections.disjoint_anchors());
15929            } else {
15930                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15931            }
15932
15933            cx.emit(EditorEvent::Edited { transaction_id });
15934            Some(transaction_id)
15935        } else {
15936            None
15937        }
15938    }
15939
15940    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15941        if self.selection_mark_mode {
15942            self.change_selections(None, window, cx, |s| {
15943                s.move_with(|_, sel| {
15944                    sel.collapse_to(sel.head(), SelectionGoal::None);
15945                });
15946            })
15947        }
15948        self.selection_mark_mode = true;
15949        cx.notify();
15950    }
15951
15952    pub fn swap_selection_ends(
15953        &mut self,
15954        _: &actions::SwapSelectionEnds,
15955        window: &mut Window,
15956        cx: &mut Context<Self>,
15957    ) {
15958        self.change_selections(None, window, cx, |s| {
15959            s.move_with(|_, sel| {
15960                if sel.start != sel.end {
15961                    sel.reversed = !sel.reversed
15962                }
15963            });
15964        });
15965        self.request_autoscroll(Autoscroll::newest(), cx);
15966        cx.notify();
15967    }
15968
15969    pub fn toggle_fold(
15970        &mut self,
15971        _: &actions::ToggleFold,
15972        window: &mut Window,
15973        cx: &mut Context<Self>,
15974    ) {
15975        if self.is_singleton(cx) {
15976            let selection = self.selections.newest::<Point>(cx);
15977
15978            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15979            let range = if selection.is_empty() {
15980                let point = selection.head().to_display_point(&display_map);
15981                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15982                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15983                    .to_point(&display_map);
15984                start..end
15985            } else {
15986                selection.range()
15987            };
15988            if display_map.folds_in_range(range).next().is_some() {
15989                self.unfold_lines(&Default::default(), window, cx)
15990            } else {
15991                self.fold(&Default::default(), window, cx)
15992            }
15993        } else {
15994            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15995            let buffer_ids: HashSet<_> = self
15996                .selections
15997                .disjoint_anchor_ranges()
15998                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15999                .collect();
16000
16001            let should_unfold = buffer_ids
16002                .iter()
16003                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
16004
16005            for buffer_id in buffer_ids {
16006                if should_unfold {
16007                    self.unfold_buffer(buffer_id, cx);
16008                } else {
16009                    self.fold_buffer(buffer_id, cx);
16010                }
16011            }
16012        }
16013    }
16014
16015    pub fn toggle_fold_recursive(
16016        &mut self,
16017        _: &actions::ToggleFoldRecursive,
16018        window: &mut Window,
16019        cx: &mut Context<Self>,
16020    ) {
16021        let selection = self.selections.newest::<Point>(cx);
16022
16023        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16024        let range = if selection.is_empty() {
16025            let point = selection.head().to_display_point(&display_map);
16026            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16027            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16028                .to_point(&display_map);
16029            start..end
16030        } else {
16031            selection.range()
16032        };
16033        if display_map.folds_in_range(range).next().is_some() {
16034            self.unfold_recursive(&Default::default(), window, cx)
16035        } else {
16036            self.fold_recursive(&Default::default(), window, cx)
16037        }
16038    }
16039
16040    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16041        if self.is_singleton(cx) {
16042            let mut to_fold = Vec::new();
16043            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16044            let selections = self.selections.all_adjusted(cx);
16045
16046            for selection in selections {
16047                let range = selection.range().sorted();
16048                let buffer_start_row = range.start.row;
16049
16050                if range.start.row != range.end.row {
16051                    let mut found = false;
16052                    let mut row = range.start.row;
16053                    while row <= range.end.row {
16054                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16055                        {
16056                            found = true;
16057                            row = crease.range().end.row + 1;
16058                            to_fold.push(crease);
16059                        } else {
16060                            row += 1
16061                        }
16062                    }
16063                    if found {
16064                        continue;
16065                    }
16066                }
16067
16068                for row in (0..=range.start.row).rev() {
16069                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16070                        if crease.range().end.row >= buffer_start_row {
16071                            to_fold.push(crease);
16072                            if row <= range.start.row {
16073                                break;
16074                            }
16075                        }
16076                    }
16077                }
16078            }
16079
16080            self.fold_creases(to_fold, true, window, cx);
16081        } else {
16082            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16083            let buffer_ids = self
16084                .selections
16085                .disjoint_anchor_ranges()
16086                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16087                .collect::<HashSet<_>>();
16088            for buffer_id in buffer_ids {
16089                self.fold_buffer(buffer_id, cx);
16090            }
16091        }
16092    }
16093
16094    fn fold_at_level(
16095        &mut self,
16096        fold_at: &FoldAtLevel,
16097        window: &mut Window,
16098        cx: &mut Context<Self>,
16099    ) {
16100        if !self.buffer.read(cx).is_singleton() {
16101            return;
16102        }
16103
16104        let fold_at_level = fold_at.0;
16105        let snapshot = self.buffer.read(cx).snapshot(cx);
16106        let mut to_fold = Vec::new();
16107        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16108
16109        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16110            while start_row < end_row {
16111                match self
16112                    .snapshot(window, cx)
16113                    .crease_for_buffer_row(MultiBufferRow(start_row))
16114                {
16115                    Some(crease) => {
16116                        let nested_start_row = crease.range().start.row + 1;
16117                        let nested_end_row = crease.range().end.row;
16118
16119                        if current_level < fold_at_level {
16120                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16121                        } else if current_level == fold_at_level {
16122                            to_fold.push(crease);
16123                        }
16124
16125                        start_row = nested_end_row + 1;
16126                    }
16127                    None => start_row += 1,
16128                }
16129            }
16130        }
16131
16132        self.fold_creases(to_fold, true, window, cx);
16133    }
16134
16135    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16136        if self.buffer.read(cx).is_singleton() {
16137            let mut fold_ranges = Vec::new();
16138            let snapshot = self.buffer.read(cx).snapshot(cx);
16139
16140            for row in 0..snapshot.max_row().0 {
16141                if let Some(foldable_range) = self
16142                    .snapshot(window, cx)
16143                    .crease_for_buffer_row(MultiBufferRow(row))
16144                {
16145                    fold_ranges.push(foldable_range);
16146                }
16147            }
16148
16149            self.fold_creases(fold_ranges, true, window, cx);
16150        } else {
16151            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16152                editor
16153                    .update_in(cx, |editor, _, cx| {
16154                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16155                            editor.fold_buffer(buffer_id, cx);
16156                        }
16157                    })
16158                    .ok();
16159            });
16160        }
16161    }
16162
16163    pub fn fold_function_bodies(
16164        &mut self,
16165        _: &actions::FoldFunctionBodies,
16166        window: &mut Window,
16167        cx: &mut Context<Self>,
16168    ) {
16169        let snapshot = self.buffer.read(cx).snapshot(cx);
16170
16171        let ranges = snapshot
16172            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16173            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16174            .collect::<Vec<_>>();
16175
16176        let creases = ranges
16177            .into_iter()
16178            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16179            .collect();
16180
16181        self.fold_creases(creases, true, window, cx);
16182    }
16183
16184    pub fn fold_recursive(
16185        &mut self,
16186        _: &actions::FoldRecursive,
16187        window: &mut Window,
16188        cx: &mut Context<Self>,
16189    ) {
16190        let mut to_fold = Vec::new();
16191        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16192        let selections = self.selections.all_adjusted(cx);
16193
16194        for selection in selections {
16195            let range = selection.range().sorted();
16196            let buffer_start_row = range.start.row;
16197
16198            if range.start.row != range.end.row {
16199                let mut found = false;
16200                for row in range.start.row..=range.end.row {
16201                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16202                        found = true;
16203                        to_fold.push(crease);
16204                    }
16205                }
16206                if found {
16207                    continue;
16208                }
16209            }
16210
16211            for row in (0..=range.start.row).rev() {
16212                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16213                    if crease.range().end.row >= buffer_start_row {
16214                        to_fold.push(crease);
16215                    } else {
16216                        break;
16217                    }
16218                }
16219            }
16220        }
16221
16222        self.fold_creases(to_fold, true, window, cx);
16223    }
16224
16225    pub fn fold_at(
16226        &mut self,
16227        buffer_row: MultiBufferRow,
16228        window: &mut Window,
16229        cx: &mut Context<Self>,
16230    ) {
16231        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16232
16233        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16234            let autoscroll = self
16235                .selections
16236                .all::<Point>(cx)
16237                .iter()
16238                .any(|selection| crease.range().overlaps(&selection.range()));
16239
16240            self.fold_creases(vec![crease], autoscroll, window, cx);
16241        }
16242    }
16243
16244    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16245        if self.is_singleton(cx) {
16246            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16247            let buffer = &display_map.buffer_snapshot;
16248            let selections = self.selections.all::<Point>(cx);
16249            let ranges = selections
16250                .iter()
16251                .map(|s| {
16252                    let range = s.display_range(&display_map).sorted();
16253                    let mut start = range.start.to_point(&display_map);
16254                    let mut end = range.end.to_point(&display_map);
16255                    start.column = 0;
16256                    end.column = buffer.line_len(MultiBufferRow(end.row));
16257                    start..end
16258                })
16259                .collect::<Vec<_>>();
16260
16261            self.unfold_ranges(&ranges, true, true, cx);
16262        } else {
16263            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16264            let buffer_ids = self
16265                .selections
16266                .disjoint_anchor_ranges()
16267                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16268                .collect::<HashSet<_>>();
16269            for buffer_id in buffer_ids {
16270                self.unfold_buffer(buffer_id, cx);
16271            }
16272        }
16273    }
16274
16275    pub fn unfold_recursive(
16276        &mut self,
16277        _: &UnfoldRecursive,
16278        _window: &mut Window,
16279        cx: &mut Context<Self>,
16280    ) {
16281        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16282        let selections = self.selections.all::<Point>(cx);
16283        let ranges = selections
16284            .iter()
16285            .map(|s| {
16286                let mut range = s.display_range(&display_map).sorted();
16287                *range.start.column_mut() = 0;
16288                *range.end.column_mut() = display_map.line_len(range.end.row());
16289                let start = range.start.to_point(&display_map);
16290                let end = range.end.to_point(&display_map);
16291                start..end
16292            })
16293            .collect::<Vec<_>>();
16294
16295        self.unfold_ranges(&ranges, true, true, cx);
16296    }
16297
16298    pub fn unfold_at(
16299        &mut self,
16300        buffer_row: MultiBufferRow,
16301        _window: &mut Window,
16302        cx: &mut Context<Self>,
16303    ) {
16304        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16305
16306        let intersection_range = Point::new(buffer_row.0, 0)
16307            ..Point::new(
16308                buffer_row.0,
16309                display_map.buffer_snapshot.line_len(buffer_row),
16310            );
16311
16312        let autoscroll = self
16313            .selections
16314            .all::<Point>(cx)
16315            .iter()
16316            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16317
16318        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16319    }
16320
16321    pub fn unfold_all(
16322        &mut self,
16323        _: &actions::UnfoldAll,
16324        _window: &mut Window,
16325        cx: &mut Context<Self>,
16326    ) {
16327        if self.buffer.read(cx).is_singleton() {
16328            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16329            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16330        } else {
16331            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16332                editor
16333                    .update(cx, |editor, cx| {
16334                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16335                            editor.unfold_buffer(buffer_id, cx);
16336                        }
16337                    })
16338                    .ok();
16339            });
16340        }
16341    }
16342
16343    pub fn fold_selected_ranges(
16344        &mut self,
16345        _: &FoldSelectedRanges,
16346        window: &mut Window,
16347        cx: &mut Context<Self>,
16348    ) {
16349        let selections = self.selections.all_adjusted(cx);
16350        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16351        let ranges = selections
16352            .into_iter()
16353            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16354            .collect::<Vec<_>>();
16355        self.fold_creases(ranges, true, window, cx);
16356    }
16357
16358    pub fn fold_ranges<T: ToOffset + Clone>(
16359        &mut self,
16360        ranges: Vec<Range<T>>,
16361        auto_scroll: bool,
16362        window: &mut Window,
16363        cx: &mut Context<Self>,
16364    ) {
16365        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16366        let ranges = ranges
16367            .into_iter()
16368            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16369            .collect::<Vec<_>>();
16370        self.fold_creases(ranges, auto_scroll, window, cx);
16371    }
16372
16373    pub fn fold_creases<T: ToOffset + Clone>(
16374        &mut self,
16375        creases: Vec<Crease<T>>,
16376        auto_scroll: bool,
16377        _window: &mut Window,
16378        cx: &mut Context<Self>,
16379    ) {
16380        if creases.is_empty() {
16381            return;
16382        }
16383
16384        let mut buffers_affected = HashSet::default();
16385        let multi_buffer = self.buffer().read(cx);
16386        for crease in &creases {
16387            if let Some((_, buffer, _)) =
16388                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16389            {
16390                buffers_affected.insert(buffer.read(cx).remote_id());
16391            };
16392        }
16393
16394        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16395
16396        if auto_scroll {
16397            self.request_autoscroll(Autoscroll::fit(), cx);
16398        }
16399
16400        cx.notify();
16401
16402        self.scrollbar_marker_state.dirty = true;
16403        self.folds_did_change(cx);
16404    }
16405
16406    /// Removes any folds whose ranges intersect any of the given ranges.
16407    pub fn unfold_ranges<T: ToOffset + Clone>(
16408        &mut self,
16409        ranges: &[Range<T>],
16410        inclusive: bool,
16411        auto_scroll: bool,
16412        cx: &mut Context<Self>,
16413    ) {
16414        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16415            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16416        });
16417        self.folds_did_change(cx);
16418    }
16419
16420    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16421        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16422            return;
16423        }
16424        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16425        self.display_map.update(cx, |display_map, cx| {
16426            display_map.fold_buffers([buffer_id], cx)
16427        });
16428        cx.emit(EditorEvent::BufferFoldToggled {
16429            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16430            folded: true,
16431        });
16432        cx.notify();
16433    }
16434
16435    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16436        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16437            return;
16438        }
16439        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16440        self.display_map.update(cx, |display_map, cx| {
16441            display_map.unfold_buffers([buffer_id], cx);
16442        });
16443        cx.emit(EditorEvent::BufferFoldToggled {
16444            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16445            folded: false,
16446        });
16447        cx.notify();
16448    }
16449
16450    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16451        self.display_map.read(cx).is_buffer_folded(buffer)
16452    }
16453
16454    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16455        self.display_map.read(cx).folded_buffers()
16456    }
16457
16458    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16459        self.display_map.update(cx, |display_map, cx| {
16460            display_map.disable_header_for_buffer(buffer_id, cx);
16461        });
16462        cx.notify();
16463    }
16464
16465    /// Removes any folds with the given ranges.
16466    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16467        &mut self,
16468        ranges: &[Range<T>],
16469        type_id: TypeId,
16470        auto_scroll: bool,
16471        cx: &mut Context<Self>,
16472    ) {
16473        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16474            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16475        });
16476        self.folds_did_change(cx);
16477    }
16478
16479    fn remove_folds_with<T: ToOffset + Clone>(
16480        &mut self,
16481        ranges: &[Range<T>],
16482        auto_scroll: bool,
16483        cx: &mut Context<Self>,
16484        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16485    ) {
16486        if ranges.is_empty() {
16487            return;
16488        }
16489
16490        let mut buffers_affected = HashSet::default();
16491        let multi_buffer = self.buffer().read(cx);
16492        for range in ranges {
16493            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16494                buffers_affected.insert(buffer.read(cx).remote_id());
16495            };
16496        }
16497
16498        self.display_map.update(cx, update);
16499
16500        if auto_scroll {
16501            self.request_autoscroll(Autoscroll::fit(), cx);
16502        }
16503
16504        cx.notify();
16505        self.scrollbar_marker_state.dirty = true;
16506        self.active_indent_guides_state.dirty = true;
16507    }
16508
16509    pub fn update_fold_widths(
16510        &mut self,
16511        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16512        cx: &mut Context<Self>,
16513    ) -> bool {
16514        self.display_map
16515            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16516    }
16517
16518    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16519        self.display_map.read(cx).fold_placeholder.clone()
16520    }
16521
16522    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16523        self.buffer.update(cx, |buffer, cx| {
16524            buffer.set_all_diff_hunks_expanded(cx);
16525        });
16526    }
16527
16528    pub fn expand_all_diff_hunks(
16529        &mut self,
16530        _: &ExpandAllDiffHunks,
16531        _window: &mut Window,
16532        cx: &mut Context<Self>,
16533    ) {
16534        self.buffer.update(cx, |buffer, cx| {
16535            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16536        });
16537    }
16538
16539    pub fn toggle_selected_diff_hunks(
16540        &mut self,
16541        _: &ToggleSelectedDiffHunks,
16542        _window: &mut Window,
16543        cx: &mut Context<Self>,
16544    ) {
16545        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16546        self.toggle_diff_hunks_in_ranges(ranges, cx);
16547    }
16548
16549    pub fn diff_hunks_in_ranges<'a>(
16550        &'a self,
16551        ranges: &'a [Range<Anchor>],
16552        buffer: &'a MultiBufferSnapshot,
16553    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16554        ranges.iter().flat_map(move |range| {
16555            let end_excerpt_id = range.end.excerpt_id;
16556            let range = range.to_point(buffer);
16557            let mut peek_end = range.end;
16558            if range.end.row < buffer.max_row().0 {
16559                peek_end = Point::new(range.end.row + 1, 0);
16560            }
16561            buffer
16562                .diff_hunks_in_range(range.start..peek_end)
16563                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16564        })
16565    }
16566
16567    pub fn has_stageable_diff_hunks_in_ranges(
16568        &self,
16569        ranges: &[Range<Anchor>],
16570        snapshot: &MultiBufferSnapshot,
16571    ) -> bool {
16572        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16573        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16574    }
16575
16576    pub fn toggle_staged_selected_diff_hunks(
16577        &mut self,
16578        _: &::git::ToggleStaged,
16579        _: &mut Window,
16580        cx: &mut Context<Self>,
16581    ) {
16582        let snapshot = self.buffer.read(cx).snapshot(cx);
16583        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16584        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16585        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16586    }
16587
16588    pub fn set_render_diff_hunk_controls(
16589        &mut self,
16590        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16591        cx: &mut Context<Self>,
16592    ) {
16593        self.render_diff_hunk_controls = render_diff_hunk_controls;
16594        cx.notify();
16595    }
16596
16597    pub fn stage_and_next(
16598        &mut self,
16599        _: &::git::StageAndNext,
16600        window: &mut Window,
16601        cx: &mut Context<Self>,
16602    ) {
16603        self.do_stage_or_unstage_and_next(true, window, cx);
16604    }
16605
16606    pub fn unstage_and_next(
16607        &mut self,
16608        _: &::git::UnstageAndNext,
16609        window: &mut Window,
16610        cx: &mut Context<Self>,
16611    ) {
16612        self.do_stage_or_unstage_and_next(false, window, cx);
16613    }
16614
16615    pub fn stage_or_unstage_diff_hunks(
16616        &mut self,
16617        stage: bool,
16618        ranges: Vec<Range<Anchor>>,
16619        cx: &mut Context<Self>,
16620    ) {
16621        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16622        cx.spawn(async move |this, cx| {
16623            task.await?;
16624            this.update(cx, |this, cx| {
16625                let snapshot = this.buffer.read(cx).snapshot(cx);
16626                let chunk_by = this
16627                    .diff_hunks_in_ranges(&ranges, &snapshot)
16628                    .chunk_by(|hunk| hunk.buffer_id);
16629                for (buffer_id, hunks) in &chunk_by {
16630                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16631                }
16632            })
16633        })
16634        .detach_and_log_err(cx);
16635    }
16636
16637    fn save_buffers_for_ranges_if_needed(
16638        &mut self,
16639        ranges: &[Range<Anchor>],
16640        cx: &mut Context<Editor>,
16641    ) -> Task<Result<()>> {
16642        let multibuffer = self.buffer.read(cx);
16643        let snapshot = multibuffer.read(cx);
16644        let buffer_ids: HashSet<_> = ranges
16645            .iter()
16646            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16647            .collect();
16648        drop(snapshot);
16649
16650        let mut buffers = HashSet::default();
16651        for buffer_id in buffer_ids {
16652            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16653                let buffer = buffer_entity.read(cx);
16654                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16655                {
16656                    buffers.insert(buffer_entity);
16657                }
16658            }
16659        }
16660
16661        if let Some(project) = &self.project {
16662            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16663        } else {
16664            Task::ready(Ok(()))
16665        }
16666    }
16667
16668    fn do_stage_or_unstage_and_next(
16669        &mut self,
16670        stage: bool,
16671        window: &mut Window,
16672        cx: &mut Context<Self>,
16673    ) {
16674        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16675
16676        if ranges.iter().any(|range| range.start != range.end) {
16677            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16678            return;
16679        }
16680
16681        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16682        let snapshot = self.snapshot(window, cx);
16683        let position = self.selections.newest::<Point>(cx).head();
16684        let mut row = snapshot
16685            .buffer_snapshot
16686            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16687            .find(|hunk| hunk.row_range.start.0 > position.row)
16688            .map(|hunk| hunk.row_range.start);
16689
16690        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16691        // Outside of the project diff editor, wrap around to the beginning.
16692        if !all_diff_hunks_expanded {
16693            row = row.or_else(|| {
16694                snapshot
16695                    .buffer_snapshot
16696                    .diff_hunks_in_range(Point::zero()..position)
16697                    .find(|hunk| hunk.row_range.end.0 < position.row)
16698                    .map(|hunk| hunk.row_range.start)
16699            });
16700        }
16701
16702        if let Some(row) = row {
16703            let destination = Point::new(row.0, 0);
16704            let autoscroll = Autoscroll::center();
16705
16706            self.unfold_ranges(&[destination..destination], false, false, cx);
16707            self.change_selections(Some(autoscroll), window, cx, |s| {
16708                s.select_ranges([destination..destination]);
16709            });
16710        }
16711    }
16712
16713    fn do_stage_or_unstage(
16714        &self,
16715        stage: bool,
16716        buffer_id: BufferId,
16717        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16718        cx: &mut App,
16719    ) -> Option<()> {
16720        let project = self.project.as_ref()?;
16721        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16722        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16723        let buffer_snapshot = buffer.read(cx).snapshot();
16724        let file_exists = buffer_snapshot
16725            .file()
16726            .is_some_and(|file| file.disk_state().exists());
16727        diff.update(cx, |diff, cx| {
16728            diff.stage_or_unstage_hunks(
16729                stage,
16730                &hunks
16731                    .map(|hunk| buffer_diff::DiffHunk {
16732                        buffer_range: hunk.buffer_range,
16733                        diff_base_byte_range: hunk.diff_base_byte_range,
16734                        secondary_status: hunk.secondary_status,
16735                        range: Point::zero()..Point::zero(), // unused
16736                    })
16737                    .collect::<Vec<_>>(),
16738                &buffer_snapshot,
16739                file_exists,
16740                cx,
16741            )
16742        });
16743        None
16744    }
16745
16746    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16747        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16748        self.buffer
16749            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16750    }
16751
16752    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16753        self.buffer.update(cx, |buffer, cx| {
16754            let ranges = vec![Anchor::min()..Anchor::max()];
16755            if !buffer.all_diff_hunks_expanded()
16756                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16757            {
16758                buffer.collapse_diff_hunks(ranges, cx);
16759                true
16760            } else {
16761                false
16762            }
16763        })
16764    }
16765
16766    fn toggle_diff_hunks_in_ranges(
16767        &mut self,
16768        ranges: Vec<Range<Anchor>>,
16769        cx: &mut Context<Editor>,
16770    ) {
16771        self.buffer.update(cx, |buffer, cx| {
16772            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16773            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16774        })
16775    }
16776
16777    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16778        self.buffer.update(cx, |buffer, cx| {
16779            let snapshot = buffer.snapshot(cx);
16780            let excerpt_id = range.end.excerpt_id;
16781            let point_range = range.to_point(&snapshot);
16782            let expand = !buffer.single_hunk_is_expanded(range, cx);
16783            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16784        })
16785    }
16786
16787    pub(crate) fn apply_all_diff_hunks(
16788        &mut self,
16789        _: &ApplyAllDiffHunks,
16790        window: &mut Window,
16791        cx: &mut Context<Self>,
16792    ) {
16793        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16794
16795        let buffers = self.buffer.read(cx).all_buffers();
16796        for branch_buffer in buffers {
16797            branch_buffer.update(cx, |branch_buffer, cx| {
16798                branch_buffer.merge_into_base(Vec::new(), cx);
16799            });
16800        }
16801
16802        if let Some(project) = self.project.clone() {
16803            self.save(true, project, window, cx).detach_and_log_err(cx);
16804        }
16805    }
16806
16807    pub(crate) fn apply_selected_diff_hunks(
16808        &mut self,
16809        _: &ApplyDiffHunk,
16810        window: &mut Window,
16811        cx: &mut Context<Self>,
16812    ) {
16813        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16814        let snapshot = self.snapshot(window, cx);
16815        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16816        let mut ranges_by_buffer = HashMap::default();
16817        self.transact(window, cx, |editor, _window, cx| {
16818            for hunk in hunks {
16819                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16820                    ranges_by_buffer
16821                        .entry(buffer.clone())
16822                        .or_insert_with(Vec::new)
16823                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16824                }
16825            }
16826
16827            for (buffer, ranges) in ranges_by_buffer {
16828                buffer.update(cx, |buffer, cx| {
16829                    buffer.merge_into_base(ranges, cx);
16830                });
16831            }
16832        });
16833
16834        if let Some(project) = self.project.clone() {
16835            self.save(true, project, window, cx).detach_and_log_err(cx);
16836        }
16837    }
16838
16839    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16840        if hovered != self.gutter_hovered {
16841            self.gutter_hovered = hovered;
16842            cx.notify();
16843        }
16844    }
16845
16846    pub fn insert_blocks(
16847        &mut self,
16848        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16849        autoscroll: Option<Autoscroll>,
16850        cx: &mut Context<Self>,
16851    ) -> Vec<CustomBlockId> {
16852        let blocks = self
16853            .display_map
16854            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16855        if let Some(autoscroll) = autoscroll {
16856            self.request_autoscroll(autoscroll, cx);
16857        }
16858        cx.notify();
16859        blocks
16860    }
16861
16862    pub fn resize_blocks(
16863        &mut self,
16864        heights: HashMap<CustomBlockId, u32>,
16865        autoscroll: Option<Autoscroll>,
16866        cx: &mut Context<Self>,
16867    ) {
16868        self.display_map
16869            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16870        if let Some(autoscroll) = autoscroll {
16871            self.request_autoscroll(autoscroll, cx);
16872        }
16873        cx.notify();
16874    }
16875
16876    pub fn replace_blocks(
16877        &mut self,
16878        renderers: HashMap<CustomBlockId, RenderBlock>,
16879        autoscroll: Option<Autoscroll>,
16880        cx: &mut Context<Self>,
16881    ) {
16882        self.display_map
16883            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16884        if let Some(autoscroll) = autoscroll {
16885            self.request_autoscroll(autoscroll, cx);
16886        }
16887        cx.notify();
16888    }
16889
16890    pub fn remove_blocks(
16891        &mut self,
16892        block_ids: HashSet<CustomBlockId>,
16893        autoscroll: Option<Autoscroll>,
16894        cx: &mut Context<Self>,
16895    ) {
16896        self.display_map.update(cx, |display_map, cx| {
16897            display_map.remove_blocks(block_ids, cx)
16898        });
16899        if let Some(autoscroll) = autoscroll {
16900            self.request_autoscroll(autoscroll, cx);
16901        }
16902        cx.notify();
16903    }
16904
16905    pub fn row_for_block(
16906        &self,
16907        block_id: CustomBlockId,
16908        cx: &mut Context<Self>,
16909    ) -> Option<DisplayRow> {
16910        self.display_map
16911            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16912    }
16913
16914    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16915        self.focused_block = Some(focused_block);
16916    }
16917
16918    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16919        self.focused_block.take()
16920    }
16921
16922    pub fn insert_creases(
16923        &mut self,
16924        creases: impl IntoIterator<Item = Crease<Anchor>>,
16925        cx: &mut Context<Self>,
16926    ) -> Vec<CreaseId> {
16927        self.display_map
16928            .update(cx, |map, cx| map.insert_creases(creases, cx))
16929    }
16930
16931    pub fn remove_creases(
16932        &mut self,
16933        ids: impl IntoIterator<Item = CreaseId>,
16934        cx: &mut Context<Self>,
16935    ) -> Vec<(CreaseId, Range<Anchor>)> {
16936        self.display_map
16937            .update(cx, |map, cx| map.remove_creases(ids, cx))
16938    }
16939
16940    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16941        self.display_map
16942            .update(cx, |map, cx| map.snapshot(cx))
16943            .longest_row()
16944    }
16945
16946    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16947        self.display_map
16948            .update(cx, |map, cx| map.snapshot(cx))
16949            .max_point()
16950    }
16951
16952    pub fn text(&self, cx: &App) -> String {
16953        self.buffer.read(cx).read(cx).text()
16954    }
16955
16956    pub fn is_empty(&self, cx: &App) -> bool {
16957        self.buffer.read(cx).read(cx).is_empty()
16958    }
16959
16960    pub fn text_option(&self, cx: &App) -> Option<String> {
16961        let text = self.text(cx);
16962        let text = text.trim();
16963
16964        if text.is_empty() {
16965            return None;
16966        }
16967
16968        Some(text.to_string())
16969    }
16970
16971    pub fn set_text(
16972        &mut self,
16973        text: impl Into<Arc<str>>,
16974        window: &mut Window,
16975        cx: &mut Context<Self>,
16976    ) {
16977        self.transact(window, cx, |this, _, cx| {
16978            this.buffer
16979                .read(cx)
16980                .as_singleton()
16981                .expect("you can only call set_text on editors for singleton buffers")
16982                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16983        });
16984    }
16985
16986    pub fn display_text(&self, cx: &mut App) -> String {
16987        self.display_map
16988            .update(cx, |map, cx| map.snapshot(cx))
16989            .text()
16990    }
16991
16992    fn create_minimap(
16993        &self,
16994        minimap_settings: MinimapSettings,
16995        window: &mut Window,
16996        cx: &mut Context<Self>,
16997    ) -> Option<Entity<Self>> {
16998        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16999            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
17000    }
17001
17002    fn initialize_new_minimap(
17003        &self,
17004        minimap_settings: MinimapSettings,
17005        window: &mut Window,
17006        cx: &mut Context<Self>,
17007    ) -> Entity<Self> {
17008        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
17009
17010        let mut minimap = Editor::new_internal(
17011            EditorMode::Minimap {
17012                parent: cx.weak_entity(),
17013            },
17014            self.buffer.clone(),
17015            self.project.clone(),
17016            Some(self.display_map.clone()),
17017            window,
17018            cx,
17019        );
17020        minimap.scroll_manager.clone_state(&self.scroll_manager);
17021        minimap.set_text_style_refinement(TextStyleRefinement {
17022            font_size: Some(MINIMAP_FONT_SIZE),
17023            font_weight: Some(MINIMAP_FONT_WEIGHT),
17024            ..Default::default()
17025        });
17026        minimap.update_minimap_configuration(minimap_settings, cx);
17027        cx.new(|_| minimap)
17028    }
17029
17030    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17031        let current_line_highlight = minimap_settings
17032            .current_line_highlight
17033            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17034        self.set_current_line_highlight(Some(current_line_highlight));
17035    }
17036
17037    pub fn minimap(&self) -> Option<&Entity<Self>> {
17038        self.minimap
17039            .as_ref()
17040            .filter(|_| self.minimap_visibility.visible())
17041    }
17042
17043    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17044        let mut wrap_guides = smallvec![];
17045
17046        if self.show_wrap_guides == Some(false) {
17047            return wrap_guides;
17048        }
17049
17050        let settings = self.buffer.read(cx).language_settings(cx);
17051        if settings.show_wrap_guides {
17052            match self.soft_wrap_mode(cx) {
17053                SoftWrap::Column(soft_wrap) => {
17054                    wrap_guides.push((soft_wrap as usize, true));
17055                }
17056                SoftWrap::Bounded(soft_wrap) => {
17057                    wrap_guides.push((soft_wrap as usize, true));
17058                }
17059                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17060            }
17061            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17062        }
17063
17064        wrap_guides
17065    }
17066
17067    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17068        let settings = self.buffer.read(cx).language_settings(cx);
17069        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17070        match mode {
17071            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17072                SoftWrap::None
17073            }
17074            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17075            language_settings::SoftWrap::PreferredLineLength => {
17076                SoftWrap::Column(settings.preferred_line_length)
17077            }
17078            language_settings::SoftWrap::Bounded => {
17079                SoftWrap::Bounded(settings.preferred_line_length)
17080            }
17081        }
17082    }
17083
17084    pub fn set_soft_wrap_mode(
17085        &mut self,
17086        mode: language_settings::SoftWrap,
17087
17088        cx: &mut Context<Self>,
17089    ) {
17090        self.soft_wrap_mode_override = Some(mode);
17091        cx.notify();
17092    }
17093
17094    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17095        self.hard_wrap = hard_wrap;
17096        cx.notify();
17097    }
17098
17099    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17100        self.text_style_refinement = Some(style);
17101    }
17102
17103    /// called by the Element so we know what style we were most recently rendered with.
17104    pub(crate) fn set_style(
17105        &mut self,
17106        style: EditorStyle,
17107        window: &mut Window,
17108        cx: &mut Context<Self>,
17109    ) {
17110        // We intentionally do not inform the display map about the minimap style
17111        // so that wrapping is not recalculated and stays consistent for the editor
17112        // and its linked minimap.
17113        if !self.mode.is_minimap() {
17114            let rem_size = window.rem_size();
17115            self.display_map.update(cx, |map, cx| {
17116                map.set_font(
17117                    style.text.font(),
17118                    style.text.font_size.to_pixels(rem_size),
17119                    cx,
17120                )
17121            });
17122        }
17123        self.style = Some(style);
17124    }
17125
17126    pub fn style(&self) -> Option<&EditorStyle> {
17127        self.style.as_ref()
17128    }
17129
17130    // Called by the element. This method is not designed to be called outside of the editor
17131    // element's layout code because it does not notify when rewrapping is computed synchronously.
17132    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17133        self.display_map
17134            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17135    }
17136
17137    pub fn set_soft_wrap(&mut self) {
17138        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17139    }
17140
17141    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17142        if self.soft_wrap_mode_override.is_some() {
17143            self.soft_wrap_mode_override.take();
17144        } else {
17145            let soft_wrap = match self.soft_wrap_mode(cx) {
17146                SoftWrap::GitDiff => return,
17147                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17148                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17149                    language_settings::SoftWrap::None
17150                }
17151            };
17152            self.soft_wrap_mode_override = Some(soft_wrap);
17153        }
17154        cx.notify();
17155    }
17156
17157    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17158        let Some(workspace) = self.workspace() else {
17159            return;
17160        };
17161        let fs = workspace.read(cx).app_state().fs.clone();
17162        let current_show = TabBarSettings::get_global(cx).show;
17163        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17164            setting.show = Some(!current_show);
17165        });
17166    }
17167
17168    pub fn toggle_indent_guides(
17169        &mut self,
17170        _: &ToggleIndentGuides,
17171        _: &mut Window,
17172        cx: &mut Context<Self>,
17173    ) {
17174        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17175            self.buffer
17176                .read(cx)
17177                .language_settings(cx)
17178                .indent_guides
17179                .enabled
17180        });
17181        self.show_indent_guides = Some(!currently_enabled);
17182        cx.notify();
17183    }
17184
17185    fn should_show_indent_guides(&self) -> Option<bool> {
17186        self.show_indent_guides
17187    }
17188
17189    pub fn toggle_line_numbers(
17190        &mut self,
17191        _: &ToggleLineNumbers,
17192        _: &mut Window,
17193        cx: &mut Context<Self>,
17194    ) {
17195        let mut editor_settings = EditorSettings::get_global(cx).clone();
17196        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17197        EditorSettings::override_global(editor_settings, cx);
17198    }
17199
17200    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17201        if let Some(show_line_numbers) = self.show_line_numbers {
17202            return show_line_numbers;
17203        }
17204        EditorSettings::get_global(cx).gutter.line_numbers
17205    }
17206
17207    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17208        self.use_relative_line_numbers
17209            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17210    }
17211
17212    pub fn toggle_relative_line_numbers(
17213        &mut self,
17214        _: &ToggleRelativeLineNumbers,
17215        _: &mut Window,
17216        cx: &mut Context<Self>,
17217    ) {
17218        let is_relative = self.should_use_relative_line_numbers(cx);
17219        self.set_relative_line_number(Some(!is_relative), cx)
17220    }
17221
17222    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17223        self.use_relative_line_numbers = is_relative;
17224        cx.notify();
17225    }
17226
17227    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17228        self.show_gutter = show_gutter;
17229        cx.notify();
17230    }
17231
17232    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17233        self.show_scrollbars = ScrollbarAxes {
17234            horizontal: show,
17235            vertical: show,
17236        };
17237        cx.notify();
17238    }
17239
17240    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17241        self.show_scrollbars.vertical = show;
17242        cx.notify();
17243    }
17244
17245    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17246        self.show_scrollbars.horizontal = show;
17247        cx.notify();
17248    }
17249
17250    pub fn set_minimap_visibility(
17251        &mut self,
17252        minimap_visibility: MinimapVisibility,
17253        window: &mut Window,
17254        cx: &mut Context<Self>,
17255    ) {
17256        if self.minimap_visibility != minimap_visibility {
17257            if minimap_visibility.visible() && self.minimap.is_none() {
17258                let minimap_settings = EditorSettings::get_global(cx).minimap;
17259                self.minimap =
17260                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17261            }
17262            self.minimap_visibility = minimap_visibility;
17263            cx.notify();
17264        }
17265    }
17266
17267    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17268        self.set_show_scrollbars(false, cx);
17269        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17270    }
17271
17272    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17273        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17274    }
17275
17276    /// Normally the text in full mode and auto height editors is padded on the
17277    /// left side by roughly half a character width for improved hit testing.
17278    ///
17279    /// Use this method to disable this for cases where this is not wanted (e.g.
17280    /// if you want to align the editor text with some other text above or below)
17281    /// or if you want to add this padding to single-line editors.
17282    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17283        self.offset_content = offset_content;
17284        cx.notify();
17285    }
17286
17287    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17288        self.show_line_numbers = Some(show_line_numbers);
17289        cx.notify();
17290    }
17291
17292    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17293        self.disable_expand_excerpt_buttons = true;
17294        cx.notify();
17295    }
17296
17297    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17298        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17299        cx.notify();
17300    }
17301
17302    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17303        self.show_code_actions = Some(show_code_actions);
17304        cx.notify();
17305    }
17306
17307    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17308        self.show_runnables = Some(show_runnables);
17309        cx.notify();
17310    }
17311
17312    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17313        self.show_breakpoints = Some(show_breakpoints);
17314        cx.notify();
17315    }
17316
17317    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17318        if self.display_map.read(cx).masked != masked {
17319            self.display_map.update(cx, |map, _| map.masked = masked);
17320        }
17321        cx.notify()
17322    }
17323
17324    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17325        self.show_wrap_guides = Some(show_wrap_guides);
17326        cx.notify();
17327    }
17328
17329    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17330        self.show_indent_guides = Some(show_indent_guides);
17331        cx.notify();
17332    }
17333
17334    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17335        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17336            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17337                if let Some(dir) = file.abs_path(cx).parent() {
17338                    return Some(dir.to_owned());
17339                }
17340            }
17341
17342            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17343                return Some(project_path.path.to_path_buf());
17344            }
17345        }
17346
17347        None
17348    }
17349
17350    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17351        self.active_excerpt(cx)?
17352            .1
17353            .read(cx)
17354            .file()
17355            .and_then(|f| f.as_local())
17356    }
17357
17358    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17359        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17360            let buffer = buffer.read(cx);
17361            if let Some(project_path) = buffer.project_path(cx) {
17362                let project = self.project.as_ref()?.read(cx);
17363                project.absolute_path(&project_path, cx)
17364            } else {
17365                buffer
17366                    .file()
17367                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17368            }
17369        })
17370    }
17371
17372    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17373        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17374            let project_path = buffer.read(cx).project_path(cx)?;
17375            let project = self.project.as_ref()?.read(cx);
17376            let entry = project.entry_for_path(&project_path, cx)?;
17377            let path = entry.path.to_path_buf();
17378            Some(path)
17379        })
17380    }
17381
17382    pub fn reveal_in_finder(
17383        &mut self,
17384        _: &RevealInFileManager,
17385        _window: &mut Window,
17386        cx: &mut Context<Self>,
17387    ) {
17388        if let Some(target) = self.target_file(cx) {
17389            cx.reveal_path(&target.abs_path(cx));
17390        }
17391    }
17392
17393    pub fn copy_path(
17394        &mut self,
17395        _: &zed_actions::workspace::CopyPath,
17396        _window: &mut Window,
17397        cx: &mut Context<Self>,
17398    ) {
17399        if let Some(path) = self.target_file_abs_path(cx) {
17400            if let Some(path) = path.to_str() {
17401                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17402            }
17403        }
17404    }
17405
17406    pub fn copy_relative_path(
17407        &mut self,
17408        _: &zed_actions::workspace::CopyRelativePath,
17409        _window: &mut Window,
17410        cx: &mut Context<Self>,
17411    ) {
17412        if let Some(path) = self.target_file_path(cx) {
17413            if let Some(path) = path.to_str() {
17414                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17415            }
17416        }
17417    }
17418
17419    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17420        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17421            buffer.read(cx).project_path(cx)
17422        } else {
17423            None
17424        }
17425    }
17426
17427    // Returns true if the editor handled a go-to-line request
17428    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17429        maybe!({
17430            let breakpoint_store = self.breakpoint_store.as_ref()?;
17431
17432            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17433            else {
17434                self.clear_row_highlights::<ActiveDebugLine>();
17435                return None;
17436            };
17437
17438            let position = active_stack_frame.position;
17439            let buffer_id = position.buffer_id?;
17440            let snapshot = self
17441                .project
17442                .as_ref()?
17443                .read(cx)
17444                .buffer_for_id(buffer_id, cx)?
17445                .read(cx)
17446                .snapshot();
17447
17448            let mut handled = false;
17449            for (id, ExcerptRange { context, .. }) in
17450                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17451            {
17452                if context.start.cmp(&position, &snapshot).is_ge()
17453                    || context.end.cmp(&position, &snapshot).is_lt()
17454                {
17455                    continue;
17456                }
17457                let snapshot = self.buffer.read(cx).snapshot(cx);
17458                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17459
17460                handled = true;
17461                self.clear_row_highlights::<ActiveDebugLine>();
17462
17463                self.go_to_line::<ActiveDebugLine>(
17464                    multibuffer_anchor,
17465                    Some(cx.theme().colors().editor_debugger_active_line_background),
17466                    window,
17467                    cx,
17468                );
17469
17470                cx.notify();
17471            }
17472
17473            handled.then_some(())
17474        })
17475        .is_some()
17476    }
17477
17478    pub fn copy_file_name_without_extension(
17479        &mut self,
17480        _: &CopyFileNameWithoutExtension,
17481        _: &mut Window,
17482        cx: &mut Context<Self>,
17483    ) {
17484        if let Some(file) = self.target_file(cx) {
17485            if let Some(file_stem) = file.path().file_stem() {
17486                if let Some(name) = file_stem.to_str() {
17487                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17488                }
17489            }
17490        }
17491    }
17492
17493    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17494        if let Some(file) = self.target_file(cx) {
17495            if let Some(file_name) = file.path().file_name() {
17496                if let Some(name) = file_name.to_str() {
17497                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17498                }
17499            }
17500        }
17501    }
17502
17503    pub fn toggle_git_blame(
17504        &mut self,
17505        _: &::git::Blame,
17506        window: &mut Window,
17507        cx: &mut Context<Self>,
17508    ) {
17509        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17510
17511        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17512            self.start_git_blame(true, window, cx);
17513        }
17514
17515        cx.notify();
17516    }
17517
17518    pub fn toggle_git_blame_inline(
17519        &mut self,
17520        _: &ToggleGitBlameInline,
17521        window: &mut Window,
17522        cx: &mut Context<Self>,
17523    ) {
17524        self.toggle_git_blame_inline_internal(true, window, cx);
17525        cx.notify();
17526    }
17527
17528    pub fn open_git_blame_commit(
17529        &mut self,
17530        _: &OpenGitBlameCommit,
17531        window: &mut Window,
17532        cx: &mut Context<Self>,
17533    ) {
17534        self.open_git_blame_commit_internal(window, cx);
17535    }
17536
17537    fn open_git_blame_commit_internal(
17538        &mut self,
17539        window: &mut Window,
17540        cx: &mut Context<Self>,
17541    ) -> Option<()> {
17542        let blame = self.blame.as_ref()?;
17543        let snapshot = self.snapshot(window, cx);
17544        let cursor = self.selections.newest::<Point>(cx).head();
17545        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17546        let blame_entry = blame
17547            .update(cx, |blame, cx| {
17548                blame
17549                    .blame_for_rows(
17550                        &[RowInfo {
17551                            buffer_id: Some(buffer.remote_id()),
17552                            buffer_row: Some(point.row),
17553                            ..Default::default()
17554                        }],
17555                        cx,
17556                    )
17557                    .next()
17558            })
17559            .flatten()?;
17560        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17561        let repo = blame.read(cx).repository(cx)?;
17562        let workspace = self.workspace()?.downgrade();
17563        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17564        None
17565    }
17566
17567    pub fn git_blame_inline_enabled(&self) -> bool {
17568        self.git_blame_inline_enabled
17569    }
17570
17571    pub fn toggle_selection_menu(
17572        &mut self,
17573        _: &ToggleSelectionMenu,
17574        _: &mut Window,
17575        cx: &mut Context<Self>,
17576    ) {
17577        self.show_selection_menu = self
17578            .show_selection_menu
17579            .map(|show_selections_menu| !show_selections_menu)
17580            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17581
17582        cx.notify();
17583    }
17584
17585    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17586        self.show_selection_menu
17587            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17588    }
17589
17590    fn start_git_blame(
17591        &mut self,
17592        user_triggered: bool,
17593        window: &mut Window,
17594        cx: &mut Context<Self>,
17595    ) {
17596        if let Some(project) = self.project.as_ref() {
17597            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17598                return;
17599            };
17600
17601            if buffer.read(cx).file().is_none() {
17602                return;
17603            }
17604
17605            let focused = self.focus_handle(cx).contains_focused(window, cx);
17606
17607            let project = project.clone();
17608            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17609            self.blame_subscription =
17610                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17611            self.blame = Some(blame);
17612        }
17613    }
17614
17615    fn toggle_git_blame_inline_internal(
17616        &mut self,
17617        user_triggered: bool,
17618        window: &mut Window,
17619        cx: &mut Context<Self>,
17620    ) {
17621        if self.git_blame_inline_enabled {
17622            self.git_blame_inline_enabled = false;
17623            self.show_git_blame_inline = false;
17624            self.show_git_blame_inline_delay_task.take();
17625        } else {
17626            self.git_blame_inline_enabled = true;
17627            self.start_git_blame_inline(user_triggered, window, cx);
17628        }
17629
17630        cx.notify();
17631    }
17632
17633    fn start_git_blame_inline(
17634        &mut self,
17635        user_triggered: bool,
17636        window: &mut Window,
17637        cx: &mut Context<Self>,
17638    ) {
17639        self.start_git_blame(user_triggered, window, cx);
17640
17641        if ProjectSettings::get_global(cx)
17642            .git
17643            .inline_blame_delay()
17644            .is_some()
17645        {
17646            self.start_inline_blame_timer(window, cx);
17647        } else {
17648            self.show_git_blame_inline = true
17649        }
17650    }
17651
17652    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17653        self.blame.as_ref()
17654    }
17655
17656    pub fn show_git_blame_gutter(&self) -> bool {
17657        self.show_git_blame_gutter
17658    }
17659
17660    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17661        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17662    }
17663
17664    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17665        self.show_git_blame_inline
17666            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17667            && !self.newest_selection_head_on_empty_line(cx)
17668            && self.has_blame_entries(cx)
17669    }
17670
17671    fn has_blame_entries(&self, cx: &App) -> bool {
17672        self.blame()
17673            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17674    }
17675
17676    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17677        let cursor_anchor = self.selections.newest_anchor().head();
17678
17679        let snapshot = self.buffer.read(cx).snapshot(cx);
17680        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17681
17682        snapshot.line_len(buffer_row) == 0
17683    }
17684
17685    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17686        let buffer_and_selection = maybe!({
17687            let selection = self.selections.newest::<Point>(cx);
17688            let selection_range = selection.range();
17689
17690            let multi_buffer = self.buffer().read(cx);
17691            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17692            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17693
17694            let (buffer, range, _) = if selection.reversed {
17695                buffer_ranges.first()
17696            } else {
17697                buffer_ranges.last()
17698            }?;
17699
17700            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17701                ..text::ToPoint::to_point(&range.end, &buffer).row;
17702            Some((
17703                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17704                selection,
17705            ))
17706        });
17707
17708        let Some((buffer, selection)) = buffer_and_selection else {
17709            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17710        };
17711
17712        let Some(project) = self.project.as_ref() else {
17713            return Task::ready(Err(anyhow!("editor does not have project")));
17714        };
17715
17716        project.update(cx, |project, cx| {
17717            project.get_permalink_to_line(&buffer, selection, cx)
17718        })
17719    }
17720
17721    pub fn copy_permalink_to_line(
17722        &mut self,
17723        _: &CopyPermalinkToLine,
17724        window: &mut Window,
17725        cx: &mut Context<Self>,
17726    ) {
17727        let permalink_task = self.get_permalink_to_line(cx);
17728        let workspace = self.workspace();
17729
17730        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17731            Ok(permalink) => {
17732                cx.update(|_, cx| {
17733                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17734                })
17735                .ok();
17736            }
17737            Err(err) => {
17738                let message = format!("Failed to copy permalink: {err}");
17739
17740                anyhow::Result::<()>::Err(err).log_err();
17741
17742                if let Some(workspace) = workspace {
17743                    workspace
17744                        .update_in(cx, |workspace, _, cx| {
17745                            struct CopyPermalinkToLine;
17746
17747                            workspace.show_toast(
17748                                Toast::new(
17749                                    NotificationId::unique::<CopyPermalinkToLine>(),
17750                                    message,
17751                                ),
17752                                cx,
17753                            )
17754                        })
17755                        .ok();
17756                }
17757            }
17758        })
17759        .detach();
17760    }
17761
17762    pub fn copy_file_location(
17763        &mut self,
17764        _: &CopyFileLocation,
17765        _: &mut Window,
17766        cx: &mut Context<Self>,
17767    ) {
17768        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17769        if let Some(file) = self.target_file(cx) {
17770            if let Some(path) = file.path().to_str() {
17771                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17772            }
17773        }
17774    }
17775
17776    pub fn open_permalink_to_line(
17777        &mut self,
17778        _: &OpenPermalinkToLine,
17779        window: &mut Window,
17780        cx: &mut Context<Self>,
17781    ) {
17782        let permalink_task = self.get_permalink_to_line(cx);
17783        let workspace = self.workspace();
17784
17785        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17786            Ok(permalink) => {
17787                cx.update(|_, cx| {
17788                    cx.open_url(permalink.as_ref());
17789                })
17790                .ok();
17791            }
17792            Err(err) => {
17793                let message = format!("Failed to open permalink: {err}");
17794
17795                anyhow::Result::<()>::Err(err).log_err();
17796
17797                if let Some(workspace) = workspace {
17798                    workspace
17799                        .update(cx, |workspace, cx| {
17800                            struct OpenPermalinkToLine;
17801
17802                            workspace.show_toast(
17803                                Toast::new(
17804                                    NotificationId::unique::<OpenPermalinkToLine>(),
17805                                    message,
17806                                ),
17807                                cx,
17808                            )
17809                        })
17810                        .ok();
17811                }
17812            }
17813        })
17814        .detach();
17815    }
17816
17817    pub fn insert_uuid_v4(
17818        &mut self,
17819        _: &InsertUuidV4,
17820        window: &mut Window,
17821        cx: &mut Context<Self>,
17822    ) {
17823        self.insert_uuid(UuidVersion::V4, window, cx);
17824    }
17825
17826    pub fn insert_uuid_v7(
17827        &mut self,
17828        _: &InsertUuidV7,
17829        window: &mut Window,
17830        cx: &mut Context<Self>,
17831    ) {
17832        self.insert_uuid(UuidVersion::V7, window, cx);
17833    }
17834
17835    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17836        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17837        self.transact(window, cx, |this, window, cx| {
17838            let edits = this
17839                .selections
17840                .all::<Point>(cx)
17841                .into_iter()
17842                .map(|selection| {
17843                    let uuid = match version {
17844                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17845                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17846                    };
17847
17848                    (selection.range(), uuid.to_string())
17849                });
17850            this.edit(edits, cx);
17851            this.refresh_inline_completion(true, false, window, cx);
17852        });
17853    }
17854
17855    pub fn open_selections_in_multibuffer(
17856        &mut self,
17857        _: &OpenSelectionsInMultibuffer,
17858        window: &mut Window,
17859        cx: &mut Context<Self>,
17860    ) {
17861        let multibuffer = self.buffer.read(cx);
17862
17863        let Some(buffer) = multibuffer.as_singleton() else {
17864            return;
17865        };
17866
17867        let Some(workspace) = self.workspace() else {
17868            return;
17869        };
17870
17871        let locations = self
17872            .selections
17873            .disjoint_anchors()
17874            .iter()
17875            .map(|range| Location {
17876                buffer: buffer.clone(),
17877                range: range.start.text_anchor..range.end.text_anchor,
17878            })
17879            .collect::<Vec<_>>();
17880
17881        let title = multibuffer.title(cx).to_string();
17882
17883        cx.spawn_in(window, async move |_, cx| {
17884            workspace.update_in(cx, |workspace, window, cx| {
17885                Self::open_locations_in_multibuffer(
17886                    workspace,
17887                    locations,
17888                    format!("Selections for '{title}'"),
17889                    false,
17890                    MultibufferSelectionMode::All,
17891                    window,
17892                    cx,
17893                );
17894            })
17895        })
17896        .detach();
17897    }
17898
17899    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17900    /// last highlight added will be used.
17901    ///
17902    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17903    pub fn highlight_rows<T: 'static>(
17904        &mut self,
17905        range: Range<Anchor>,
17906        color: Hsla,
17907        options: RowHighlightOptions,
17908        cx: &mut Context<Self>,
17909    ) {
17910        let snapshot = self.buffer().read(cx).snapshot(cx);
17911        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17912        let ix = row_highlights.binary_search_by(|highlight| {
17913            Ordering::Equal
17914                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17915                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17916        });
17917
17918        if let Err(mut ix) = ix {
17919            let index = post_inc(&mut self.highlight_order);
17920
17921            // If this range intersects with the preceding highlight, then merge it with
17922            // the preceding highlight. Otherwise insert a new highlight.
17923            let mut merged = false;
17924            if ix > 0 {
17925                let prev_highlight = &mut row_highlights[ix - 1];
17926                if prev_highlight
17927                    .range
17928                    .end
17929                    .cmp(&range.start, &snapshot)
17930                    .is_ge()
17931                {
17932                    ix -= 1;
17933                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17934                        prev_highlight.range.end = range.end;
17935                    }
17936                    merged = true;
17937                    prev_highlight.index = index;
17938                    prev_highlight.color = color;
17939                    prev_highlight.options = options;
17940                }
17941            }
17942
17943            if !merged {
17944                row_highlights.insert(
17945                    ix,
17946                    RowHighlight {
17947                        range: range.clone(),
17948                        index,
17949                        color,
17950                        options,
17951                        type_id: TypeId::of::<T>(),
17952                    },
17953                );
17954            }
17955
17956            // If any of the following highlights intersect with this one, merge them.
17957            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17958                let highlight = &row_highlights[ix];
17959                if next_highlight
17960                    .range
17961                    .start
17962                    .cmp(&highlight.range.end, &snapshot)
17963                    .is_le()
17964                {
17965                    if next_highlight
17966                        .range
17967                        .end
17968                        .cmp(&highlight.range.end, &snapshot)
17969                        .is_gt()
17970                    {
17971                        row_highlights[ix].range.end = next_highlight.range.end;
17972                    }
17973                    row_highlights.remove(ix + 1);
17974                } else {
17975                    break;
17976                }
17977            }
17978        }
17979    }
17980
17981    /// Remove any highlighted row ranges of the given type that intersect the
17982    /// given ranges.
17983    pub fn remove_highlighted_rows<T: 'static>(
17984        &mut self,
17985        ranges_to_remove: Vec<Range<Anchor>>,
17986        cx: &mut Context<Self>,
17987    ) {
17988        let snapshot = self.buffer().read(cx).snapshot(cx);
17989        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17990        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17991        row_highlights.retain(|highlight| {
17992            while let Some(range_to_remove) = ranges_to_remove.peek() {
17993                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17994                    Ordering::Less | Ordering::Equal => {
17995                        ranges_to_remove.next();
17996                    }
17997                    Ordering::Greater => {
17998                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17999                            Ordering::Less | Ordering::Equal => {
18000                                return false;
18001                            }
18002                            Ordering::Greater => break,
18003                        }
18004                    }
18005                }
18006            }
18007
18008            true
18009        })
18010    }
18011
18012    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18013    pub fn clear_row_highlights<T: 'static>(&mut self) {
18014        self.highlighted_rows.remove(&TypeId::of::<T>());
18015    }
18016
18017    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18018    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18019        self.highlighted_rows
18020            .get(&TypeId::of::<T>())
18021            .map_or(&[] as &[_], |vec| vec.as_slice())
18022            .iter()
18023            .map(|highlight| (highlight.range.clone(), highlight.color))
18024    }
18025
18026    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18027    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18028    /// Allows to ignore certain kinds of highlights.
18029    pub fn highlighted_display_rows(
18030        &self,
18031        window: &mut Window,
18032        cx: &mut App,
18033    ) -> BTreeMap<DisplayRow, LineHighlight> {
18034        let snapshot = self.snapshot(window, cx);
18035        let mut used_highlight_orders = HashMap::default();
18036        self.highlighted_rows
18037            .iter()
18038            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18039            .fold(
18040                BTreeMap::<DisplayRow, LineHighlight>::new(),
18041                |mut unique_rows, highlight| {
18042                    let start = highlight.range.start.to_display_point(&snapshot);
18043                    let end = highlight.range.end.to_display_point(&snapshot);
18044                    let start_row = start.row().0;
18045                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18046                        && end.column() == 0
18047                    {
18048                        end.row().0.saturating_sub(1)
18049                    } else {
18050                        end.row().0
18051                    };
18052                    for row in start_row..=end_row {
18053                        let used_index =
18054                            used_highlight_orders.entry(row).or_insert(highlight.index);
18055                        if highlight.index >= *used_index {
18056                            *used_index = highlight.index;
18057                            unique_rows.insert(
18058                                DisplayRow(row),
18059                                LineHighlight {
18060                                    include_gutter: highlight.options.include_gutter,
18061                                    border: None,
18062                                    background: highlight.color.into(),
18063                                    type_id: Some(highlight.type_id),
18064                                },
18065                            );
18066                        }
18067                    }
18068                    unique_rows
18069                },
18070            )
18071    }
18072
18073    pub fn highlighted_display_row_for_autoscroll(
18074        &self,
18075        snapshot: &DisplaySnapshot,
18076    ) -> Option<DisplayRow> {
18077        self.highlighted_rows
18078            .values()
18079            .flat_map(|highlighted_rows| highlighted_rows.iter())
18080            .filter_map(|highlight| {
18081                if highlight.options.autoscroll {
18082                    Some(highlight.range.start.to_display_point(snapshot).row())
18083                } else {
18084                    None
18085                }
18086            })
18087            .min()
18088    }
18089
18090    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18091        self.highlight_background::<SearchWithinRange>(
18092            ranges,
18093            |colors| colors.editor_document_highlight_read_background,
18094            cx,
18095        )
18096    }
18097
18098    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18099        self.breadcrumb_header = Some(new_header);
18100    }
18101
18102    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18103        self.clear_background_highlights::<SearchWithinRange>(cx);
18104    }
18105
18106    pub fn highlight_background<T: 'static>(
18107        &mut self,
18108        ranges: &[Range<Anchor>],
18109        color_fetcher: fn(&ThemeColors) -> Hsla,
18110        cx: &mut Context<Self>,
18111    ) {
18112        self.background_highlights
18113            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18114        self.scrollbar_marker_state.dirty = true;
18115        cx.notify();
18116    }
18117
18118    pub fn clear_background_highlights<T: 'static>(
18119        &mut self,
18120        cx: &mut Context<Self>,
18121    ) -> Option<BackgroundHighlight> {
18122        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18123        if !text_highlights.1.is_empty() {
18124            self.scrollbar_marker_state.dirty = true;
18125            cx.notify();
18126        }
18127        Some(text_highlights)
18128    }
18129
18130    pub fn highlight_gutter<T: 'static>(
18131        &mut self,
18132        ranges: &[Range<Anchor>],
18133        color_fetcher: fn(&App) -> Hsla,
18134        cx: &mut Context<Self>,
18135    ) {
18136        self.gutter_highlights
18137            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18138        cx.notify();
18139    }
18140
18141    pub fn clear_gutter_highlights<T: 'static>(
18142        &mut self,
18143        cx: &mut Context<Self>,
18144    ) -> Option<GutterHighlight> {
18145        cx.notify();
18146        self.gutter_highlights.remove(&TypeId::of::<T>())
18147    }
18148
18149    #[cfg(feature = "test-support")]
18150    pub fn all_text_background_highlights(
18151        &self,
18152        window: &mut Window,
18153        cx: &mut Context<Self>,
18154    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18155        let snapshot = self.snapshot(window, cx);
18156        let buffer = &snapshot.buffer_snapshot;
18157        let start = buffer.anchor_before(0);
18158        let end = buffer.anchor_after(buffer.len());
18159        let theme = cx.theme().colors();
18160        self.background_highlights_in_range(start..end, &snapshot, theme)
18161    }
18162
18163    #[cfg(feature = "test-support")]
18164    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18165        let snapshot = self.buffer().read(cx).snapshot(cx);
18166
18167        let highlights = self
18168            .background_highlights
18169            .get(&TypeId::of::<items::BufferSearchHighlights>());
18170
18171        if let Some((_color, ranges)) = highlights {
18172            ranges
18173                .iter()
18174                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18175                .collect_vec()
18176        } else {
18177            vec![]
18178        }
18179    }
18180
18181    fn document_highlights_for_position<'a>(
18182        &'a self,
18183        position: Anchor,
18184        buffer: &'a MultiBufferSnapshot,
18185    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18186        let read_highlights = self
18187            .background_highlights
18188            .get(&TypeId::of::<DocumentHighlightRead>())
18189            .map(|h| &h.1);
18190        let write_highlights = self
18191            .background_highlights
18192            .get(&TypeId::of::<DocumentHighlightWrite>())
18193            .map(|h| &h.1);
18194        let left_position = position.bias_left(buffer);
18195        let right_position = position.bias_right(buffer);
18196        read_highlights
18197            .into_iter()
18198            .chain(write_highlights)
18199            .flat_map(move |ranges| {
18200                let start_ix = match ranges.binary_search_by(|probe| {
18201                    let cmp = probe.end.cmp(&left_position, buffer);
18202                    if cmp.is_ge() {
18203                        Ordering::Greater
18204                    } else {
18205                        Ordering::Less
18206                    }
18207                }) {
18208                    Ok(i) | Err(i) => i,
18209                };
18210
18211                ranges[start_ix..]
18212                    .iter()
18213                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18214            })
18215    }
18216
18217    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18218        self.background_highlights
18219            .get(&TypeId::of::<T>())
18220            .map_or(false, |(_, highlights)| !highlights.is_empty())
18221    }
18222
18223    pub fn background_highlights_in_range(
18224        &self,
18225        search_range: Range<Anchor>,
18226        display_snapshot: &DisplaySnapshot,
18227        theme: &ThemeColors,
18228    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18229        let mut results = Vec::new();
18230        for (color_fetcher, ranges) in self.background_highlights.values() {
18231            let color = color_fetcher(theme);
18232            let start_ix = match ranges.binary_search_by(|probe| {
18233                let cmp = probe
18234                    .end
18235                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18236                if cmp.is_gt() {
18237                    Ordering::Greater
18238                } else {
18239                    Ordering::Less
18240                }
18241            }) {
18242                Ok(i) | Err(i) => i,
18243            };
18244            for range in &ranges[start_ix..] {
18245                if range
18246                    .start
18247                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18248                    .is_ge()
18249                {
18250                    break;
18251                }
18252
18253                let start = range.start.to_display_point(display_snapshot);
18254                let end = range.end.to_display_point(display_snapshot);
18255                results.push((start..end, color))
18256            }
18257        }
18258        results
18259    }
18260
18261    pub fn background_highlight_row_ranges<T: 'static>(
18262        &self,
18263        search_range: Range<Anchor>,
18264        display_snapshot: &DisplaySnapshot,
18265        count: usize,
18266    ) -> Vec<RangeInclusive<DisplayPoint>> {
18267        let mut results = Vec::new();
18268        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18269            return vec![];
18270        };
18271
18272        let start_ix = match ranges.binary_search_by(|probe| {
18273            let cmp = probe
18274                .end
18275                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18276            if cmp.is_gt() {
18277                Ordering::Greater
18278            } else {
18279                Ordering::Less
18280            }
18281        }) {
18282            Ok(i) | Err(i) => i,
18283        };
18284        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18285            if let (Some(start_display), Some(end_display)) = (start, end) {
18286                results.push(
18287                    start_display.to_display_point(display_snapshot)
18288                        ..=end_display.to_display_point(display_snapshot),
18289                );
18290            }
18291        };
18292        let mut start_row: Option<Point> = None;
18293        let mut end_row: Option<Point> = None;
18294        if ranges.len() > count {
18295            return Vec::new();
18296        }
18297        for range in &ranges[start_ix..] {
18298            if range
18299                .start
18300                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18301                .is_ge()
18302            {
18303                break;
18304            }
18305            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18306            if let Some(current_row) = &end_row {
18307                if end.row == current_row.row {
18308                    continue;
18309                }
18310            }
18311            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18312            if start_row.is_none() {
18313                assert_eq!(end_row, None);
18314                start_row = Some(start);
18315                end_row = Some(end);
18316                continue;
18317            }
18318            if let Some(current_end) = end_row.as_mut() {
18319                if start.row > current_end.row + 1 {
18320                    push_region(start_row, end_row);
18321                    start_row = Some(start);
18322                    end_row = Some(end);
18323                } else {
18324                    // Merge two hunks.
18325                    *current_end = end;
18326                }
18327            } else {
18328                unreachable!();
18329            }
18330        }
18331        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18332        push_region(start_row, end_row);
18333        results
18334    }
18335
18336    pub fn gutter_highlights_in_range(
18337        &self,
18338        search_range: Range<Anchor>,
18339        display_snapshot: &DisplaySnapshot,
18340        cx: &App,
18341    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18342        let mut results = Vec::new();
18343        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18344            let color = color_fetcher(cx);
18345            let start_ix = match ranges.binary_search_by(|probe| {
18346                let cmp = probe
18347                    .end
18348                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18349                if cmp.is_gt() {
18350                    Ordering::Greater
18351                } else {
18352                    Ordering::Less
18353                }
18354            }) {
18355                Ok(i) | Err(i) => i,
18356            };
18357            for range in &ranges[start_ix..] {
18358                if range
18359                    .start
18360                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18361                    .is_ge()
18362                {
18363                    break;
18364                }
18365
18366                let start = range.start.to_display_point(display_snapshot);
18367                let end = range.end.to_display_point(display_snapshot);
18368                results.push((start..end, color))
18369            }
18370        }
18371        results
18372    }
18373
18374    /// Get the text ranges corresponding to the redaction query
18375    pub fn redacted_ranges(
18376        &self,
18377        search_range: Range<Anchor>,
18378        display_snapshot: &DisplaySnapshot,
18379        cx: &App,
18380    ) -> Vec<Range<DisplayPoint>> {
18381        display_snapshot
18382            .buffer_snapshot
18383            .redacted_ranges(search_range, |file| {
18384                if let Some(file) = file {
18385                    file.is_private()
18386                        && EditorSettings::get(
18387                            Some(SettingsLocation {
18388                                worktree_id: file.worktree_id(cx),
18389                                path: file.path().as_ref(),
18390                            }),
18391                            cx,
18392                        )
18393                        .redact_private_values
18394                } else {
18395                    false
18396                }
18397            })
18398            .map(|range| {
18399                range.start.to_display_point(display_snapshot)
18400                    ..range.end.to_display_point(display_snapshot)
18401            })
18402            .collect()
18403    }
18404
18405    pub fn highlight_text<T: 'static>(
18406        &mut self,
18407        ranges: Vec<Range<Anchor>>,
18408        style: HighlightStyle,
18409        cx: &mut Context<Self>,
18410    ) {
18411        self.display_map.update(cx, |map, _| {
18412            map.highlight_text(TypeId::of::<T>(), ranges, style)
18413        });
18414        cx.notify();
18415    }
18416
18417    pub(crate) fn highlight_inlays<T: 'static>(
18418        &mut self,
18419        highlights: Vec<InlayHighlight>,
18420        style: HighlightStyle,
18421        cx: &mut Context<Self>,
18422    ) {
18423        self.display_map.update(cx, |map, _| {
18424            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18425        });
18426        cx.notify();
18427    }
18428
18429    pub fn text_highlights<'a, T: 'static>(
18430        &'a self,
18431        cx: &'a App,
18432    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18433        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18434    }
18435
18436    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18437        let cleared = self
18438            .display_map
18439            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18440        if cleared {
18441            cx.notify();
18442        }
18443    }
18444
18445    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18446        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18447            && self.focus_handle.is_focused(window)
18448    }
18449
18450    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18451        self.show_cursor_when_unfocused = is_enabled;
18452        cx.notify();
18453    }
18454
18455    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18456        cx.notify();
18457    }
18458
18459    fn on_debug_session_event(
18460        &mut self,
18461        _session: Entity<Session>,
18462        event: &SessionEvent,
18463        cx: &mut Context<Self>,
18464    ) {
18465        match event {
18466            SessionEvent::InvalidateInlineValue => {
18467                self.refresh_inline_values(cx);
18468            }
18469            _ => {}
18470        }
18471    }
18472
18473    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18474        let Some(project) = self.project.clone() else {
18475            return;
18476        };
18477
18478        if !self.inline_value_cache.enabled {
18479            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18480            self.splice_inlays(&inlays, Vec::new(), cx);
18481            return;
18482        }
18483
18484        let current_execution_position = self
18485            .highlighted_rows
18486            .get(&TypeId::of::<ActiveDebugLine>())
18487            .and_then(|lines| lines.last().map(|line| line.range.start));
18488
18489        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18490            let inline_values = editor
18491                .update(cx, |editor, cx| {
18492                    let Some(current_execution_position) = current_execution_position else {
18493                        return Some(Task::ready(Ok(Vec::new())));
18494                    };
18495
18496                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18497                        let snapshot = buffer.snapshot(cx);
18498
18499                        let excerpt = snapshot.excerpt_containing(
18500                            current_execution_position..current_execution_position,
18501                        )?;
18502
18503                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18504                    })?;
18505
18506                    let range =
18507                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18508
18509                    project.inline_values(buffer, range, cx)
18510                })
18511                .ok()
18512                .flatten()?
18513                .await
18514                .context("refreshing debugger inlays")
18515                .log_err()?;
18516
18517            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18518
18519            for (buffer_id, inline_value) in inline_values
18520                .into_iter()
18521                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18522            {
18523                buffer_inline_values
18524                    .entry(buffer_id)
18525                    .or_default()
18526                    .push(inline_value);
18527            }
18528
18529            editor
18530                .update(cx, |editor, cx| {
18531                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18532                    let mut new_inlays = Vec::default();
18533
18534                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18535                        let buffer_id = buffer_snapshot.remote_id();
18536                        buffer_inline_values
18537                            .get(&buffer_id)
18538                            .into_iter()
18539                            .flatten()
18540                            .for_each(|hint| {
18541                                let inlay = Inlay::debugger_hint(
18542                                    post_inc(&mut editor.next_inlay_id),
18543                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18544                                    hint.text(),
18545                                );
18546
18547                                new_inlays.push(inlay);
18548                            });
18549                    }
18550
18551                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18552                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18553
18554                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18555                })
18556                .ok()?;
18557            Some(())
18558        });
18559    }
18560
18561    fn on_buffer_event(
18562        &mut self,
18563        multibuffer: &Entity<MultiBuffer>,
18564        event: &multi_buffer::Event,
18565        window: &mut Window,
18566        cx: &mut Context<Self>,
18567    ) {
18568        match event {
18569            multi_buffer::Event::Edited {
18570                singleton_buffer_edited,
18571                edited_buffer: buffer_edited,
18572            } => {
18573                self.scrollbar_marker_state.dirty = true;
18574                self.active_indent_guides_state.dirty = true;
18575                self.refresh_active_diagnostics(cx);
18576                self.refresh_code_actions(window, cx);
18577                self.refresh_selected_text_highlights(true, window, cx);
18578                refresh_matching_bracket_highlights(self, window, cx);
18579                if self.has_active_inline_completion() {
18580                    self.update_visible_inline_completion(window, cx);
18581                }
18582                if let Some(buffer) = buffer_edited {
18583                    let buffer_id = buffer.read(cx).remote_id();
18584                    if !self.registered_buffers.contains_key(&buffer_id) {
18585                        if let Some(project) = self.project.as_ref() {
18586                            project.update(cx, |project, cx| {
18587                                self.registered_buffers.insert(
18588                                    buffer_id,
18589                                    project.register_buffer_with_language_servers(&buffer, cx),
18590                                );
18591                            })
18592                        }
18593                    }
18594                }
18595                cx.emit(EditorEvent::BufferEdited);
18596                cx.emit(SearchEvent::MatchesInvalidated);
18597                if *singleton_buffer_edited {
18598                    if let Some(project) = &self.project {
18599                        #[allow(clippy::mutable_key_type)]
18600                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18601                            multibuffer
18602                                .all_buffers()
18603                                .into_iter()
18604                                .filter_map(|buffer| {
18605                                    buffer.update(cx, |buffer, cx| {
18606                                        let language = buffer.language()?;
18607                                        let should_discard = project.update(cx, |project, cx| {
18608                                            project.is_local()
18609                                                && !project.has_language_servers_for(buffer, cx)
18610                                        });
18611                                        should_discard.not().then_some(language.clone())
18612                                    })
18613                                })
18614                                .collect::<HashSet<_>>()
18615                        });
18616                        if !languages_affected.is_empty() {
18617                            self.refresh_inlay_hints(
18618                                InlayHintRefreshReason::BufferEdited(languages_affected),
18619                                cx,
18620                            );
18621                        }
18622                    }
18623                }
18624
18625                let Some(project) = &self.project else { return };
18626                let (telemetry, is_via_ssh) = {
18627                    let project = project.read(cx);
18628                    let telemetry = project.client().telemetry().clone();
18629                    let is_via_ssh = project.is_via_ssh();
18630                    (telemetry, is_via_ssh)
18631                };
18632                refresh_linked_ranges(self, window, cx);
18633                telemetry.log_edit_event("editor", is_via_ssh);
18634            }
18635            multi_buffer::Event::ExcerptsAdded {
18636                buffer,
18637                predecessor,
18638                excerpts,
18639            } => {
18640                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18641                let buffer_id = buffer.read(cx).remote_id();
18642                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18643                    if let Some(project) = &self.project {
18644                        update_uncommitted_diff_for_buffer(
18645                            cx.entity(),
18646                            project,
18647                            [buffer.clone()],
18648                            self.buffer.clone(),
18649                            cx,
18650                        )
18651                        .detach();
18652                    }
18653                }
18654                cx.emit(EditorEvent::ExcerptsAdded {
18655                    buffer: buffer.clone(),
18656                    predecessor: *predecessor,
18657                    excerpts: excerpts.clone(),
18658                });
18659                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18660            }
18661            multi_buffer::Event::ExcerptsRemoved {
18662                ids,
18663                removed_buffer_ids,
18664            } => {
18665                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18666                let buffer = self.buffer.read(cx);
18667                self.registered_buffers
18668                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18669                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18670                cx.emit(EditorEvent::ExcerptsRemoved {
18671                    ids: ids.clone(),
18672                    removed_buffer_ids: removed_buffer_ids.clone(),
18673                })
18674            }
18675            multi_buffer::Event::ExcerptsEdited {
18676                excerpt_ids,
18677                buffer_ids,
18678            } => {
18679                self.display_map.update(cx, |map, cx| {
18680                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18681                });
18682                cx.emit(EditorEvent::ExcerptsEdited {
18683                    ids: excerpt_ids.clone(),
18684                })
18685            }
18686            multi_buffer::Event::ExcerptsExpanded { ids } => {
18687                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18688                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18689            }
18690            multi_buffer::Event::Reparsed(buffer_id) => {
18691                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18692                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18693
18694                cx.emit(EditorEvent::Reparsed(*buffer_id));
18695            }
18696            multi_buffer::Event::DiffHunksToggled => {
18697                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18698            }
18699            multi_buffer::Event::LanguageChanged(buffer_id) => {
18700                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18701                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18702                cx.emit(EditorEvent::Reparsed(*buffer_id));
18703                cx.notify();
18704            }
18705            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18706            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18707            multi_buffer::Event::FileHandleChanged
18708            | multi_buffer::Event::Reloaded
18709            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18710            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18711            multi_buffer::Event::DiagnosticsUpdated => {
18712                self.refresh_active_diagnostics(cx);
18713                self.refresh_inline_diagnostics(true, window, cx);
18714                self.scrollbar_marker_state.dirty = true;
18715                cx.notify();
18716            }
18717            _ => {}
18718        };
18719    }
18720
18721    pub fn start_temporary_diff_override(&mut self) {
18722        self.load_diff_task.take();
18723        self.temporary_diff_override = true;
18724    }
18725
18726    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18727        self.temporary_diff_override = false;
18728        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18729        self.buffer.update(cx, |buffer, cx| {
18730            buffer.set_all_diff_hunks_collapsed(cx);
18731        });
18732
18733        if let Some(project) = self.project.clone() {
18734            self.load_diff_task = Some(
18735                update_uncommitted_diff_for_buffer(
18736                    cx.entity(),
18737                    &project,
18738                    self.buffer.read(cx).all_buffers(),
18739                    self.buffer.clone(),
18740                    cx,
18741                )
18742                .shared(),
18743            );
18744        }
18745    }
18746
18747    fn on_display_map_changed(
18748        &mut self,
18749        _: Entity<DisplayMap>,
18750        _: &mut Window,
18751        cx: &mut Context<Self>,
18752    ) {
18753        cx.notify();
18754    }
18755
18756    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18757        let new_severity = if self.diagnostics_enabled() {
18758            EditorSettings::get_global(cx)
18759                .diagnostics_max_severity
18760                .unwrap_or(DiagnosticSeverity::Hint)
18761        } else {
18762            DiagnosticSeverity::Off
18763        };
18764        self.set_max_diagnostics_severity(new_severity, cx);
18765        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18766        self.update_edit_prediction_settings(cx);
18767        self.refresh_inline_completion(true, false, window, cx);
18768        self.refresh_inlay_hints(
18769            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18770                self.selections.newest_anchor().head(),
18771                &self.buffer.read(cx).snapshot(cx),
18772                cx,
18773            )),
18774            cx,
18775        );
18776
18777        let old_cursor_shape = self.cursor_shape;
18778
18779        {
18780            let editor_settings = EditorSettings::get_global(cx);
18781            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18782            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18783            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18784            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18785        }
18786
18787        if old_cursor_shape != self.cursor_shape {
18788            cx.emit(EditorEvent::CursorShapeChanged);
18789        }
18790
18791        let project_settings = ProjectSettings::get_global(cx);
18792        self.serialize_dirty_buffers =
18793            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18794
18795        if self.mode.is_full() {
18796            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18797            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18798            if self.show_inline_diagnostics != show_inline_diagnostics {
18799                self.show_inline_diagnostics = show_inline_diagnostics;
18800                self.refresh_inline_diagnostics(false, window, cx);
18801            }
18802
18803            if self.git_blame_inline_enabled != inline_blame_enabled {
18804                self.toggle_git_blame_inline_internal(false, window, cx);
18805            }
18806
18807            let minimap_settings = EditorSettings::get_global(cx).minimap;
18808            if self.minimap_visibility != MinimapVisibility::Disabled {
18809                if self.minimap_visibility.settings_visibility()
18810                    != minimap_settings.minimap_enabled()
18811                {
18812                    self.set_minimap_visibility(
18813                        MinimapVisibility::for_mode(self.mode(), cx),
18814                        window,
18815                        cx,
18816                    );
18817                } else if let Some(minimap_entity) = self.minimap.as_ref() {
18818                    minimap_entity.update(cx, |minimap_editor, cx| {
18819                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
18820                    })
18821                }
18822            }
18823        }
18824
18825        cx.notify();
18826    }
18827
18828    pub fn set_searchable(&mut self, searchable: bool) {
18829        self.searchable = searchable;
18830    }
18831
18832    pub fn searchable(&self) -> bool {
18833        self.searchable
18834    }
18835
18836    fn open_proposed_changes_editor(
18837        &mut self,
18838        _: &OpenProposedChangesEditor,
18839        window: &mut Window,
18840        cx: &mut Context<Self>,
18841    ) {
18842        let Some(workspace) = self.workspace() else {
18843            cx.propagate();
18844            return;
18845        };
18846
18847        let selections = self.selections.all::<usize>(cx);
18848        let multi_buffer = self.buffer.read(cx);
18849        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18850        let mut new_selections_by_buffer = HashMap::default();
18851        for selection in selections {
18852            for (buffer, range, _) in
18853                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18854            {
18855                let mut range = range.to_point(buffer);
18856                range.start.column = 0;
18857                range.end.column = buffer.line_len(range.end.row);
18858                new_selections_by_buffer
18859                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18860                    .or_insert(Vec::new())
18861                    .push(range)
18862            }
18863        }
18864
18865        let proposed_changes_buffers = new_selections_by_buffer
18866            .into_iter()
18867            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18868            .collect::<Vec<_>>();
18869        let proposed_changes_editor = cx.new(|cx| {
18870            ProposedChangesEditor::new(
18871                "Proposed changes",
18872                proposed_changes_buffers,
18873                self.project.clone(),
18874                window,
18875                cx,
18876            )
18877        });
18878
18879        window.defer(cx, move |window, cx| {
18880            workspace.update(cx, |workspace, cx| {
18881                workspace.active_pane().update(cx, |pane, cx| {
18882                    pane.add_item(
18883                        Box::new(proposed_changes_editor),
18884                        true,
18885                        true,
18886                        None,
18887                        window,
18888                        cx,
18889                    );
18890                });
18891            });
18892        });
18893    }
18894
18895    pub fn open_excerpts_in_split(
18896        &mut self,
18897        _: &OpenExcerptsSplit,
18898        window: &mut Window,
18899        cx: &mut Context<Self>,
18900    ) {
18901        self.open_excerpts_common(None, true, window, cx)
18902    }
18903
18904    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18905        self.open_excerpts_common(None, false, window, cx)
18906    }
18907
18908    fn open_excerpts_common(
18909        &mut self,
18910        jump_data: Option<JumpData>,
18911        split: bool,
18912        window: &mut Window,
18913        cx: &mut Context<Self>,
18914    ) {
18915        let Some(workspace) = self.workspace() else {
18916            cx.propagate();
18917            return;
18918        };
18919
18920        if self.buffer.read(cx).is_singleton() {
18921            cx.propagate();
18922            return;
18923        }
18924
18925        let mut new_selections_by_buffer = HashMap::default();
18926        match &jump_data {
18927            Some(JumpData::MultiBufferPoint {
18928                excerpt_id,
18929                position,
18930                anchor,
18931                line_offset_from_top,
18932            }) => {
18933                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18934                if let Some(buffer) = multi_buffer_snapshot
18935                    .buffer_id_for_excerpt(*excerpt_id)
18936                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18937                {
18938                    let buffer_snapshot = buffer.read(cx).snapshot();
18939                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18940                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18941                    } else {
18942                        buffer_snapshot.clip_point(*position, Bias::Left)
18943                    };
18944                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18945                    new_selections_by_buffer.insert(
18946                        buffer,
18947                        (
18948                            vec![jump_to_offset..jump_to_offset],
18949                            Some(*line_offset_from_top),
18950                        ),
18951                    );
18952                }
18953            }
18954            Some(JumpData::MultiBufferRow {
18955                row,
18956                line_offset_from_top,
18957            }) => {
18958                let point = MultiBufferPoint::new(row.0, 0);
18959                if let Some((buffer, buffer_point, _)) =
18960                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18961                {
18962                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18963                    new_selections_by_buffer
18964                        .entry(buffer)
18965                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18966                        .0
18967                        .push(buffer_offset..buffer_offset)
18968                }
18969            }
18970            None => {
18971                let selections = self.selections.all::<usize>(cx);
18972                let multi_buffer = self.buffer.read(cx);
18973                for selection in selections {
18974                    for (snapshot, range, _, anchor) in multi_buffer
18975                        .snapshot(cx)
18976                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18977                    {
18978                        if let Some(anchor) = anchor {
18979                            // selection is in a deleted hunk
18980                            let Some(buffer_id) = anchor.buffer_id else {
18981                                continue;
18982                            };
18983                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18984                                continue;
18985                            };
18986                            let offset = text::ToOffset::to_offset(
18987                                &anchor.text_anchor,
18988                                &buffer_handle.read(cx).snapshot(),
18989                            );
18990                            let range = offset..offset;
18991                            new_selections_by_buffer
18992                                .entry(buffer_handle)
18993                                .or_insert((Vec::new(), None))
18994                                .0
18995                                .push(range)
18996                        } else {
18997                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18998                            else {
18999                                continue;
19000                            };
19001                            new_selections_by_buffer
19002                                .entry(buffer_handle)
19003                                .or_insert((Vec::new(), None))
19004                                .0
19005                                .push(range)
19006                        }
19007                    }
19008                }
19009            }
19010        }
19011
19012        new_selections_by_buffer
19013            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19014
19015        if new_selections_by_buffer.is_empty() {
19016            return;
19017        }
19018
19019        // We defer the pane interaction because we ourselves are a workspace item
19020        // and activating a new item causes the pane to call a method on us reentrantly,
19021        // which panics if we're on the stack.
19022        window.defer(cx, move |window, cx| {
19023            workspace.update(cx, |workspace, cx| {
19024                let pane = if split {
19025                    workspace.adjacent_pane(window, cx)
19026                } else {
19027                    workspace.active_pane().clone()
19028                };
19029
19030                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19031                    let editor = buffer
19032                        .read(cx)
19033                        .file()
19034                        .is_none()
19035                        .then(|| {
19036                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19037                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19038                            // Instead, we try to activate the existing editor in the pane first.
19039                            let (editor, pane_item_index) =
19040                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19041                                    let editor = item.downcast::<Editor>()?;
19042                                    let singleton_buffer =
19043                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19044                                    if singleton_buffer == buffer {
19045                                        Some((editor, i))
19046                                    } else {
19047                                        None
19048                                    }
19049                                })?;
19050                            pane.update(cx, |pane, cx| {
19051                                pane.activate_item(pane_item_index, true, true, window, cx)
19052                            });
19053                            Some(editor)
19054                        })
19055                        .flatten()
19056                        .unwrap_or_else(|| {
19057                            workspace.open_project_item::<Self>(
19058                                pane.clone(),
19059                                buffer,
19060                                true,
19061                                true,
19062                                window,
19063                                cx,
19064                            )
19065                        });
19066
19067                    editor.update(cx, |editor, cx| {
19068                        let autoscroll = match scroll_offset {
19069                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19070                            None => Autoscroll::newest(),
19071                        };
19072                        let nav_history = editor.nav_history.take();
19073                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19074                            s.select_ranges(ranges);
19075                        });
19076                        editor.nav_history = nav_history;
19077                    });
19078                }
19079            })
19080        });
19081    }
19082
19083    // For now, don't allow opening excerpts in buffers that aren't backed by
19084    // regular project files.
19085    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19086        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19087    }
19088
19089    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19090        let snapshot = self.buffer.read(cx).read(cx);
19091        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19092        Some(
19093            ranges
19094                .iter()
19095                .map(move |range| {
19096                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19097                })
19098                .collect(),
19099        )
19100    }
19101
19102    fn selection_replacement_ranges(
19103        &self,
19104        range: Range<OffsetUtf16>,
19105        cx: &mut App,
19106    ) -> Vec<Range<OffsetUtf16>> {
19107        let selections = self.selections.all::<OffsetUtf16>(cx);
19108        let newest_selection = selections
19109            .iter()
19110            .max_by_key(|selection| selection.id)
19111            .unwrap();
19112        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19113        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19114        let snapshot = self.buffer.read(cx).read(cx);
19115        selections
19116            .into_iter()
19117            .map(|mut selection| {
19118                selection.start.0 =
19119                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19120                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19121                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19122                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19123            })
19124            .collect()
19125    }
19126
19127    fn report_editor_event(
19128        &self,
19129        event_type: &'static str,
19130        file_extension: Option<String>,
19131        cx: &App,
19132    ) {
19133        if cfg!(any(test, feature = "test-support")) {
19134            return;
19135        }
19136
19137        let Some(project) = &self.project else { return };
19138
19139        // If None, we are in a file without an extension
19140        let file = self
19141            .buffer
19142            .read(cx)
19143            .as_singleton()
19144            .and_then(|b| b.read(cx).file());
19145        let file_extension = file_extension.or(file
19146            .as_ref()
19147            .and_then(|file| Path::new(file.file_name(cx)).extension())
19148            .and_then(|e| e.to_str())
19149            .map(|a| a.to_string()));
19150
19151        let vim_mode = vim_enabled(cx);
19152
19153        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19154        let copilot_enabled = edit_predictions_provider
19155            == language::language_settings::EditPredictionProvider::Copilot;
19156        let copilot_enabled_for_language = self
19157            .buffer
19158            .read(cx)
19159            .language_settings(cx)
19160            .show_edit_predictions;
19161
19162        let project = project.read(cx);
19163        telemetry::event!(
19164            event_type,
19165            file_extension,
19166            vim_mode,
19167            copilot_enabled,
19168            copilot_enabled_for_language,
19169            edit_predictions_provider,
19170            is_via_ssh = project.is_via_ssh(),
19171        );
19172    }
19173
19174    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19175    /// with each line being an array of {text, highlight} objects.
19176    fn copy_highlight_json(
19177        &mut self,
19178        _: &CopyHighlightJson,
19179        window: &mut Window,
19180        cx: &mut Context<Self>,
19181    ) {
19182        #[derive(Serialize)]
19183        struct Chunk<'a> {
19184            text: String,
19185            highlight: Option<&'a str>,
19186        }
19187
19188        let snapshot = self.buffer.read(cx).snapshot(cx);
19189        let range = self
19190            .selected_text_range(false, window, cx)
19191            .and_then(|selection| {
19192                if selection.range.is_empty() {
19193                    None
19194                } else {
19195                    Some(selection.range)
19196                }
19197            })
19198            .unwrap_or_else(|| 0..snapshot.len());
19199
19200        let chunks = snapshot.chunks(range, true);
19201        let mut lines = Vec::new();
19202        let mut line: VecDeque<Chunk> = VecDeque::new();
19203
19204        let Some(style) = self.style.as_ref() else {
19205            return;
19206        };
19207
19208        for chunk in chunks {
19209            let highlight = chunk
19210                .syntax_highlight_id
19211                .and_then(|id| id.name(&style.syntax));
19212            let mut chunk_lines = chunk.text.split('\n').peekable();
19213            while let Some(text) = chunk_lines.next() {
19214                let mut merged_with_last_token = false;
19215                if let Some(last_token) = line.back_mut() {
19216                    if last_token.highlight == highlight {
19217                        last_token.text.push_str(text);
19218                        merged_with_last_token = true;
19219                    }
19220                }
19221
19222                if !merged_with_last_token {
19223                    line.push_back(Chunk {
19224                        text: text.into(),
19225                        highlight,
19226                    });
19227                }
19228
19229                if chunk_lines.peek().is_some() {
19230                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19231                        line.pop_front();
19232                    }
19233                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19234                        line.pop_back();
19235                    }
19236
19237                    lines.push(mem::take(&mut line));
19238                }
19239            }
19240        }
19241
19242        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19243            return;
19244        };
19245        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19246    }
19247
19248    pub fn open_context_menu(
19249        &mut self,
19250        _: &OpenContextMenu,
19251        window: &mut Window,
19252        cx: &mut Context<Self>,
19253    ) {
19254        self.request_autoscroll(Autoscroll::newest(), cx);
19255        let position = self.selections.newest_display(cx).start;
19256        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19257    }
19258
19259    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19260        &self.inlay_hint_cache
19261    }
19262
19263    pub fn replay_insert_event(
19264        &mut self,
19265        text: &str,
19266        relative_utf16_range: Option<Range<isize>>,
19267        window: &mut Window,
19268        cx: &mut Context<Self>,
19269    ) {
19270        if !self.input_enabled {
19271            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19272            return;
19273        }
19274        if let Some(relative_utf16_range) = relative_utf16_range {
19275            let selections = self.selections.all::<OffsetUtf16>(cx);
19276            self.change_selections(None, window, cx, |s| {
19277                let new_ranges = selections.into_iter().map(|range| {
19278                    let start = OffsetUtf16(
19279                        range
19280                            .head()
19281                            .0
19282                            .saturating_add_signed(relative_utf16_range.start),
19283                    );
19284                    let end = OffsetUtf16(
19285                        range
19286                            .head()
19287                            .0
19288                            .saturating_add_signed(relative_utf16_range.end),
19289                    );
19290                    start..end
19291                });
19292                s.select_ranges(new_ranges);
19293            });
19294        }
19295
19296        self.handle_input(text, window, cx);
19297    }
19298
19299    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19300        let Some(provider) = self.semantics_provider.as_ref() else {
19301            return false;
19302        };
19303
19304        let mut supports = false;
19305        self.buffer().update(cx, |this, cx| {
19306            this.for_each_buffer(|buffer| {
19307                supports |= provider.supports_inlay_hints(buffer, cx);
19308            });
19309        });
19310
19311        supports
19312    }
19313
19314    pub fn is_focused(&self, window: &Window) -> bool {
19315        self.focus_handle.is_focused(window)
19316    }
19317
19318    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19319        cx.emit(EditorEvent::Focused);
19320
19321        if let Some(descendant) = self
19322            .last_focused_descendant
19323            .take()
19324            .and_then(|descendant| descendant.upgrade())
19325        {
19326            window.focus(&descendant);
19327        } else {
19328            if let Some(blame) = self.blame.as_ref() {
19329                blame.update(cx, GitBlame::focus)
19330            }
19331
19332            self.blink_manager.update(cx, BlinkManager::enable);
19333            self.show_cursor_names(window, cx);
19334            self.buffer.update(cx, |buffer, cx| {
19335                buffer.finalize_last_transaction(cx);
19336                if self.leader_id.is_none() {
19337                    buffer.set_active_selections(
19338                        &self.selections.disjoint_anchors(),
19339                        self.selections.line_mode,
19340                        self.cursor_shape,
19341                        cx,
19342                    );
19343                }
19344            });
19345        }
19346    }
19347
19348    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19349        cx.emit(EditorEvent::FocusedIn)
19350    }
19351
19352    fn handle_focus_out(
19353        &mut self,
19354        event: FocusOutEvent,
19355        _window: &mut Window,
19356        cx: &mut Context<Self>,
19357    ) {
19358        if event.blurred != self.focus_handle {
19359            self.last_focused_descendant = Some(event.blurred);
19360        }
19361        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19362    }
19363
19364    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19365        self.blink_manager.update(cx, BlinkManager::disable);
19366        self.buffer
19367            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19368
19369        if let Some(blame) = self.blame.as_ref() {
19370            blame.update(cx, GitBlame::blur)
19371        }
19372        if !self.hover_state.focused(window, cx) {
19373            hide_hover(self, cx);
19374        }
19375        if !self
19376            .context_menu
19377            .borrow()
19378            .as_ref()
19379            .is_some_and(|context_menu| context_menu.focused(window, cx))
19380        {
19381            self.hide_context_menu(window, cx);
19382        }
19383        self.discard_inline_completion(false, cx);
19384        cx.emit(EditorEvent::Blurred);
19385        cx.notify();
19386    }
19387
19388    pub fn register_action<A: Action>(
19389        &mut self,
19390        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19391    ) -> Subscription {
19392        let id = self.next_editor_action_id.post_inc();
19393        let listener = Arc::new(listener);
19394        self.editor_actions.borrow_mut().insert(
19395            id,
19396            Box::new(move |window, _| {
19397                let listener = listener.clone();
19398                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19399                    let action = action.downcast_ref().unwrap();
19400                    if phase == DispatchPhase::Bubble {
19401                        listener(action, window, cx)
19402                    }
19403                })
19404            }),
19405        );
19406
19407        let editor_actions = self.editor_actions.clone();
19408        Subscription::new(move || {
19409            editor_actions.borrow_mut().remove(&id);
19410        })
19411    }
19412
19413    pub fn file_header_size(&self) -> u32 {
19414        FILE_HEADER_HEIGHT
19415    }
19416
19417    pub fn restore(
19418        &mut self,
19419        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19420        window: &mut Window,
19421        cx: &mut Context<Self>,
19422    ) {
19423        let workspace = self.workspace();
19424        let project = self.project.as_ref();
19425        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19426            let mut tasks = Vec::new();
19427            for (buffer_id, changes) in revert_changes {
19428                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19429                    buffer.update(cx, |buffer, cx| {
19430                        buffer.edit(
19431                            changes
19432                                .into_iter()
19433                                .map(|(range, text)| (range, text.to_string())),
19434                            None,
19435                            cx,
19436                        );
19437                    });
19438
19439                    if let Some(project) =
19440                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19441                    {
19442                        project.update(cx, |project, cx| {
19443                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19444                        })
19445                    }
19446                }
19447            }
19448            tasks
19449        });
19450        cx.spawn_in(window, async move |_, cx| {
19451            for (buffer, task) in save_tasks {
19452                let result = task.await;
19453                if result.is_err() {
19454                    let Some(path) = buffer
19455                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19456                        .ok()
19457                    else {
19458                        continue;
19459                    };
19460                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19461                        let Some(task) = cx
19462                            .update_window_entity(&workspace, |workspace, window, cx| {
19463                                workspace
19464                                    .open_path_preview(path, None, false, false, false, window, cx)
19465                            })
19466                            .ok()
19467                        else {
19468                            continue;
19469                        };
19470                        task.await.log_err();
19471                    }
19472                }
19473            }
19474        })
19475        .detach();
19476        self.change_selections(None, window, cx, |selections| selections.refresh());
19477    }
19478
19479    pub fn to_pixel_point(
19480        &self,
19481        source: multi_buffer::Anchor,
19482        editor_snapshot: &EditorSnapshot,
19483        window: &mut Window,
19484    ) -> Option<gpui::Point<Pixels>> {
19485        let source_point = source.to_display_point(editor_snapshot);
19486        self.display_to_pixel_point(source_point, editor_snapshot, window)
19487    }
19488
19489    pub fn display_to_pixel_point(
19490        &self,
19491        source: DisplayPoint,
19492        editor_snapshot: &EditorSnapshot,
19493        window: &mut Window,
19494    ) -> Option<gpui::Point<Pixels>> {
19495        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19496        let text_layout_details = self.text_layout_details(window);
19497        let scroll_top = text_layout_details
19498            .scroll_anchor
19499            .scroll_position(editor_snapshot)
19500            .y;
19501
19502        if source.row().as_f32() < scroll_top.floor() {
19503            return None;
19504        }
19505        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19506        let source_y = line_height * (source.row().as_f32() - scroll_top);
19507        Some(gpui::Point::new(source_x, source_y))
19508    }
19509
19510    pub fn has_visible_completions_menu(&self) -> bool {
19511        !self.edit_prediction_preview_is_active()
19512            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19513                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19514            })
19515    }
19516
19517    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19518        if self.mode.is_minimap() {
19519            return;
19520        }
19521        self.addons
19522            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19523    }
19524
19525    pub fn unregister_addon<T: Addon>(&mut self) {
19526        self.addons.remove(&std::any::TypeId::of::<T>());
19527    }
19528
19529    pub fn addon<T: Addon>(&self) -> Option<&T> {
19530        let type_id = std::any::TypeId::of::<T>();
19531        self.addons
19532            .get(&type_id)
19533            .and_then(|item| item.to_any().downcast_ref::<T>())
19534    }
19535
19536    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19537        let type_id = std::any::TypeId::of::<T>();
19538        self.addons
19539            .get_mut(&type_id)
19540            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19541    }
19542
19543    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19544        let text_layout_details = self.text_layout_details(window);
19545        let style = &text_layout_details.editor_style;
19546        let font_id = window.text_system().resolve_font(&style.text.font());
19547        let font_size = style.text.font_size.to_pixels(window.rem_size());
19548        let line_height = style.text.line_height_in_pixels(window.rem_size());
19549        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19550
19551        gpui::Size::new(em_width, line_height)
19552    }
19553
19554    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19555        self.load_diff_task.clone()
19556    }
19557
19558    fn read_metadata_from_db(
19559        &mut self,
19560        item_id: u64,
19561        workspace_id: WorkspaceId,
19562        window: &mut Window,
19563        cx: &mut Context<Editor>,
19564    ) {
19565        if self.is_singleton(cx)
19566            && !self.mode.is_minimap()
19567            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19568        {
19569            let buffer_snapshot = OnceCell::new();
19570
19571            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19572                if !folds.is_empty() {
19573                    let snapshot =
19574                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19575                    self.fold_ranges(
19576                        folds
19577                            .into_iter()
19578                            .map(|(start, end)| {
19579                                snapshot.clip_offset(start, Bias::Left)
19580                                    ..snapshot.clip_offset(end, Bias::Right)
19581                            })
19582                            .collect(),
19583                        false,
19584                        window,
19585                        cx,
19586                    );
19587                }
19588            }
19589
19590            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19591                if !selections.is_empty() {
19592                    let snapshot =
19593                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19594                    self.change_selections(None, window, cx, |s| {
19595                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19596                            snapshot.clip_offset(start, Bias::Left)
19597                                ..snapshot.clip_offset(end, Bias::Right)
19598                        }));
19599                    });
19600                }
19601            };
19602        }
19603
19604        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19605    }
19606}
19607
19608fn vim_enabled(cx: &App) -> bool {
19609    cx.global::<SettingsStore>()
19610        .raw_user_settings()
19611        .get("vim_mode")
19612        == Some(&serde_json::Value::Bool(true))
19613}
19614
19615fn process_completion_for_edit(
19616    completion: &Completion,
19617    intent: CompletionIntent,
19618    buffer: &Entity<Buffer>,
19619    cursor_position: &text::Anchor,
19620    cx: &mut Context<Editor>,
19621) -> CompletionEdit {
19622    let buffer = buffer.read(cx);
19623    let buffer_snapshot = buffer.snapshot();
19624    let (snippet, new_text) = if completion.is_snippet() {
19625        let mut snippet_source = completion.new_text.clone();
19626        if let Some(scope) = buffer_snapshot.language_scope_at(cursor_position) {
19627            if scope.prefers_label_for_snippet_in_completion() {
19628                if let Some(label) = completion.label() {
19629                    if matches!(
19630                        completion.kind(),
19631                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
19632                    ) {
19633                        snippet_source = label;
19634                    }
19635                }
19636            }
19637        }
19638        match Snippet::parse(&snippet_source).log_err() {
19639            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
19640            None => (None, completion.new_text.clone()),
19641        }
19642    } else {
19643        (None, completion.new_text.clone())
19644    };
19645
19646    let mut range_to_replace = {
19647        let replace_range = &completion.replace_range;
19648        if let CompletionSource::Lsp {
19649            insert_range: Some(insert_range),
19650            ..
19651        } = &completion.source
19652        {
19653            debug_assert_eq!(
19654                insert_range.start, replace_range.start,
19655                "insert_range and replace_range should start at the same position"
19656            );
19657            debug_assert!(
19658                insert_range
19659                    .start
19660                    .cmp(&cursor_position, &buffer_snapshot)
19661                    .is_le(),
19662                "insert_range should start before or at cursor position"
19663            );
19664            debug_assert!(
19665                replace_range
19666                    .start
19667                    .cmp(&cursor_position, &buffer_snapshot)
19668                    .is_le(),
19669                "replace_range should start before or at cursor position"
19670            );
19671            debug_assert!(
19672                insert_range
19673                    .end
19674                    .cmp(&cursor_position, &buffer_snapshot)
19675                    .is_le(),
19676                "insert_range should end before or at cursor position"
19677            );
19678
19679            let should_replace = match intent {
19680                CompletionIntent::CompleteWithInsert => false,
19681                CompletionIntent::CompleteWithReplace => true,
19682                CompletionIntent::Complete | CompletionIntent::Compose => {
19683                    let insert_mode =
19684                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19685                            .completions
19686                            .lsp_insert_mode;
19687                    match insert_mode {
19688                        LspInsertMode::Insert => false,
19689                        LspInsertMode::Replace => true,
19690                        LspInsertMode::ReplaceSubsequence => {
19691                            let mut text_to_replace = buffer.chars_for_range(
19692                                buffer.anchor_before(replace_range.start)
19693                                    ..buffer.anchor_after(replace_range.end),
19694                            );
19695                            let mut current_needle = text_to_replace.next();
19696                            for haystack_ch in completion.label.text.chars() {
19697                                if let Some(needle_ch) = current_needle {
19698                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
19699                                        current_needle = text_to_replace.next();
19700                                    }
19701                                }
19702                            }
19703                            current_needle.is_none()
19704                        }
19705                        LspInsertMode::ReplaceSuffix => {
19706                            if replace_range
19707                                .end
19708                                .cmp(&cursor_position, &buffer_snapshot)
19709                                .is_gt()
19710                            {
19711                                let range_after_cursor = *cursor_position..replace_range.end;
19712                                let text_after_cursor = buffer
19713                                    .text_for_range(
19714                                        buffer.anchor_before(range_after_cursor.start)
19715                                            ..buffer.anchor_after(range_after_cursor.end),
19716                                    )
19717                                    .collect::<String>()
19718                                    .to_ascii_lowercase();
19719                                completion
19720                                    .label
19721                                    .text
19722                                    .to_ascii_lowercase()
19723                                    .ends_with(&text_after_cursor)
19724                            } else {
19725                                true
19726                            }
19727                        }
19728                    }
19729                }
19730            };
19731
19732            if should_replace {
19733                replace_range.clone()
19734            } else {
19735                insert_range.clone()
19736            }
19737        } else {
19738            replace_range.clone()
19739        }
19740    };
19741
19742    if range_to_replace
19743        .end
19744        .cmp(&cursor_position, &buffer_snapshot)
19745        .is_lt()
19746    {
19747        range_to_replace.end = *cursor_position;
19748    }
19749
19750    CompletionEdit {
19751        new_text,
19752        replace_range: range_to_replace.to_offset(&buffer),
19753        snippet,
19754    }
19755}
19756
19757struct CompletionEdit {
19758    new_text: String,
19759    replace_range: Range<usize>,
19760    snippet: Option<Snippet>,
19761}
19762
19763fn insert_extra_newline_brackets(
19764    buffer: &MultiBufferSnapshot,
19765    range: Range<usize>,
19766    language: &language::LanguageScope,
19767) -> bool {
19768    let leading_whitespace_len = buffer
19769        .reversed_chars_at(range.start)
19770        .take_while(|c| c.is_whitespace() && *c != '\n')
19771        .map(|c| c.len_utf8())
19772        .sum::<usize>();
19773    let trailing_whitespace_len = buffer
19774        .chars_at(range.end)
19775        .take_while(|c| c.is_whitespace() && *c != '\n')
19776        .map(|c| c.len_utf8())
19777        .sum::<usize>();
19778    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19779
19780    language.brackets().any(|(pair, enabled)| {
19781        let pair_start = pair.start.trim_end();
19782        let pair_end = pair.end.trim_start();
19783
19784        enabled
19785            && pair.newline
19786            && buffer.contains_str_at(range.end, pair_end)
19787            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19788    })
19789}
19790
19791fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19792    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19793        [(buffer, range, _)] => (*buffer, range.clone()),
19794        _ => return false,
19795    };
19796    let pair = {
19797        let mut result: Option<BracketMatch> = None;
19798
19799        for pair in buffer
19800            .all_bracket_ranges(range.clone())
19801            .filter(move |pair| {
19802                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19803            })
19804        {
19805            let len = pair.close_range.end - pair.open_range.start;
19806
19807            if let Some(existing) = &result {
19808                let existing_len = existing.close_range.end - existing.open_range.start;
19809                if len > existing_len {
19810                    continue;
19811                }
19812            }
19813
19814            result = Some(pair);
19815        }
19816
19817        result
19818    };
19819    let Some(pair) = pair else {
19820        return false;
19821    };
19822    pair.newline_only
19823        && buffer
19824            .chars_for_range(pair.open_range.end..range.start)
19825            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19826            .all(|c| c.is_whitespace() && c != '\n')
19827}
19828
19829fn update_uncommitted_diff_for_buffer(
19830    editor: Entity<Editor>,
19831    project: &Entity<Project>,
19832    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19833    buffer: Entity<MultiBuffer>,
19834    cx: &mut App,
19835) -> Task<()> {
19836    let mut tasks = Vec::new();
19837    project.update(cx, |project, cx| {
19838        for buffer in buffers {
19839            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19840                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19841            }
19842        }
19843    });
19844    cx.spawn(async move |cx| {
19845        let diffs = future::join_all(tasks).await;
19846        if editor
19847            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19848            .unwrap_or(false)
19849        {
19850            return;
19851        }
19852
19853        buffer
19854            .update(cx, |buffer, cx| {
19855                for diff in diffs.into_iter().flatten() {
19856                    buffer.add_diff(diff, cx);
19857                }
19858            })
19859            .ok();
19860    })
19861}
19862
19863fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
19864    let tab_size = tab_size.get() as usize;
19865    let mut width = offset;
19866
19867    for ch in text.chars() {
19868        width += if ch == '\t' {
19869            tab_size - (width % tab_size)
19870        } else {
19871            1
19872        };
19873    }
19874
19875    width - offset
19876}
19877
19878#[cfg(test)]
19879mod tests {
19880    use super::*;
19881
19882    #[test]
19883    fn test_string_size_with_expanded_tabs() {
19884        let nz = |val| NonZeroU32::new(val).unwrap();
19885        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
19886        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
19887        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
19888        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
19889        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
19890        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
19891        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
19892        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
19893    }
19894}
19895
19896/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
19897struct WordBreakingTokenizer<'a> {
19898    input: &'a str,
19899}
19900
19901impl<'a> WordBreakingTokenizer<'a> {
19902    fn new(input: &'a str) -> Self {
19903        Self { input }
19904    }
19905}
19906
19907fn is_char_ideographic(ch: char) -> bool {
19908    use unicode_script::Script::*;
19909    use unicode_script::UnicodeScript;
19910    matches!(ch.script(), Han | Tangut | Yi)
19911}
19912
19913fn is_grapheme_ideographic(text: &str) -> bool {
19914    text.chars().any(is_char_ideographic)
19915}
19916
19917fn is_grapheme_whitespace(text: &str) -> bool {
19918    text.chars().any(|x| x.is_whitespace())
19919}
19920
19921fn should_stay_with_preceding_ideograph(text: &str) -> bool {
19922    text.chars().next().map_or(false, |ch| {
19923        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
19924    })
19925}
19926
19927#[derive(PartialEq, Eq, Debug, Clone, Copy)]
19928enum WordBreakToken<'a> {
19929    Word { token: &'a str, grapheme_len: usize },
19930    InlineWhitespace { token: &'a str, grapheme_len: usize },
19931    Newline,
19932}
19933
19934impl<'a> Iterator for WordBreakingTokenizer<'a> {
19935    /// Yields a span, the count of graphemes in the token, and whether it was
19936    /// whitespace. Note that it also breaks at word boundaries.
19937    type Item = WordBreakToken<'a>;
19938
19939    fn next(&mut self) -> Option<Self::Item> {
19940        use unicode_segmentation::UnicodeSegmentation;
19941        if self.input.is_empty() {
19942            return None;
19943        }
19944
19945        let mut iter = self.input.graphemes(true).peekable();
19946        let mut offset = 0;
19947        let mut grapheme_len = 0;
19948        if let Some(first_grapheme) = iter.next() {
19949            let is_newline = first_grapheme == "\n";
19950            let is_whitespace = is_grapheme_whitespace(first_grapheme);
19951            offset += first_grapheme.len();
19952            grapheme_len += 1;
19953            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
19954                if let Some(grapheme) = iter.peek().copied() {
19955                    if should_stay_with_preceding_ideograph(grapheme) {
19956                        offset += grapheme.len();
19957                        grapheme_len += 1;
19958                    }
19959                }
19960            } else {
19961                let mut words = self.input[offset..].split_word_bound_indices().peekable();
19962                let mut next_word_bound = words.peek().copied();
19963                if next_word_bound.map_or(false, |(i, _)| i == 0) {
19964                    next_word_bound = words.next();
19965                }
19966                while let Some(grapheme) = iter.peek().copied() {
19967                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
19968                        break;
19969                    };
19970                    if is_grapheme_whitespace(grapheme) != is_whitespace
19971                        || (grapheme == "\n") != is_newline
19972                    {
19973                        break;
19974                    };
19975                    offset += grapheme.len();
19976                    grapheme_len += 1;
19977                    iter.next();
19978                }
19979            }
19980            let token = &self.input[..offset];
19981            self.input = &self.input[offset..];
19982            if token == "\n" {
19983                Some(WordBreakToken::Newline)
19984            } else if is_whitespace {
19985                Some(WordBreakToken::InlineWhitespace {
19986                    token,
19987                    grapheme_len,
19988                })
19989            } else {
19990                Some(WordBreakToken::Word {
19991                    token,
19992                    grapheme_len,
19993                })
19994            }
19995        } else {
19996            None
19997        }
19998    }
19999}
20000
20001#[test]
20002fn test_word_breaking_tokenizer() {
20003    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20004        ("", &[]),
20005        ("  ", &[whitespace("  ", 2)]),
20006        ("Ʒ", &[word("Ʒ", 1)]),
20007        ("Ǽ", &[word("Ǽ", 1)]),
20008        ("", &[word("", 1)]),
20009        ("⋑⋑", &[word("⋑⋑", 2)]),
20010        (
20011            "原理,进而",
20012            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20013        ),
20014        (
20015            "hello world",
20016            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20017        ),
20018        (
20019            "hello, world",
20020            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20021        ),
20022        (
20023            "  hello world",
20024            &[
20025                whitespace("  ", 2),
20026                word("hello", 5),
20027                whitespace(" ", 1),
20028                word("world", 5),
20029            ],
20030        ),
20031        (
20032            "这是什么 \n 钢笔",
20033            &[
20034                word("", 1),
20035                word("", 1),
20036                word("", 1),
20037                word("", 1),
20038                whitespace(" ", 1),
20039                newline(),
20040                whitespace(" ", 1),
20041                word("", 1),
20042                word("", 1),
20043            ],
20044        ),
20045        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20046    ];
20047
20048    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20049        WordBreakToken::Word {
20050            token,
20051            grapheme_len,
20052        }
20053    }
20054
20055    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20056        WordBreakToken::InlineWhitespace {
20057            token,
20058            grapheme_len,
20059        }
20060    }
20061
20062    fn newline() -> WordBreakToken<'static> {
20063        WordBreakToken::Newline
20064    }
20065
20066    for (input, result) in tests {
20067        assert_eq!(
20068            WordBreakingTokenizer::new(input)
20069                .collect::<Vec<_>>()
20070                .as_slice(),
20071            *result,
20072        );
20073    }
20074}
20075
20076fn wrap_with_prefix(
20077    line_prefix: String,
20078    unwrapped_text: String,
20079    wrap_column: usize,
20080    tab_size: NonZeroU32,
20081    preserve_existing_whitespace: bool,
20082) -> String {
20083    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20084    let mut wrapped_text = String::new();
20085    let mut current_line = line_prefix.clone();
20086
20087    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20088    let mut current_line_len = line_prefix_len;
20089    let mut in_whitespace = false;
20090    for token in tokenizer {
20091        let have_preceding_whitespace = in_whitespace;
20092        match token {
20093            WordBreakToken::Word {
20094                token,
20095                grapheme_len,
20096            } => {
20097                in_whitespace = false;
20098                if current_line_len + grapheme_len > wrap_column
20099                    && current_line_len != line_prefix_len
20100                {
20101                    wrapped_text.push_str(current_line.trim_end());
20102                    wrapped_text.push('\n');
20103                    current_line.truncate(line_prefix.len());
20104                    current_line_len = line_prefix_len;
20105                }
20106                current_line.push_str(token);
20107                current_line_len += grapheme_len;
20108            }
20109            WordBreakToken::InlineWhitespace {
20110                mut token,
20111                mut grapheme_len,
20112            } => {
20113                in_whitespace = true;
20114                if have_preceding_whitespace && !preserve_existing_whitespace {
20115                    continue;
20116                }
20117                if !preserve_existing_whitespace {
20118                    token = " ";
20119                    grapheme_len = 1;
20120                }
20121                if current_line_len + grapheme_len > wrap_column {
20122                    wrapped_text.push_str(current_line.trim_end());
20123                    wrapped_text.push('\n');
20124                    current_line.truncate(line_prefix.len());
20125                    current_line_len = line_prefix_len;
20126                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20127                    current_line.push_str(token);
20128                    current_line_len += grapheme_len;
20129                }
20130            }
20131            WordBreakToken::Newline => {
20132                in_whitespace = true;
20133                if preserve_existing_whitespace {
20134                    wrapped_text.push_str(current_line.trim_end());
20135                    wrapped_text.push('\n');
20136                    current_line.truncate(line_prefix.len());
20137                    current_line_len = line_prefix_len;
20138                } else if have_preceding_whitespace {
20139                    continue;
20140                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20141                {
20142                    wrapped_text.push_str(current_line.trim_end());
20143                    wrapped_text.push('\n');
20144                    current_line.truncate(line_prefix.len());
20145                    current_line_len = line_prefix_len;
20146                } else if current_line_len != line_prefix_len {
20147                    current_line.push(' ');
20148                    current_line_len += 1;
20149                }
20150            }
20151        }
20152    }
20153
20154    if !current_line.is_empty() {
20155        wrapped_text.push_str(&current_line);
20156    }
20157    wrapped_text
20158}
20159
20160#[test]
20161fn test_wrap_with_prefix() {
20162    assert_eq!(
20163        wrap_with_prefix(
20164            "# ".to_string(),
20165            "abcdefg".to_string(),
20166            4,
20167            NonZeroU32::new(4).unwrap(),
20168            false,
20169        ),
20170        "# abcdefg"
20171    );
20172    assert_eq!(
20173        wrap_with_prefix(
20174            "".to_string(),
20175            "\thello world".to_string(),
20176            8,
20177            NonZeroU32::new(4).unwrap(),
20178            false,
20179        ),
20180        "hello\nworld"
20181    );
20182    assert_eq!(
20183        wrap_with_prefix(
20184            "// ".to_string(),
20185            "xx \nyy zz aa bb cc".to_string(),
20186            12,
20187            NonZeroU32::new(4).unwrap(),
20188            false,
20189        ),
20190        "// xx yy zz\n// aa bb cc"
20191    );
20192    assert_eq!(
20193        wrap_with_prefix(
20194            String::new(),
20195            "这是什么 \n 钢笔".to_string(),
20196            3,
20197            NonZeroU32::new(4).unwrap(),
20198            false,
20199        ),
20200        "这是什\n么 钢\n"
20201    );
20202}
20203
20204pub trait CollaborationHub {
20205    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20206    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20207    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20208}
20209
20210impl CollaborationHub for Entity<Project> {
20211    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20212        self.read(cx).collaborators()
20213    }
20214
20215    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20216        self.read(cx).user_store().read(cx).participant_indices()
20217    }
20218
20219    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20220        let this = self.read(cx);
20221        let user_ids = this.collaborators().values().map(|c| c.user_id);
20222        this.user_store().read(cx).participant_names(user_ids, cx)
20223    }
20224}
20225
20226pub trait SemanticsProvider {
20227    fn hover(
20228        &self,
20229        buffer: &Entity<Buffer>,
20230        position: text::Anchor,
20231        cx: &mut App,
20232    ) -> Option<Task<Vec<project::Hover>>>;
20233
20234    fn inline_values(
20235        &self,
20236        buffer_handle: Entity<Buffer>,
20237        range: Range<text::Anchor>,
20238        cx: &mut App,
20239    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20240
20241    fn inlay_hints(
20242        &self,
20243        buffer_handle: Entity<Buffer>,
20244        range: Range<text::Anchor>,
20245        cx: &mut App,
20246    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20247
20248    fn resolve_inlay_hint(
20249        &self,
20250        hint: InlayHint,
20251        buffer_handle: Entity<Buffer>,
20252        server_id: LanguageServerId,
20253        cx: &mut App,
20254    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20255
20256    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20257
20258    fn document_highlights(
20259        &self,
20260        buffer: &Entity<Buffer>,
20261        position: text::Anchor,
20262        cx: &mut App,
20263    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20264
20265    fn definitions(
20266        &self,
20267        buffer: &Entity<Buffer>,
20268        position: text::Anchor,
20269        kind: GotoDefinitionKind,
20270        cx: &mut App,
20271    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20272
20273    fn range_for_rename(
20274        &self,
20275        buffer: &Entity<Buffer>,
20276        position: text::Anchor,
20277        cx: &mut App,
20278    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20279
20280    fn perform_rename(
20281        &self,
20282        buffer: &Entity<Buffer>,
20283        position: text::Anchor,
20284        new_name: String,
20285        cx: &mut App,
20286    ) -> Option<Task<Result<ProjectTransaction>>>;
20287}
20288
20289pub trait CompletionProvider {
20290    fn completions(
20291        &self,
20292        excerpt_id: ExcerptId,
20293        buffer: &Entity<Buffer>,
20294        buffer_position: text::Anchor,
20295        trigger: CompletionContext,
20296        window: &mut Window,
20297        cx: &mut Context<Editor>,
20298    ) -> Task<Result<Vec<CompletionResponse>>>;
20299
20300    fn resolve_completions(
20301        &self,
20302        buffer: Entity<Buffer>,
20303        completion_indices: Vec<usize>,
20304        completions: Rc<RefCell<Box<[Completion]>>>,
20305        cx: &mut Context<Editor>,
20306    ) -> Task<Result<bool>>;
20307
20308    fn apply_additional_edits_for_completion(
20309        &self,
20310        _buffer: Entity<Buffer>,
20311        _completions: Rc<RefCell<Box<[Completion]>>>,
20312        _completion_index: usize,
20313        _push_to_history: bool,
20314        _cx: &mut Context<Editor>,
20315    ) -> Task<Result<Option<language::Transaction>>> {
20316        Task::ready(Ok(None))
20317    }
20318
20319    fn is_completion_trigger(
20320        &self,
20321        buffer: &Entity<Buffer>,
20322        position: language::Anchor,
20323        text: &str,
20324        trigger_in_words: bool,
20325        menu_is_open: bool,
20326        cx: &mut Context<Editor>,
20327    ) -> bool;
20328
20329    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20330
20331    fn sort_completions(&self) -> bool {
20332        true
20333    }
20334
20335    fn filter_completions(&self) -> bool {
20336        true
20337    }
20338}
20339
20340pub trait CodeActionProvider {
20341    fn id(&self) -> Arc<str>;
20342
20343    fn code_actions(
20344        &self,
20345        buffer: &Entity<Buffer>,
20346        range: Range<text::Anchor>,
20347        window: &mut Window,
20348        cx: &mut App,
20349    ) -> Task<Result<Vec<CodeAction>>>;
20350
20351    fn apply_code_action(
20352        &self,
20353        buffer_handle: Entity<Buffer>,
20354        action: CodeAction,
20355        excerpt_id: ExcerptId,
20356        push_to_history: bool,
20357        window: &mut Window,
20358        cx: &mut App,
20359    ) -> Task<Result<ProjectTransaction>>;
20360}
20361
20362impl CodeActionProvider for Entity<Project> {
20363    fn id(&self) -> Arc<str> {
20364        "project".into()
20365    }
20366
20367    fn code_actions(
20368        &self,
20369        buffer: &Entity<Buffer>,
20370        range: Range<text::Anchor>,
20371        _window: &mut Window,
20372        cx: &mut App,
20373    ) -> Task<Result<Vec<CodeAction>>> {
20374        self.update(cx, |project, cx| {
20375            let code_lens = project.code_lens(buffer, range.clone(), cx);
20376            let code_actions = project.code_actions(buffer, range, None, cx);
20377            cx.background_spawn(async move {
20378                let (code_lens, code_actions) = join(code_lens, code_actions).await;
20379                Ok(code_lens
20380                    .context("code lens fetch")?
20381                    .into_iter()
20382                    .chain(code_actions.context("code action fetch")?)
20383                    .collect())
20384            })
20385        })
20386    }
20387
20388    fn apply_code_action(
20389        &self,
20390        buffer_handle: Entity<Buffer>,
20391        action: CodeAction,
20392        _excerpt_id: ExcerptId,
20393        push_to_history: bool,
20394        _window: &mut Window,
20395        cx: &mut App,
20396    ) -> Task<Result<ProjectTransaction>> {
20397        self.update(cx, |project, cx| {
20398            project.apply_code_action(buffer_handle, action, push_to_history, cx)
20399        })
20400    }
20401}
20402
20403fn snippet_completions(
20404    project: &Project,
20405    buffer: &Entity<Buffer>,
20406    buffer_position: text::Anchor,
20407    cx: &mut App,
20408) -> Task<Result<CompletionResponse>> {
20409    let languages = buffer.read(cx).languages_at(buffer_position);
20410    let snippet_store = project.snippets().read(cx);
20411
20412    let scopes: Vec<_> = languages
20413        .iter()
20414        .filter_map(|language| {
20415            let language_name = language.lsp_id();
20416            let snippets = snippet_store.snippets_for(Some(language_name), cx);
20417
20418            if snippets.is_empty() {
20419                None
20420            } else {
20421                Some((language.default_scope(), snippets))
20422            }
20423        })
20424        .collect();
20425
20426    if scopes.is_empty() {
20427        return Task::ready(Ok(CompletionResponse {
20428            completions: vec![],
20429            is_incomplete: false,
20430        }));
20431    }
20432
20433    let snapshot = buffer.read(cx).text_snapshot();
20434    let chars: String = snapshot
20435        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
20436        .collect();
20437    let executor = cx.background_executor().clone();
20438
20439    cx.background_spawn(async move {
20440        let mut is_incomplete = false;
20441        let mut completions: Vec<Completion> = Vec::new();
20442        for (scope, snippets) in scopes.into_iter() {
20443            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
20444            let mut last_word = chars
20445                .chars()
20446                .take_while(|c| classifier.is_word(*c))
20447                .collect::<String>();
20448            last_word = last_word.chars().rev().collect();
20449
20450            if last_word.is_empty() {
20451                return Ok(CompletionResponse {
20452                    completions: vec![],
20453                    is_incomplete: true,
20454                });
20455            }
20456
20457            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
20458            let to_lsp = |point: &text::Anchor| {
20459                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
20460                point_to_lsp(end)
20461            };
20462            let lsp_end = to_lsp(&buffer_position);
20463
20464            let candidates = snippets
20465                .iter()
20466                .enumerate()
20467                .flat_map(|(ix, snippet)| {
20468                    snippet
20469                        .prefix
20470                        .iter()
20471                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
20472                })
20473                .collect::<Vec<StringMatchCandidate>>();
20474
20475            const MAX_RESULTS: usize = 100;
20476            let mut matches = fuzzy::match_strings(
20477                &candidates,
20478                &last_word,
20479                last_word.chars().any(|c| c.is_uppercase()),
20480                MAX_RESULTS,
20481                &Default::default(),
20482                executor.clone(),
20483            )
20484            .await;
20485
20486            if matches.len() >= MAX_RESULTS {
20487                is_incomplete = true;
20488            }
20489
20490            // Remove all candidates where the query's start does not match the start of any word in the candidate
20491            if let Some(query_start) = last_word.chars().next() {
20492                matches.retain(|string_match| {
20493                    split_words(&string_match.string).any(|word| {
20494                        // Check that the first codepoint of the word as lowercase matches the first
20495                        // codepoint of the query as lowercase
20496                        word.chars()
20497                            .flat_map(|codepoint| codepoint.to_lowercase())
20498                            .zip(query_start.to_lowercase())
20499                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20500                    })
20501                });
20502            }
20503
20504            let matched_strings = matches
20505                .into_iter()
20506                .map(|m| m.string)
20507                .collect::<HashSet<_>>();
20508
20509            completions.extend(snippets.iter().filter_map(|snippet| {
20510                let matching_prefix = snippet
20511                    .prefix
20512                    .iter()
20513                    .find(|prefix| matched_strings.contains(*prefix))?;
20514                let start = as_offset - last_word.len();
20515                let start = snapshot.anchor_before(start);
20516                let range = start..buffer_position;
20517                let lsp_start = to_lsp(&start);
20518                let lsp_range = lsp::Range {
20519                    start: lsp_start,
20520                    end: lsp_end,
20521                };
20522                Some(Completion {
20523                    replace_range: range,
20524                    new_text: snippet.body.clone(),
20525                    source: CompletionSource::Lsp {
20526                        insert_range: None,
20527                        server_id: LanguageServerId(usize::MAX),
20528                        resolved: true,
20529                        lsp_completion: Box::new(lsp::CompletionItem {
20530                            label: snippet.prefix.first().unwrap().clone(),
20531                            kind: Some(CompletionItemKind::SNIPPET),
20532                            label_details: snippet.description.as_ref().map(|description| {
20533                                lsp::CompletionItemLabelDetails {
20534                                    detail: Some(description.clone()),
20535                                    description: None,
20536                                }
20537                            }),
20538                            insert_text_format: Some(InsertTextFormat::SNIPPET),
20539                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20540                                lsp::InsertReplaceEdit {
20541                                    new_text: snippet.body.clone(),
20542                                    insert: lsp_range,
20543                                    replace: lsp_range,
20544                                },
20545                            )),
20546                            filter_text: Some(snippet.body.clone()),
20547                            sort_text: Some(char::MAX.to_string()),
20548                            ..lsp::CompletionItem::default()
20549                        }),
20550                        lsp_defaults: None,
20551                    },
20552                    label: CodeLabel {
20553                        text: matching_prefix.clone(),
20554                        runs: Vec::new(),
20555                        filter_range: 0..matching_prefix.len(),
20556                    },
20557                    icon_path: None,
20558                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
20559                        single_line: snippet.name.clone().into(),
20560                        plain_text: snippet
20561                            .description
20562                            .clone()
20563                            .map(|description| description.into()),
20564                    }),
20565                    insert_text_mode: None,
20566                    confirm: None,
20567                })
20568            }))
20569        }
20570
20571        Ok(CompletionResponse {
20572            completions,
20573            is_incomplete,
20574        })
20575    })
20576}
20577
20578impl CompletionProvider for Entity<Project> {
20579    fn completions(
20580        &self,
20581        _excerpt_id: ExcerptId,
20582        buffer: &Entity<Buffer>,
20583        buffer_position: text::Anchor,
20584        options: CompletionContext,
20585        _window: &mut Window,
20586        cx: &mut Context<Editor>,
20587    ) -> Task<Result<Vec<CompletionResponse>>> {
20588        self.update(cx, |project, cx| {
20589            let snippets = snippet_completions(project, buffer, buffer_position, cx);
20590            let project_completions = project.completions(buffer, buffer_position, options, cx);
20591            cx.background_spawn(async move {
20592                let mut responses = project_completions.await?;
20593                let snippets = snippets.await?;
20594                if !snippets.completions.is_empty() {
20595                    responses.push(snippets);
20596                }
20597                Ok(responses)
20598            })
20599        })
20600    }
20601
20602    fn resolve_completions(
20603        &self,
20604        buffer: Entity<Buffer>,
20605        completion_indices: Vec<usize>,
20606        completions: Rc<RefCell<Box<[Completion]>>>,
20607        cx: &mut Context<Editor>,
20608    ) -> Task<Result<bool>> {
20609        self.update(cx, |project, cx| {
20610            project.lsp_store().update(cx, |lsp_store, cx| {
20611                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
20612            })
20613        })
20614    }
20615
20616    fn apply_additional_edits_for_completion(
20617        &self,
20618        buffer: Entity<Buffer>,
20619        completions: Rc<RefCell<Box<[Completion]>>>,
20620        completion_index: usize,
20621        push_to_history: bool,
20622        cx: &mut Context<Editor>,
20623    ) -> Task<Result<Option<language::Transaction>>> {
20624        self.update(cx, |project, cx| {
20625            project.lsp_store().update(cx, |lsp_store, cx| {
20626                lsp_store.apply_additional_edits_for_completion(
20627                    buffer,
20628                    completions,
20629                    completion_index,
20630                    push_to_history,
20631                    cx,
20632                )
20633            })
20634        })
20635    }
20636
20637    fn is_completion_trigger(
20638        &self,
20639        buffer: &Entity<Buffer>,
20640        position: language::Anchor,
20641        text: &str,
20642        trigger_in_words: bool,
20643        menu_is_open: bool,
20644        cx: &mut Context<Editor>,
20645    ) -> bool {
20646        let mut chars = text.chars();
20647        let char = if let Some(char) = chars.next() {
20648            char
20649        } else {
20650            return false;
20651        };
20652        if chars.next().is_some() {
20653            return false;
20654        }
20655
20656        let buffer = buffer.read(cx);
20657        let snapshot = buffer.snapshot();
20658        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
20659            return false;
20660        }
20661        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20662        if trigger_in_words && classifier.is_word(char) {
20663            return true;
20664        }
20665
20666        buffer.completion_triggers().contains(text)
20667    }
20668}
20669
20670impl SemanticsProvider for Entity<Project> {
20671    fn hover(
20672        &self,
20673        buffer: &Entity<Buffer>,
20674        position: text::Anchor,
20675        cx: &mut App,
20676    ) -> Option<Task<Vec<project::Hover>>> {
20677        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20678    }
20679
20680    fn document_highlights(
20681        &self,
20682        buffer: &Entity<Buffer>,
20683        position: text::Anchor,
20684        cx: &mut App,
20685    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20686        Some(self.update(cx, |project, cx| {
20687            project.document_highlights(buffer, position, cx)
20688        }))
20689    }
20690
20691    fn definitions(
20692        &self,
20693        buffer: &Entity<Buffer>,
20694        position: text::Anchor,
20695        kind: GotoDefinitionKind,
20696        cx: &mut App,
20697    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20698        Some(self.update(cx, |project, cx| match kind {
20699            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20700            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20701            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20702            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20703        }))
20704    }
20705
20706    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20707        // TODO: make this work for remote projects
20708        self.update(cx, |project, cx| {
20709            if project
20710                .active_debug_session(cx)
20711                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20712            {
20713                return true;
20714            }
20715
20716            buffer.update(cx, |buffer, cx| {
20717                project.any_language_server_supports_inlay_hints(buffer, cx)
20718            })
20719        })
20720    }
20721
20722    fn inline_values(
20723        &self,
20724        buffer_handle: Entity<Buffer>,
20725
20726        range: Range<text::Anchor>,
20727        cx: &mut App,
20728    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20729        self.update(cx, |project, cx| {
20730            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20731
20732            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20733        })
20734    }
20735
20736    fn inlay_hints(
20737        &self,
20738        buffer_handle: Entity<Buffer>,
20739        range: Range<text::Anchor>,
20740        cx: &mut App,
20741    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20742        Some(self.update(cx, |project, cx| {
20743            project.inlay_hints(buffer_handle, range, cx)
20744        }))
20745    }
20746
20747    fn resolve_inlay_hint(
20748        &self,
20749        hint: InlayHint,
20750        buffer_handle: Entity<Buffer>,
20751        server_id: LanguageServerId,
20752        cx: &mut App,
20753    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20754        Some(self.update(cx, |project, cx| {
20755            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20756        }))
20757    }
20758
20759    fn range_for_rename(
20760        &self,
20761        buffer: &Entity<Buffer>,
20762        position: text::Anchor,
20763        cx: &mut App,
20764    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20765        Some(self.update(cx, |project, cx| {
20766            let buffer = buffer.clone();
20767            let task = project.prepare_rename(buffer.clone(), position, cx);
20768            cx.spawn(async move |_, cx| {
20769                Ok(match task.await? {
20770                    PrepareRenameResponse::Success(range) => Some(range),
20771                    PrepareRenameResponse::InvalidPosition => None,
20772                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20773                        // Fallback on using TreeSitter info to determine identifier range
20774                        buffer.read_with(cx, |buffer, _| {
20775                            let snapshot = buffer.snapshot();
20776                            let (range, kind) = snapshot.surrounding_word(position);
20777                            if kind != Some(CharKind::Word) {
20778                                return None;
20779                            }
20780                            Some(
20781                                snapshot.anchor_before(range.start)
20782                                    ..snapshot.anchor_after(range.end),
20783                            )
20784                        })?
20785                    }
20786                })
20787            })
20788        }))
20789    }
20790
20791    fn perform_rename(
20792        &self,
20793        buffer: &Entity<Buffer>,
20794        position: text::Anchor,
20795        new_name: String,
20796        cx: &mut App,
20797    ) -> Option<Task<Result<ProjectTransaction>>> {
20798        Some(self.update(cx, |project, cx| {
20799            project.perform_rename(buffer.clone(), position, new_name, cx)
20800        }))
20801    }
20802}
20803
20804fn inlay_hint_settings(
20805    location: Anchor,
20806    snapshot: &MultiBufferSnapshot,
20807    cx: &mut Context<Editor>,
20808) -> InlayHintSettings {
20809    let file = snapshot.file_at(location);
20810    let language = snapshot.language_at(location).map(|l| l.name());
20811    language_settings(language, file, cx).inlay_hints
20812}
20813
20814fn consume_contiguous_rows(
20815    contiguous_row_selections: &mut Vec<Selection<Point>>,
20816    selection: &Selection<Point>,
20817    display_map: &DisplaySnapshot,
20818    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20819) -> (MultiBufferRow, MultiBufferRow) {
20820    contiguous_row_selections.push(selection.clone());
20821    let start_row = MultiBufferRow(selection.start.row);
20822    let mut end_row = ending_row(selection, display_map);
20823
20824    while let Some(next_selection) = selections.peek() {
20825        if next_selection.start.row <= end_row.0 {
20826            end_row = ending_row(next_selection, display_map);
20827            contiguous_row_selections.push(selections.next().unwrap().clone());
20828        } else {
20829            break;
20830        }
20831    }
20832    (start_row, end_row)
20833}
20834
20835fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20836    if next_selection.end.column > 0 || next_selection.is_empty() {
20837        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20838    } else {
20839        MultiBufferRow(next_selection.end.row)
20840    }
20841}
20842
20843impl EditorSnapshot {
20844    pub fn remote_selections_in_range<'a>(
20845        &'a self,
20846        range: &'a Range<Anchor>,
20847        collaboration_hub: &dyn CollaborationHub,
20848        cx: &'a App,
20849    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20850        let participant_names = collaboration_hub.user_names(cx);
20851        let participant_indices = collaboration_hub.user_participant_indices(cx);
20852        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20853        let collaborators_by_replica_id = collaborators_by_peer_id
20854            .values()
20855            .map(|collaborator| (collaborator.replica_id, collaborator))
20856            .collect::<HashMap<_, _>>();
20857        self.buffer_snapshot
20858            .selections_in_range(range, false)
20859            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20860                if replica_id == AGENT_REPLICA_ID {
20861                    Some(RemoteSelection {
20862                        replica_id,
20863                        selection,
20864                        cursor_shape,
20865                        line_mode,
20866                        collaborator_id: CollaboratorId::Agent,
20867                        user_name: Some("Agent".into()),
20868                        color: cx.theme().players().agent(),
20869                    })
20870                } else {
20871                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20872                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20873                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20874                    Some(RemoteSelection {
20875                        replica_id,
20876                        selection,
20877                        cursor_shape,
20878                        line_mode,
20879                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20880                        user_name,
20881                        color: if let Some(index) = participant_index {
20882                            cx.theme().players().color_for_participant(index.0)
20883                        } else {
20884                            cx.theme().players().absent()
20885                        },
20886                    })
20887                }
20888            })
20889    }
20890
20891    pub fn hunks_for_ranges(
20892        &self,
20893        ranges: impl IntoIterator<Item = Range<Point>>,
20894    ) -> Vec<MultiBufferDiffHunk> {
20895        let mut hunks = Vec::new();
20896        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20897            HashMap::default();
20898        for query_range in ranges {
20899            let query_rows =
20900                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20901            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20902                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20903            ) {
20904                // Include deleted hunks that are adjacent to the query range, because
20905                // otherwise they would be missed.
20906                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20907                if hunk.status().is_deleted() {
20908                    intersects_range |= hunk.row_range.start == query_rows.end;
20909                    intersects_range |= hunk.row_range.end == query_rows.start;
20910                }
20911                if intersects_range {
20912                    if !processed_buffer_rows
20913                        .entry(hunk.buffer_id)
20914                        .or_default()
20915                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20916                    {
20917                        continue;
20918                    }
20919                    hunks.push(hunk);
20920                }
20921            }
20922        }
20923
20924        hunks
20925    }
20926
20927    fn display_diff_hunks_for_rows<'a>(
20928        &'a self,
20929        display_rows: Range<DisplayRow>,
20930        folded_buffers: &'a HashSet<BufferId>,
20931    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20932        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20933        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20934
20935        self.buffer_snapshot
20936            .diff_hunks_in_range(buffer_start..buffer_end)
20937            .filter_map(|hunk| {
20938                if folded_buffers.contains(&hunk.buffer_id) {
20939                    return None;
20940                }
20941
20942                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20943                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20944
20945                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20946                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20947
20948                let display_hunk = if hunk_display_start.column() != 0 {
20949                    DisplayDiffHunk::Folded {
20950                        display_row: hunk_display_start.row(),
20951                    }
20952                } else {
20953                    let mut end_row = hunk_display_end.row();
20954                    if hunk_display_end.column() > 0 {
20955                        end_row.0 += 1;
20956                    }
20957                    let is_created_file = hunk.is_created_file();
20958                    DisplayDiffHunk::Unfolded {
20959                        status: hunk.status(),
20960                        diff_base_byte_range: hunk.diff_base_byte_range,
20961                        display_row_range: hunk_display_start.row()..end_row,
20962                        multi_buffer_range: Anchor::range_in_buffer(
20963                            hunk.excerpt_id,
20964                            hunk.buffer_id,
20965                            hunk.buffer_range,
20966                        ),
20967                        is_created_file,
20968                    }
20969                };
20970
20971                Some(display_hunk)
20972            })
20973    }
20974
20975    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20976        self.display_snapshot.buffer_snapshot.language_at(position)
20977    }
20978
20979    pub fn is_focused(&self) -> bool {
20980        self.is_focused
20981    }
20982
20983    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20984        self.placeholder_text.as_ref()
20985    }
20986
20987    pub fn scroll_position(&self) -> gpui::Point<f32> {
20988        self.scroll_anchor.scroll_position(&self.display_snapshot)
20989    }
20990
20991    fn gutter_dimensions(
20992        &self,
20993        font_id: FontId,
20994        font_size: Pixels,
20995        max_line_number_width: Pixels,
20996        cx: &App,
20997    ) -> Option<GutterDimensions> {
20998        if !self.show_gutter {
20999            return None;
21000        }
21001
21002        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
21003        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
21004
21005        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21006            matches!(
21007                ProjectSettings::get_global(cx).git.git_gutter,
21008                Some(GitGutterSetting::TrackedFiles)
21009            )
21010        });
21011        let gutter_settings = EditorSettings::get_global(cx).gutter;
21012        let show_line_numbers = self
21013            .show_line_numbers
21014            .unwrap_or(gutter_settings.line_numbers);
21015        let line_gutter_width = if show_line_numbers {
21016            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
21017            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
21018            max_line_number_width.max(min_width_for_number_on_gutter)
21019        } else {
21020            0.0.into()
21021        };
21022
21023        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21024        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21025
21026        let git_blame_entries_width =
21027            self.git_blame_gutter_max_author_length
21028                .map(|max_author_length| {
21029                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21030                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21031
21032                    /// The number of characters to dedicate to gaps and margins.
21033                    const SPACING_WIDTH: usize = 4;
21034
21035                    let max_char_count = max_author_length.min(renderer.max_author_length())
21036                        + ::git::SHORT_SHA_LENGTH
21037                        + MAX_RELATIVE_TIMESTAMP.len()
21038                        + SPACING_WIDTH;
21039
21040                    em_advance * max_char_count
21041                });
21042
21043        let is_singleton = self.buffer_snapshot.is_singleton();
21044
21045        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21046        left_padding += if !is_singleton {
21047            em_width * 4.0
21048        } else if show_runnables || show_breakpoints {
21049            em_width * 3.0
21050        } else if show_git_gutter && show_line_numbers {
21051            em_width * 2.0
21052        } else if show_git_gutter || show_line_numbers {
21053            em_width
21054        } else {
21055            px(0.)
21056        };
21057
21058        let shows_folds = is_singleton && gutter_settings.folds;
21059
21060        let right_padding = if shows_folds && show_line_numbers {
21061            em_width * 4.0
21062        } else if shows_folds || (!is_singleton && show_line_numbers) {
21063            em_width * 3.0
21064        } else if show_line_numbers {
21065            em_width
21066        } else {
21067            px(0.)
21068        };
21069
21070        Some(GutterDimensions {
21071            left_padding,
21072            right_padding,
21073            width: line_gutter_width + left_padding + right_padding,
21074            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21075            git_blame_entries_width,
21076        })
21077    }
21078
21079    pub fn render_crease_toggle(
21080        &self,
21081        buffer_row: MultiBufferRow,
21082        row_contains_cursor: bool,
21083        editor: Entity<Editor>,
21084        window: &mut Window,
21085        cx: &mut App,
21086    ) -> Option<AnyElement> {
21087        let folded = self.is_line_folded(buffer_row);
21088        let mut is_foldable = false;
21089
21090        if let Some(crease) = self
21091            .crease_snapshot
21092            .query_row(buffer_row, &self.buffer_snapshot)
21093        {
21094            is_foldable = true;
21095            match crease {
21096                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21097                    if let Some(render_toggle) = render_toggle {
21098                        let toggle_callback =
21099                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21100                                if folded {
21101                                    editor.update(cx, |editor, cx| {
21102                                        editor.fold_at(buffer_row, window, cx)
21103                                    });
21104                                } else {
21105                                    editor.update(cx, |editor, cx| {
21106                                        editor.unfold_at(buffer_row, window, cx)
21107                                    });
21108                                }
21109                            });
21110                        return Some((render_toggle)(
21111                            buffer_row,
21112                            folded,
21113                            toggle_callback,
21114                            window,
21115                            cx,
21116                        ));
21117                    }
21118                }
21119            }
21120        }
21121
21122        is_foldable |= self.starts_indent(buffer_row);
21123
21124        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21125            Some(
21126                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21127                    .toggle_state(folded)
21128                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21129                        if folded {
21130                            this.unfold_at(buffer_row, window, cx);
21131                        } else {
21132                            this.fold_at(buffer_row, window, cx);
21133                        }
21134                    }))
21135                    .into_any_element(),
21136            )
21137        } else {
21138            None
21139        }
21140    }
21141
21142    pub fn render_crease_trailer(
21143        &self,
21144        buffer_row: MultiBufferRow,
21145        window: &mut Window,
21146        cx: &mut App,
21147    ) -> Option<AnyElement> {
21148        let folded = self.is_line_folded(buffer_row);
21149        if let Crease::Inline { render_trailer, .. } = self
21150            .crease_snapshot
21151            .query_row(buffer_row, &self.buffer_snapshot)?
21152        {
21153            let render_trailer = render_trailer.as_ref()?;
21154            Some(render_trailer(buffer_row, folded, window, cx))
21155        } else {
21156            None
21157        }
21158    }
21159}
21160
21161impl Deref for EditorSnapshot {
21162    type Target = DisplaySnapshot;
21163
21164    fn deref(&self) -> &Self::Target {
21165        &self.display_snapshot
21166    }
21167}
21168
21169#[derive(Clone, Debug, PartialEq, Eq)]
21170pub enum EditorEvent {
21171    InputIgnored {
21172        text: Arc<str>,
21173    },
21174    InputHandled {
21175        utf16_range_to_replace: Option<Range<isize>>,
21176        text: Arc<str>,
21177    },
21178    ExcerptsAdded {
21179        buffer: Entity<Buffer>,
21180        predecessor: ExcerptId,
21181        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21182    },
21183    ExcerptsRemoved {
21184        ids: Vec<ExcerptId>,
21185        removed_buffer_ids: Vec<BufferId>,
21186    },
21187    BufferFoldToggled {
21188        ids: Vec<ExcerptId>,
21189        folded: bool,
21190    },
21191    ExcerptsEdited {
21192        ids: Vec<ExcerptId>,
21193    },
21194    ExcerptsExpanded {
21195        ids: Vec<ExcerptId>,
21196    },
21197    BufferEdited,
21198    Edited {
21199        transaction_id: clock::Lamport,
21200    },
21201    Reparsed(BufferId),
21202    Focused,
21203    FocusedIn,
21204    Blurred,
21205    DirtyChanged,
21206    Saved,
21207    TitleChanged,
21208    DiffBaseChanged,
21209    SelectionsChanged {
21210        local: bool,
21211    },
21212    ScrollPositionChanged {
21213        local: bool,
21214        autoscroll: bool,
21215    },
21216    Closed,
21217    TransactionUndone {
21218        transaction_id: clock::Lamport,
21219    },
21220    TransactionBegun {
21221        transaction_id: clock::Lamport,
21222    },
21223    Reloaded,
21224    CursorShapeChanged,
21225    PushedToNavHistory {
21226        anchor: Anchor,
21227        is_deactivate: bool,
21228    },
21229}
21230
21231impl EventEmitter<EditorEvent> for Editor {}
21232
21233impl Focusable for Editor {
21234    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21235        self.focus_handle.clone()
21236    }
21237}
21238
21239impl Render for Editor {
21240    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21241        let settings = ThemeSettings::get_global(cx);
21242
21243        let mut text_style = match self.mode {
21244            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21245                color: cx.theme().colors().editor_foreground,
21246                font_family: settings.ui_font.family.clone(),
21247                font_features: settings.ui_font.features.clone(),
21248                font_fallbacks: settings.ui_font.fallbacks.clone(),
21249                font_size: rems(0.875).into(),
21250                font_weight: settings.ui_font.weight,
21251                line_height: relative(settings.buffer_line_height.value()),
21252                ..Default::default()
21253            },
21254            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21255                color: cx.theme().colors().editor_foreground,
21256                font_family: settings.buffer_font.family.clone(),
21257                font_features: settings.buffer_font.features.clone(),
21258                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21259                font_size: settings.buffer_font_size(cx).into(),
21260                font_weight: settings.buffer_font.weight,
21261                line_height: relative(settings.buffer_line_height.value()),
21262                ..Default::default()
21263            },
21264        };
21265        if let Some(text_style_refinement) = &self.text_style_refinement {
21266            text_style.refine(text_style_refinement)
21267        }
21268
21269        let background = match self.mode {
21270            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21271            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
21272            EditorMode::Full { .. } => cx.theme().colors().editor_background,
21273            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
21274        };
21275
21276        EditorElement::new(
21277            &cx.entity(),
21278            EditorStyle {
21279                background,
21280                local_player: cx.theme().players().local(),
21281                text: text_style,
21282                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
21283                syntax: cx.theme().syntax().clone(),
21284                status: cx.theme().status().clone(),
21285                inlay_hints_style: make_inlay_hints_style(cx),
21286                inline_completion_styles: make_suggestion_styles(cx),
21287                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
21288                show_underlines: !self.mode.is_minimap(),
21289            },
21290        )
21291    }
21292}
21293
21294impl EntityInputHandler for Editor {
21295    fn text_for_range(
21296        &mut self,
21297        range_utf16: Range<usize>,
21298        adjusted_range: &mut Option<Range<usize>>,
21299        _: &mut Window,
21300        cx: &mut Context<Self>,
21301    ) -> Option<String> {
21302        let snapshot = self.buffer.read(cx).read(cx);
21303        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
21304        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
21305        if (start.0..end.0) != range_utf16 {
21306            adjusted_range.replace(start.0..end.0);
21307        }
21308        Some(snapshot.text_for_range(start..end).collect())
21309    }
21310
21311    fn selected_text_range(
21312        &mut self,
21313        ignore_disabled_input: bool,
21314        _: &mut Window,
21315        cx: &mut Context<Self>,
21316    ) -> Option<UTF16Selection> {
21317        // Prevent the IME menu from appearing when holding down an alphabetic key
21318        // while input is disabled.
21319        if !ignore_disabled_input && !self.input_enabled {
21320            return None;
21321        }
21322
21323        let selection = self.selections.newest::<OffsetUtf16>(cx);
21324        let range = selection.range();
21325
21326        Some(UTF16Selection {
21327            range: range.start.0..range.end.0,
21328            reversed: selection.reversed,
21329        })
21330    }
21331
21332    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
21333        let snapshot = self.buffer.read(cx).read(cx);
21334        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
21335        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
21336    }
21337
21338    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21339        self.clear_highlights::<InputComposition>(cx);
21340        self.ime_transaction.take();
21341    }
21342
21343    fn replace_text_in_range(
21344        &mut self,
21345        range_utf16: Option<Range<usize>>,
21346        text: &str,
21347        window: &mut Window,
21348        cx: &mut Context<Self>,
21349    ) {
21350        if !self.input_enabled {
21351            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21352            return;
21353        }
21354
21355        self.transact(window, cx, |this, window, cx| {
21356            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
21357                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21358                Some(this.selection_replacement_ranges(range_utf16, cx))
21359            } else {
21360                this.marked_text_ranges(cx)
21361            };
21362
21363            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
21364                let newest_selection_id = this.selections.newest_anchor().id;
21365                this.selections
21366                    .all::<OffsetUtf16>(cx)
21367                    .iter()
21368                    .zip(ranges_to_replace.iter())
21369                    .find_map(|(selection, range)| {
21370                        if selection.id == newest_selection_id {
21371                            Some(
21372                                (range.start.0 as isize - selection.head().0 as isize)
21373                                    ..(range.end.0 as isize - selection.head().0 as isize),
21374                            )
21375                        } else {
21376                            None
21377                        }
21378                    })
21379            });
21380
21381            cx.emit(EditorEvent::InputHandled {
21382                utf16_range_to_replace: range_to_replace,
21383                text: text.into(),
21384            });
21385
21386            if let Some(new_selected_ranges) = new_selected_ranges {
21387                this.change_selections(None, window, cx, |selections| {
21388                    selections.select_ranges(new_selected_ranges)
21389                });
21390                this.backspace(&Default::default(), window, cx);
21391            }
21392
21393            this.handle_input(text, window, cx);
21394        });
21395
21396        if let Some(transaction) = self.ime_transaction {
21397            self.buffer.update(cx, |buffer, cx| {
21398                buffer.group_until_transaction(transaction, cx);
21399            });
21400        }
21401
21402        self.unmark_text(window, cx);
21403    }
21404
21405    fn replace_and_mark_text_in_range(
21406        &mut self,
21407        range_utf16: Option<Range<usize>>,
21408        text: &str,
21409        new_selected_range_utf16: Option<Range<usize>>,
21410        window: &mut Window,
21411        cx: &mut Context<Self>,
21412    ) {
21413        if !self.input_enabled {
21414            return;
21415        }
21416
21417        let transaction = self.transact(window, cx, |this, window, cx| {
21418            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
21419                let snapshot = this.buffer.read(cx).read(cx);
21420                if let Some(relative_range_utf16) = range_utf16.as_ref() {
21421                    for marked_range in &mut marked_ranges {
21422                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
21423                        marked_range.start.0 += relative_range_utf16.start;
21424                        marked_range.start =
21425                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
21426                        marked_range.end =
21427                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
21428                    }
21429                }
21430                Some(marked_ranges)
21431            } else if let Some(range_utf16) = range_utf16 {
21432                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21433                Some(this.selection_replacement_ranges(range_utf16, cx))
21434            } else {
21435                None
21436            };
21437
21438            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
21439                let newest_selection_id = this.selections.newest_anchor().id;
21440                this.selections
21441                    .all::<OffsetUtf16>(cx)
21442                    .iter()
21443                    .zip(ranges_to_replace.iter())
21444                    .find_map(|(selection, range)| {
21445                        if selection.id == newest_selection_id {
21446                            Some(
21447                                (range.start.0 as isize - selection.head().0 as isize)
21448                                    ..(range.end.0 as isize - selection.head().0 as isize),
21449                            )
21450                        } else {
21451                            None
21452                        }
21453                    })
21454            });
21455
21456            cx.emit(EditorEvent::InputHandled {
21457                utf16_range_to_replace: range_to_replace,
21458                text: text.into(),
21459            });
21460
21461            if let Some(ranges) = ranges_to_replace {
21462                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
21463            }
21464
21465            let marked_ranges = {
21466                let snapshot = this.buffer.read(cx).read(cx);
21467                this.selections
21468                    .disjoint_anchors()
21469                    .iter()
21470                    .map(|selection| {
21471                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
21472                    })
21473                    .collect::<Vec<_>>()
21474            };
21475
21476            if text.is_empty() {
21477                this.unmark_text(window, cx);
21478            } else {
21479                this.highlight_text::<InputComposition>(
21480                    marked_ranges.clone(),
21481                    HighlightStyle {
21482                        underline: Some(UnderlineStyle {
21483                            thickness: px(1.),
21484                            color: None,
21485                            wavy: false,
21486                        }),
21487                        ..Default::default()
21488                    },
21489                    cx,
21490                );
21491            }
21492
21493            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
21494            let use_autoclose = this.use_autoclose;
21495            let use_auto_surround = this.use_auto_surround;
21496            this.set_use_autoclose(false);
21497            this.set_use_auto_surround(false);
21498            this.handle_input(text, window, cx);
21499            this.set_use_autoclose(use_autoclose);
21500            this.set_use_auto_surround(use_auto_surround);
21501
21502            if let Some(new_selected_range) = new_selected_range_utf16 {
21503                let snapshot = this.buffer.read(cx).read(cx);
21504                let new_selected_ranges = marked_ranges
21505                    .into_iter()
21506                    .map(|marked_range| {
21507                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
21508                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
21509                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
21510                        snapshot.clip_offset_utf16(new_start, Bias::Left)
21511                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
21512                    })
21513                    .collect::<Vec<_>>();
21514
21515                drop(snapshot);
21516                this.change_selections(None, window, cx, |selections| {
21517                    selections.select_ranges(new_selected_ranges)
21518                });
21519            }
21520        });
21521
21522        self.ime_transaction = self.ime_transaction.or(transaction);
21523        if let Some(transaction) = self.ime_transaction {
21524            self.buffer.update(cx, |buffer, cx| {
21525                buffer.group_until_transaction(transaction, cx);
21526            });
21527        }
21528
21529        if self.text_highlights::<InputComposition>(cx).is_none() {
21530            self.ime_transaction.take();
21531        }
21532    }
21533
21534    fn bounds_for_range(
21535        &mut self,
21536        range_utf16: Range<usize>,
21537        element_bounds: gpui::Bounds<Pixels>,
21538        window: &mut Window,
21539        cx: &mut Context<Self>,
21540    ) -> Option<gpui::Bounds<Pixels>> {
21541        let text_layout_details = self.text_layout_details(window);
21542        let gpui::Size {
21543            width: em_width,
21544            height: line_height,
21545        } = self.character_size(window);
21546
21547        let snapshot = self.snapshot(window, cx);
21548        let scroll_position = snapshot.scroll_position();
21549        let scroll_left = scroll_position.x * em_width;
21550
21551        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
21552        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
21553            + self.gutter_dimensions.width
21554            + self.gutter_dimensions.margin;
21555        let y = line_height * (start.row().as_f32() - scroll_position.y);
21556
21557        Some(Bounds {
21558            origin: element_bounds.origin + point(x, y),
21559            size: size(em_width, line_height),
21560        })
21561    }
21562
21563    fn character_index_for_point(
21564        &mut self,
21565        point: gpui::Point<Pixels>,
21566        _window: &mut Window,
21567        _cx: &mut Context<Self>,
21568    ) -> Option<usize> {
21569        let position_map = self.last_position_map.as_ref()?;
21570        if !position_map.text_hitbox.contains(&point) {
21571            return None;
21572        }
21573        let display_point = position_map.point_for_position(point).previous_valid;
21574        let anchor = position_map
21575            .snapshot
21576            .display_point_to_anchor(display_point, Bias::Left);
21577        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
21578        Some(utf16_offset.0)
21579    }
21580}
21581
21582trait SelectionExt {
21583    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
21584    fn spanned_rows(
21585        &self,
21586        include_end_if_at_line_start: bool,
21587        map: &DisplaySnapshot,
21588    ) -> Range<MultiBufferRow>;
21589}
21590
21591impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
21592    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
21593        let start = self
21594            .start
21595            .to_point(&map.buffer_snapshot)
21596            .to_display_point(map);
21597        let end = self
21598            .end
21599            .to_point(&map.buffer_snapshot)
21600            .to_display_point(map);
21601        if self.reversed {
21602            end..start
21603        } else {
21604            start..end
21605        }
21606    }
21607
21608    fn spanned_rows(
21609        &self,
21610        include_end_if_at_line_start: bool,
21611        map: &DisplaySnapshot,
21612    ) -> Range<MultiBufferRow> {
21613        let start = self.start.to_point(&map.buffer_snapshot);
21614        let mut end = self.end.to_point(&map.buffer_snapshot);
21615        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
21616            end.row -= 1;
21617        }
21618
21619        let buffer_start = map.prev_line_boundary(start).0;
21620        let buffer_end = map.next_line_boundary(end).0;
21621        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
21622    }
21623}
21624
21625impl<T: InvalidationRegion> InvalidationStack<T> {
21626    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
21627    where
21628        S: Clone + ToOffset,
21629    {
21630        while let Some(region) = self.last() {
21631            let all_selections_inside_invalidation_ranges =
21632                if selections.len() == region.ranges().len() {
21633                    selections
21634                        .iter()
21635                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
21636                        .all(|(selection, invalidation_range)| {
21637                            let head = selection.head().to_offset(buffer);
21638                            invalidation_range.start <= head && invalidation_range.end >= head
21639                        })
21640                } else {
21641                    false
21642                };
21643
21644            if all_selections_inside_invalidation_ranges {
21645                break;
21646            } else {
21647                self.pop();
21648            }
21649        }
21650    }
21651}
21652
21653impl<T> Default for InvalidationStack<T> {
21654    fn default() -> Self {
21655        Self(Default::default())
21656    }
21657}
21658
21659impl<T> Deref for InvalidationStack<T> {
21660    type Target = Vec<T>;
21661
21662    fn deref(&self) -> &Self::Target {
21663        &self.0
21664    }
21665}
21666
21667impl<T> DerefMut for InvalidationStack<T> {
21668    fn deref_mut(&mut self) -> &mut Self::Target {
21669        &mut self.0
21670    }
21671}
21672
21673impl InvalidationRegion for SnippetState {
21674    fn ranges(&self) -> &[Range<Anchor>] {
21675        &self.ranges[self.active_index]
21676    }
21677}
21678
21679fn inline_completion_edit_text(
21680    current_snapshot: &BufferSnapshot,
21681    edits: &[(Range<Anchor>, String)],
21682    edit_preview: &EditPreview,
21683    include_deletions: bool,
21684    cx: &App,
21685) -> HighlightedText {
21686    let edits = edits
21687        .iter()
21688        .map(|(anchor, text)| {
21689            (
21690                anchor.start.text_anchor..anchor.end.text_anchor,
21691                text.clone(),
21692            )
21693        })
21694        .collect::<Vec<_>>();
21695
21696    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21697}
21698
21699pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21700    match severity {
21701        lsp::DiagnosticSeverity::ERROR => colors.error,
21702        lsp::DiagnosticSeverity::WARNING => colors.warning,
21703        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21704        lsp::DiagnosticSeverity::HINT => colors.info,
21705        _ => colors.ignored,
21706    }
21707}
21708
21709pub fn styled_runs_for_code_label<'a>(
21710    label: &'a CodeLabel,
21711    syntax_theme: &'a theme::SyntaxTheme,
21712) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21713    let fade_out = HighlightStyle {
21714        fade_out: Some(0.35),
21715        ..Default::default()
21716    };
21717
21718    let mut prev_end = label.filter_range.end;
21719    label
21720        .runs
21721        .iter()
21722        .enumerate()
21723        .flat_map(move |(ix, (range, highlight_id))| {
21724            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21725                style
21726            } else {
21727                return Default::default();
21728            };
21729            let mut muted_style = style;
21730            muted_style.highlight(fade_out);
21731
21732            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21733            if range.start >= label.filter_range.end {
21734                if range.start > prev_end {
21735                    runs.push((prev_end..range.start, fade_out));
21736                }
21737                runs.push((range.clone(), muted_style));
21738            } else if range.end <= label.filter_range.end {
21739                runs.push((range.clone(), style));
21740            } else {
21741                runs.push((range.start..label.filter_range.end, style));
21742                runs.push((label.filter_range.end..range.end, muted_style));
21743            }
21744            prev_end = cmp::max(prev_end, range.end);
21745
21746            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21747                runs.push((prev_end..label.text.len(), fade_out));
21748            }
21749
21750            runs
21751        })
21752}
21753
21754pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21755    let mut prev_index = 0;
21756    let mut prev_codepoint: Option<char> = None;
21757    text.char_indices()
21758        .chain([(text.len(), '\0')])
21759        .filter_map(move |(index, codepoint)| {
21760            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21761            let is_boundary = index == text.len()
21762                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21763                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21764            if is_boundary {
21765                let chunk = &text[prev_index..index];
21766                prev_index = index;
21767                Some(chunk)
21768            } else {
21769                None
21770            }
21771        })
21772}
21773
21774pub trait RangeToAnchorExt: Sized {
21775    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21776
21777    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21778        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21779        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21780    }
21781}
21782
21783impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21784    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21785        let start_offset = self.start.to_offset(snapshot);
21786        let end_offset = self.end.to_offset(snapshot);
21787        if start_offset == end_offset {
21788            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21789        } else {
21790            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21791        }
21792    }
21793}
21794
21795pub trait RowExt {
21796    fn as_f32(&self) -> f32;
21797
21798    fn next_row(&self) -> Self;
21799
21800    fn previous_row(&self) -> Self;
21801
21802    fn minus(&self, other: Self) -> u32;
21803}
21804
21805impl RowExt for DisplayRow {
21806    fn as_f32(&self) -> f32 {
21807        self.0 as f32
21808    }
21809
21810    fn next_row(&self) -> Self {
21811        Self(self.0 + 1)
21812    }
21813
21814    fn previous_row(&self) -> Self {
21815        Self(self.0.saturating_sub(1))
21816    }
21817
21818    fn minus(&self, other: Self) -> u32 {
21819        self.0 - other.0
21820    }
21821}
21822
21823impl RowExt for MultiBufferRow {
21824    fn as_f32(&self) -> f32 {
21825        self.0 as f32
21826    }
21827
21828    fn next_row(&self) -> Self {
21829        Self(self.0 + 1)
21830    }
21831
21832    fn previous_row(&self) -> Self {
21833        Self(self.0.saturating_sub(1))
21834    }
21835
21836    fn minus(&self, other: Self) -> u32 {
21837        self.0 - other.0
21838    }
21839}
21840
21841trait RowRangeExt {
21842    type Row;
21843
21844    fn len(&self) -> usize;
21845
21846    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21847}
21848
21849impl RowRangeExt for Range<MultiBufferRow> {
21850    type Row = MultiBufferRow;
21851
21852    fn len(&self) -> usize {
21853        (self.end.0 - self.start.0) as usize
21854    }
21855
21856    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21857        (self.start.0..self.end.0).map(MultiBufferRow)
21858    }
21859}
21860
21861impl RowRangeExt for Range<DisplayRow> {
21862    type Row = DisplayRow;
21863
21864    fn len(&self) -> usize {
21865        (self.end.0 - self.start.0) as usize
21866    }
21867
21868    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21869        (self.start.0..self.end.0).map(DisplayRow)
21870    }
21871}
21872
21873/// If select range has more than one line, we
21874/// just point the cursor to range.start.
21875fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21876    if range.start.row == range.end.row {
21877        range
21878    } else {
21879        range.start..range.start
21880    }
21881}
21882pub struct KillRing(ClipboardItem);
21883impl Global for KillRing {}
21884
21885const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21886
21887enum BreakpointPromptEditAction {
21888    Log,
21889    Condition,
21890    HitCondition,
21891}
21892
21893struct BreakpointPromptEditor {
21894    pub(crate) prompt: Entity<Editor>,
21895    editor: WeakEntity<Editor>,
21896    breakpoint_anchor: Anchor,
21897    breakpoint: Breakpoint,
21898    edit_action: BreakpointPromptEditAction,
21899    block_ids: HashSet<CustomBlockId>,
21900    editor_margins: Arc<Mutex<EditorMargins>>,
21901    _subscriptions: Vec<Subscription>,
21902}
21903
21904impl BreakpointPromptEditor {
21905    const MAX_LINES: u8 = 4;
21906
21907    fn new(
21908        editor: WeakEntity<Editor>,
21909        breakpoint_anchor: Anchor,
21910        breakpoint: Breakpoint,
21911        edit_action: BreakpointPromptEditAction,
21912        window: &mut Window,
21913        cx: &mut Context<Self>,
21914    ) -> Self {
21915        let base_text = match edit_action {
21916            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21917            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21918            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21919        }
21920        .map(|msg| msg.to_string())
21921        .unwrap_or_default();
21922
21923        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21924        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21925
21926        let prompt = cx.new(|cx| {
21927            let mut prompt = Editor::new(
21928                EditorMode::AutoHeight {
21929                    max_lines: Self::MAX_LINES as usize,
21930                },
21931                buffer,
21932                None,
21933                window,
21934                cx,
21935            );
21936            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21937            prompt.set_show_cursor_when_unfocused(false, cx);
21938            prompt.set_placeholder_text(
21939                match edit_action {
21940                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21941                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21942                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21943                },
21944                cx,
21945            );
21946
21947            prompt
21948        });
21949
21950        Self {
21951            prompt,
21952            editor,
21953            breakpoint_anchor,
21954            breakpoint,
21955            edit_action,
21956            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21957            block_ids: Default::default(),
21958            _subscriptions: vec![],
21959        }
21960    }
21961
21962    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21963        self.block_ids.extend(block_ids)
21964    }
21965
21966    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21967        if let Some(editor) = self.editor.upgrade() {
21968            let message = self
21969                .prompt
21970                .read(cx)
21971                .buffer
21972                .read(cx)
21973                .as_singleton()
21974                .expect("A multi buffer in breakpoint prompt isn't possible")
21975                .read(cx)
21976                .as_rope()
21977                .to_string();
21978
21979            editor.update(cx, |editor, cx| {
21980                editor.edit_breakpoint_at_anchor(
21981                    self.breakpoint_anchor,
21982                    self.breakpoint.clone(),
21983                    match self.edit_action {
21984                        BreakpointPromptEditAction::Log => {
21985                            BreakpointEditAction::EditLogMessage(message.into())
21986                        }
21987                        BreakpointPromptEditAction::Condition => {
21988                            BreakpointEditAction::EditCondition(message.into())
21989                        }
21990                        BreakpointPromptEditAction::HitCondition => {
21991                            BreakpointEditAction::EditHitCondition(message.into())
21992                        }
21993                    },
21994                    cx,
21995                );
21996
21997                editor.remove_blocks(self.block_ids.clone(), None, cx);
21998                cx.focus_self(window);
21999            });
22000        }
22001    }
22002
22003    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22004        self.editor
22005            .update(cx, |editor, cx| {
22006                editor.remove_blocks(self.block_ids.clone(), None, cx);
22007                window.focus(&editor.focus_handle);
22008            })
22009            .log_err();
22010    }
22011
22012    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22013        let settings = ThemeSettings::get_global(cx);
22014        let text_style = TextStyle {
22015            color: if self.prompt.read(cx).read_only(cx) {
22016                cx.theme().colors().text_disabled
22017            } else {
22018                cx.theme().colors().text
22019            },
22020            font_family: settings.buffer_font.family.clone(),
22021            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22022            font_size: settings.buffer_font_size(cx).into(),
22023            font_weight: settings.buffer_font.weight,
22024            line_height: relative(settings.buffer_line_height.value()),
22025            ..Default::default()
22026        };
22027        EditorElement::new(
22028            &self.prompt,
22029            EditorStyle {
22030                background: cx.theme().colors().editor_background,
22031                local_player: cx.theme().players().local(),
22032                text: text_style,
22033                ..Default::default()
22034            },
22035        )
22036    }
22037}
22038
22039impl Render for BreakpointPromptEditor {
22040    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22041        let editor_margins = *self.editor_margins.lock();
22042        let gutter_dimensions = editor_margins.gutter;
22043        h_flex()
22044            .key_context("Editor")
22045            .bg(cx.theme().colors().editor_background)
22046            .border_y_1()
22047            .border_color(cx.theme().status().info_border)
22048            .size_full()
22049            .py(window.line_height() / 2.5)
22050            .on_action(cx.listener(Self::confirm))
22051            .on_action(cx.listener(Self::cancel))
22052            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22053            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22054    }
22055}
22056
22057impl Focusable for BreakpointPromptEditor {
22058    fn focus_handle(&self, cx: &App) -> FocusHandle {
22059        self.prompt.focus_handle(cx)
22060    }
22061}
22062
22063fn all_edits_insertions_or_deletions(
22064    edits: &Vec<(Range<Anchor>, String)>,
22065    snapshot: &MultiBufferSnapshot,
22066) -> bool {
22067    let mut all_insertions = true;
22068    let mut all_deletions = true;
22069
22070    for (range, new_text) in edits.iter() {
22071        let range_is_empty = range.to_offset(&snapshot).is_empty();
22072        let text_is_empty = new_text.is_empty();
22073
22074        if range_is_empty != text_is_empty {
22075            if range_is_empty {
22076                all_deletions = false;
22077            } else {
22078                all_insertions = false;
22079            }
22080        } else {
22081            return false;
22082        }
22083
22084        if !all_insertions && !all_deletions {
22085            return false;
22086        }
22087    }
22088    all_insertions || all_deletions
22089}
22090
22091struct MissingEditPredictionKeybindingTooltip;
22092
22093impl Render for MissingEditPredictionKeybindingTooltip {
22094    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22095        ui::tooltip_container(window, cx, |container, _, cx| {
22096            container
22097                .flex_shrink_0()
22098                .max_w_80()
22099                .min_h(rems_from_px(124.))
22100                .justify_between()
22101                .child(
22102                    v_flex()
22103                        .flex_1()
22104                        .text_ui_sm(cx)
22105                        .child(Label::new("Conflict with Accept Keybinding"))
22106                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22107                )
22108                .child(
22109                    h_flex()
22110                        .pb_1()
22111                        .gap_1()
22112                        .items_end()
22113                        .w_full()
22114                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22115                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22116                        }))
22117                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22118                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22119                        })),
22120                )
22121        })
22122    }
22123}
22124
22125#[derive(Debug, Clone, Copy, PartialEq)]
22126pub struct LineHighlight {
22127    pub background: Background,
22128    pub border: Option<gpui::Hsla>,
22129    pub include_gutter: bool,
22130    pub type_id: Option<TypeId>,
22131}
22132
22133fn render_diff_hunk_controls(
22134    row: u32,
22135    status: &DiffHunkStatus,
22136    hunk_range: Range<Anchor>,
22137    is_created_file: bool,
22138    line_height: Pixels,
22139    editor: &Entity<Editor>,
22140    _window: &mut Window,
22141    cx: &mut App,
22142) -> AnyElement {
22143    h_flex()
22144        .h(line_height)
22145        .mr_1()
22146        .gap_1()
22147        .px_0p5()
22148        .pb_1()
22149        .border_x_1()
22150        .border_b_1()
22151        .border_color(cx.theme().colors().border_variant)
22152        .rounded_b_lg()
22153        .bg(cx.theme().colors().editor_background)
22154        .gap_1()
22155        .block_mouse_except_scroll()
22156        .shadow_md()
22157        .child(if status.has_secondary_hunk() {
22158            Button::new(("stage", row as u64), "Stage")
22159                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22160                .tooltip({
22161                    let focus_handle = editor.focus_handle(cx);
22162                    move |window, cx| {
22163                        Tooltip::for_action_in(
22164                            "Stage Hunk",
22165                            &::git::ToggleStaged,
22166                            &focus_handle,
22167                            window,
22168                            cx,
22169                        )
22170                    }
22171                })
22172                .on_click({
22173                    let editor = editor.clone();
22174                    move |_event, _window, cx| {
22175                        editor.update(cx, |editor, cx| {
22176                            editor.stage_or_unstage_diff_hunks(
22177                                true,
22178                                vec![hunk_range.start..hunk_range.start],
22179                                cx,
22180                            );
22181                        });
22182                    }
22183                })
22184        } else {
22185            Button::new(("unstage", row as u64), "Unstage")
22186                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22187                .tooltip({
22188                    let focus_handle = editor.focus_handle(cx);
22189                    move |window, cx| {
22190                        Tooltip::for_action_in(
22191                            "Unstage Hunk",
22192                            &::git::ToggleStaged,
22193                            &focus_handle,
22194                            window,
22195                            cx,
22196                        )
22197                    }
22198                })
22199                .on_click({
22200                    let editor = editor.clone();
22201                    move |_event, _window, cx| {
22202                        editor.update(cx, |editor, cx| {
22203                            editor.stage_or_unstage_diff_hunks(
22204                                false,
22205                                vec![hunk_range.start..hunk_range.start],
22206                                cx,
22207                            );
22208                        });
22209                    }
22210                })
22211        })
22212        .child(
22213            Button::new(("restore", row as u64), "Restore")
22214                .tooltip({
22215                    let focus_handle = editor.focus_handle(cx);
22216                    move |window, cx| {
22217                        Tooltip::for_action_in(
22218                            "Restore Hunk",
22219                            &::git::Restore,
22220                            &focus_handle,
22221                            window,
22222                            cx,
22223                        )
22224                    }
22225                })
22226                .on_click({
22227                    let editor = editor.clone();
22228                    move |_event, window, cx| {
22229                        editor.update(cx, |editor, cx| {
22230                            let snapshot = editor.snapshot(window, cx);
22231                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22232                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22233                        });
22234                    }
22235                })
22236                .disabled(is_created_file),
22237        )
22238        .when(
22239            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22240            |el| {
22241                el.child(
22242                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22243                        .shape(IconButtonShape::Square)
22244                        .icon_size(IconSize::Small)
22245                        // .disabled(!has_multiple_hunks)
22246                        .tooltip({
22247                            let focus_handle = editor.focus_handle(cx);
22248                            move |window, cx| {
22249                                Tooltip::for_action_in(
22250                                    "Next Hunk",
22251                                    &GoToHunk,
22252                                    &focus_handle,
22253                                    window,
22254                                    cx,
22255                                )
22256                            }
22257                        })
22258                        .on_click({
22259                            let editor = editor.clone();
22260                            move |_event, window, cx| {
22261                                editor.update(cx, |editor, cx| {
22262                                    let snapshot = editor.snapshot(window, cx);
22263                                    let position =
22264                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22265                                    editor.go_to_hunk_before_or_after_position(
22266                                        &snapshot,
22267                                        position,
22268                                        Direction::Next,
22269                                        window,
22270                                        cx,
22271                                    );
22272                                    editor.expand_selected_diff_hunks(cx);
22273                                });
22274                            }
22275                        }),
22276                )
22277                .child(
22278                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
22279                        .shape(IconButtonShape::Square)
22280                        .icon_size(IconSize::Small)
22281                        // .disabled(!has_multiple_hunks)
22282                        .tooltip({
22283                            let focus_handle = editor.focus_handle(cx);
22284                            move |window, cx| {
22285                                Tooltip::for_action_in(
22286                                    "Previous Hunk",
22287                                    &GoToPreviousHunk,
22288                                    &focus_handle,
22289                                    window,
22290                                    cx,
22291                                )
22292                            }
22293                        })
22294                        .on_click({
22295                            let editor = editor.clone();
22296                            move |_event, window, cx| {
22297                                editor.update(cx, |editor, cx| {
22298                                    let snapshot = editor.snapshot(window, cx);
22299                                    let point =
22300                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
22301                                    editor.go_to_hunk_before_or_after_position(
22302                                        &snapshot,
22303                                        point,
22304                                        Direction::Prev,
22305                                        window,
22306                                        cx,
22307                                    );
22308                                    editor.expand_selected_diff_hunks(cx);
22309                                });
22310                            }
22311                        }),
22312                )
22313            },
22314        )
22315        .into_any_element()
22316}