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    fn insert_transaction(
 1225        &mut self,
 1226        transaction_id: TransactionId,
 1227        selections: Arc<[Selection<Anchor>]>,
 1228    ) {
 1229        self.selections_by_transaction
 1230            .insert(transaction_id, (selections, None));
 1231    }
 1232
 1233    #[allow(clippy::type_complexity)]
 1234    fn transaction(
 1235        &self,
 1236        transaction_id: TransactionId,
 1237    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1238        self.selections_by_transaction.get(&transaction_id)
 1239    }
 1240
 1241    #[allow(clippy::type_complexity)]
 1242    fn transaction_mut(
 1243        &mut self,
 1244        transaction_id: TransactionId,
 1245    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1246        self.selections_by_transaction.get_mut(&transaction_id)
 1247    }
 1248
 1249    fn push(&mut self, entry: SelectionHistoryEntry) {
 1250        if !entry.selections.is_empty() {
 1251            match self.mode {
 1252                SelectionHistoryMode::Normal => {
 1253                    self.push_undo(entry);
 1254                    self.redo_stack.clear();
 1255                }
 1256                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1257                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1258            }
 1259        }
 1260    }
 1261
 1262    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1263        if self
 1264            .undo_stack
 1265            .back()
 1266            .map_or(true, |e| e.selections != entry.selections)
 1267        {
 1268            self.undo_stack.push_back(entry);
 1269            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1270                self.undo_stack.pop_front();
 1271            }
 1272        }
 1273    }
 1274
 1275    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1276        if self
 1277            .redo_stack
 1278            .back()
 1279            .map_or(true, |e| e.selections != entry.selections)
 1280        {
 1281            self.redo_stack.push_back(entry);
 1282            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1283                self.redo_stack.pop_front();
 1284            }
 1285        }
 1286    }
 1287}
 1288
 1289#[derive(Clone, Copy)]
 1290pub struct RowHighlightOptions {
 1291    pub autoscroll: bool,
 1292    pub include_gutter: bool,
 1293}
 1294
 1295impl Default for RowHighlightOptions {
 1296    fn default() -> Self {
 1297        Self {
 1298            autoscroll: Default::default(),
 1299            include_gutter: true,
 1300        }
 1301    }
 1302}
 1303
 1304struct RowHighlight {
 1305    index: usize,
 1306    range: Range<Anchor>,
 1307    color: Hsla,
 1308    options: RowHighlightOptions,
 1309    type_id: TypeId,
 1310}
 1311
 1312#[derive(Clone, Debug)]
 1313struct AddSelectionsState {
 1314    above: bool,
 1315    stack: Vec<usize>,
 1316}
 1317
 1318#[derive(Clone)]
 1319struct SelectNextState {
 1320    query: AhoCorasick,
 1321    wordwise: bool,
 1322    done: bool,
 1323}
 1324
 1325impl std::fmt::Debug for SelectNextState {
 1326    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1327        f.debug_struct(std::any::type_name::<Self>())
 1328            .field("wordwise", &self.wordwise)
 1329            .field("done", &self.done)
 1330            .finish()
 1331    }
 1332}
 1333
 1334#[derive(Debug)]
 1335struct AutocloseRegion {
 1336    selection_id: usize,
 1337    range: Range<Anchor>,
 1338    pair: BracketPair,
 1339}
 1340
 1341#[derive(Debug)]
 1342struct SnippetState {
 1343    ranges: Vec<Vec<Range<Anchor>>>,
 1344    active_index: usize,
 1345    choices: Vec<Option<Vec<String>>>,
 1346}
 1347
 1348#[doc(hidden)]
 1349pub struct RenameState {
 1350    pub range: Range<Anchor>,
 1351    pub old_name: Arc<str>,
 1352    pub editor: Entity<Editor>,
 1353    block_id: CustomBlockId,
 1354}
 1355
 1356struct InvalidationStack<T>(Vec<T>);
 1357
 1358struct RegisteredInlineCompletionProvider {
 1359    provider: Arc<dyn InlineCompletionProviderHandle>,
 1360    _subscription: Subscription,
 1361}
 1362
 1363#[derive(Debug, PartialEq, Eq)]
 1364pub struct ActiveDiagnosticGroup {
 1365    pub active_range: Range<Anchor>,
 1366    pub active_message: String,
 1367    pub group_id: usize,
 1368    pub blocks: HashSet<CustomBlockId>,
 1369}
 1370
 1371#[derive(Debug, PartialEq, Eq)]
 1372
 1373pub(crate) enum ActiveDiagnostic {
 1374    None,
 1375    All,
 1376    Group(ActiveDiagnosticGroup),
 1377}
 1378
 1379#[derive(Serialize, Deserialize, Clone, Debug)]
 1380pub struct ClipboardSelection {
 1381    /// The number of bytes in this selection.
 1382    pub len: usize,
 1383    /// Whether this was a full-line selection.
 1384    pub is_entire_line: bool,
 1385    /// The indentation of the first line when this content was originally copied.
 1386    pub first_line_indent: u32,
 1387}
 1388
 1389// selections, scroll behavior, was newest selection reversed
 1390type SelectSyntaxNodeHistoryState = (
 1391    Box<[Selection<usize>]>,
 1392    SelectSyntaxNodeScrollBehavior,
 1393    bool,
 1394);
 1395
 1396#[derive(Default)]
 1397struct SelectSyntaxNodeHistory {
 1398    stack: Vec<SelectSyntaxNodeHistoryState>,
 1399    // disable temporarily to allow changing selections without losing the stack
 1400    pub disable_clearing: bool,
 1401}
 1402
 1403impl SelectSyntaxNodeHistory {
 1404    pub fn try_clear(&mut self) {
 1405        if !self.disable_clearing {
 1406            self.stack.clear();
 1407        }
 1408    }
 1409
 1410    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1411        self.stack.push(selection);
 1412    }
 1413
 1414    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1415        self.stack.pop()
 1416    }
 1417}
 1418
 1419enum SelectSyntaxNodeScrollBehavior {
 1420    CursorTop,
 1421    FitSelection,
 1422    CursorBottom,
 1423}
 1424
 1425#[derive(Debug)]
 1426pub(crate) struct NavigationData {
 1427    cursor_anchor: Anchor,
 1428    cursor_position: Point,
 1429    scroll_anchor: ScrollAnchor,
 1430    scroll_top_row: u32,
 1431}
 1432
 1433#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1434pub enum GotoDefinitionKind {
 1435    Symbol,
 1436    Declaration,
 1437    Type,
 1438    Implementation,
 1439}
 1440
 1441#[derive(Debug, Clone)]
 1442enum InlayHintRefreshReason {
 1443    ModifiersChanged(bool),
 1444    Toggle(bool),
 1445    SettingsChange(InlayHintSettings),
 1446    NewLinesShown,
 1447    BufferEdited(HashSet<Arc<Language>>),
 1448    RefreshRequested,
 1449    ExcerptsRemoved(Vec<ExcerptId>),
 1450}
 1451
 1452impl InlayHintRefreshReason {
 1453    fn description(&self) -> &'static str {
 1454        match self {
 1455            Self::ModifiersChanged(_) => "modifiers changed",
 1456            Self::Toggle(_) => "toggle",
 1457            Self::SettingsChange(_) => "settings change",
 1458            Self::NewLinesShown => "new lines shown",
 1459            Self::BufferEdited(_) => "buffer edited",
 1460            Self::RefreshRequested => "refresh requested",
 1461            Self::ExcerptsRemoved(_) => "excerpts removed",
 1462        }
 1463    }
 1464}
 1465
 1466pub enum FormatTarget {
 1467    Buffers,
 1468    Ranges(Vec<Range<MultiBufferPoint>>),
 1469}
 1470
 1471pub(crate) struct FocusedBlock {
 1472    id: BlockId,
 1473    focus_handle: WeakFocusHandle,
 1474}
 1475
 1476#[derive(Clone)]
 1477enum JumpData {
 1478    MultiBufferRow {
 1479        row: MultiBufferRow,
 1480        line_offset_from_top: u32,
 1481    },
 1482    MultiBufferPoint {
 1483        excerpt_id: ExcerptId,
 1484        position: Point,
 1485        anchor: text::Anchor,
 1486        line_offset_from_top: u32,
 1487    },
 1488}
 1489
 1490pub enum MultibufferSelectionMode {
 1491    First,
 1492    All,
 1493}
 1494
 1495#[derive(Clone, Copy, Debug, Default)]
 1496pub struct RewrapOptions {
 1497    pub override_language_settings: bool,
 1498    pub preserve_existing_whitespace: bool,
 1499}
 1500
 1501impl Editor {
 1502    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1503        let buffer = cx.new(|cx| Buffer::local("", cx));
 1504        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1505        Self::new(
 1506            EditorMode::SingleLine { auto_width: false },
 1507            buffer,
 1508            None,
 1509            window,
 1510            cx,
 1511        )
 1512    }
 1513
 1514    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1515        let buffer = cx.new(|cx| Buffer::local("", cx));
 1516        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1517        Self::new(EditorMode::full(), buffer, None, window, cx)
 1518    }
 1519
 1520    pub fn auto_width(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1521        let buffer = cx.new(|cx| Buffer::local("", cx));
 1522        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1523        Self::new(
 1524            EditorMode::SingleLine { auto_width: true },
 1525            buffer,
 1526            None,
 1527            window,
 1528            cx,
 1529        )
 1530    }
 1531
 1532    pub fn auto_height(max_lines: usize, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1533        let buffer = cx.new(|cx| Buffer::local("", cx));
 1534        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1535        Self::new(
 1536            EditorMode::AutoHeight { max_lines },
 1537            buffer,
 1538            None,
 1539            window,
 1540            cx,
 1541        )
 1542    }
 1543
 1544    pub fn for_buffer(
 1545        buffer: Entity<Buffer>,
 1546        project: Option<Entity<Project>>,
 1547        window: &mut Window,
 1548        cx: &mut Context<Self>,
 1549    ) -> Self {
 1550        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1551        Self::new(EditorMode::full(), buffer, project, window, cx)
 1552    }
 1553
 1554    pub fn for_multibuffer(
 1555        buffer: Entity<MultiBuffer>,
 1556        project: Option<Entity<Project>>,
 1557        window: &mut Window,
 1558        cx: &mut Context<Self>,
 1559    ) -> Self {
 1560        Self::new(EditorMode::full(), buffer, project, window, cx)
 1561    }
 1562
 1563    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1564        let mut clone = Self::new(
 1565            self.mode.clone(),
 1566            self.buffer.clone(),
 1567            self.project.clone(),
 1568            window,
 1569            cx,
 1570        );
 1571        self.display_map.update(cx, |display_map, cx| {
 1572            let snapshot = display_map.snapshot(cx);
 1573            clone.display_map.update(cx, |display_map, cx| {
 1574                display_map.set_state(&snapshot, cx);
 1575            });
 1576        });
 1577        clone.folds_did_change(cx);
 1578        clone.selections.clone_state(&self.selections);
 1579        clone.scroll_manager.clone_state(&self.scroll_manager);
 1580        clone.searchable = self.searchable;
 1581        clone.read_only = self.read_only;
 1582        clone
 1583    }
 1584
 1585    pub fn new(
 1586        mode: EditorMode,
 1587        buffer: Entity<MultiBuffer>,
 1588        project: Option<Entity<Project>>,
 1589        window: &mut Window,
 1590        cx: &mut Context<Self>,
 1591    ) -> Self {
 1592        Editor::new_internal(mode, buffer, project, None, window, cx)
 1593    }
 1594
 1595    fn new_internal(
 1596        mode: EditorMode,
 1597        buffer: Entity<MultiBuffer>,
 1598        project: Option<Entity<Project>>,
 1599        display_map: Option<Entity<DisplayMap>>,
 1600        window: &mut Window,
 1601        cx: &mut Context<Self>,
 1602    ) -> Self {
 1603        debug_assert!(
 1604            display_map.is_none() || mode.is_minimap(),
 1605            "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!"
 1606        );
 1607
 1608        let full_mode = mode.is_full();
 1609        let diagnostics_max_severity = if full_mode {
 1610            EditorSettings::get_global(cx)
 1611                .diagnostics_max_severity
 1612                .unwrap_or(DiagnosticSeverity::Hint)
 1613        } else {
 1614            DiagnosticSeverity::Off
 1615        };
 1616        let style = window.text_style();
 1617        let font_size = style.font_size.to_pixels(window.rem_size());
 1618        let editor = cx.entity().downgrade();
 1619        let fold_placeholder = FoldPlaceholder {
 1620            constrain_width: true,
 1621            render: Arc::new(move |fold_id, fold_range, cx| {
 1622                let editor = editor.clone();
 1623                div()
 1624                    .id(fold_id)
 1625                    .bg(cx.theme().colors().ghost_element_background)
 1626                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1627                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1628                    .rounded_xs()
 1629                    .size_full()
 1630                    .cursor_pointer()
 1631                    .child("")
 1632                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1633                    .on_click(move |_, _window, cx| {
 1634                        editor
 1635                            .update(cx, |editor, cx| {
 1636                                editor.unfold_ranges(
 1637                                    &[fold_range.start..fold_range.end],
 1638                                    true,
 1639                                    false,
 1640                                    cx,
 1641                                );
 1642                                cx.stop_propagation();
 1643                            })
 1644                            .ok();
 1645                    })
 1646                    .into_any()
 1647            }),
 1648            merge_adjacent: true,
 1649            ..FoldPlaceholder::default()
 1650        };
 1651        let display_map = display_map.unwrap_or_else(|| {
 1652            cx.new(|cx| {
 1653                DisplayMap::new(
 1654                    buffer.clone(),
 1655                    style.font(),
 1656                    font_size,
 1657                    None,
 1658                    FILE_HEADER_HEIGHT,
 1659                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1660                    fold_placeholder,
 1661                    diagnostics_max_severity,
 1662                    cx,
 1663                )
 1664            })
 1665        });
 1666
 1667        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1668
 1669        let blink_manager = cx.new(|cx| BlinkManager::new(CURSOR_BLINK_INTERVAL, cx));
 1670
 1671        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1672            .then(|| language_settings::SoftWrap::None);
 1673
 1674        let mut project_subscriptions = Vec::new();
 1675        if mode.is_full() {
 1676            if let Some(project) = project.as_ref() {
 1677                project_subscriptions.push(cx.subscribe_in(
 1678                    project,
 1679                    window,
 1680                    |editor, _, event, window, cx| match event {
 1681                        project::Event::RefreshCodeLens => {
 1682                            // we always query lens with actions, without storing them, always refreshing them
 1683                        }
 1684                        project::Event::RefreshInlayHints => {
 1685                            editor
 1686                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1687                        }
 1688                        project::Event::LanguageServerAdded(..)
 1689                        | project::Event::LanguageServerRemoved(..) => {
 1690                            if editor.tasks_update_task.is_none() {
 1691                                editor.tasks_update_task =
 1692                                    Some(editor.refresh_runnables(window, cx));
 1693                            }
 1694                        }
 1695                        project::Event::SnippetEdit(id, snippet_edits) => {
 1696                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1697                                let focus_handle = editor.focus_handle(cx);
 1698                                if focus_handle.is_focused(window) {
 1699                                    let snapshot = buffer.read(cx).snapshot();
 1700                                    for (range, snippet) in snippet_edits {
 1701                                        let editor_range =
 1702                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1703                                        editor
 1704                                            .insert_snippet(
 1705                                                &[editor_range],
 1706                                                snippet.clone(),
 1707                                                window,
 1708                                                cx,
 1709                                            )
 1710                                            .ok();
 1711                                    }
 1712                                }
 1713                            }
 1714                        }
 1715                        _ => {}
 1716                    },
 1717                ));
 1718                if let Some(task_inventory) = project
 1719                    .read(cx)
 1720                    .task_store()
 1721                    .read(cx)
 1722                    .task_inventory()
 1723                    .cloned()
 1724                {
 1725                    project_subscriptions.push(cx.observe_in(
 1726                        &task_inventory,
 1727                        window,
 1728                        |editor, _, window, cx| {
 1729                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1730                        },
 1731                    ));
 1732                };
 1733
 1734                project_subscriptions.push(cx.subscribe_in(
 1735                    &project.read(cx).breakpoint_store(),
 1736                    window,
 1737                    |editor, _, event, window, cx| match event {
 1738                        BreakpointStoreEvent::ClearDebugLines => {
 1739                            editor.clear_row_highlights::<ActiveDebugLine>();
 1740                            editor.refresh_inline_values(cx);
 1741                        }
 1742                        BreakpointStoreEvent::SetDebugLine => {
 1743                            if editor.go_to_active_debug_line(window, cx) {
 1744                                cx.stop_propagation();
 1745                            }
 1746
 1747                            editor.refresh_inline_values(cx);
 1748                        }
 1749                        _ => {}
 1750                    },
 1751                ));
 1752            }
 1753        }
 1754
 1755        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1756
 1757        let inlay_hint_settings =
 1758            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1759        let focus_handle = cx.focus_handle();
 1760        cx.on_focus(&focus_handle, window, Self::handle_focus)
 1761            .detach();
 1762        cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1763            .detach();
 1764        cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1765            .detach();
 1766        cx.on_blur(&focus_handle, window, Self::handle_blur)
 1767            .detach();
 1768
 1769        let show_indent_guides = if matches!(mode, EditorMode::SingleLine { .. }) {
 1770            Some(false)
 1771        } else {
 1772            None
 1773        };
 1774
 1775        let breakpoint_store = match (&mode, project.as_ref()) {
 1776            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1777            _ => None,
 1778        };
 1779
 1780        let mut code_action_providers = Vec::new();
 1781        let mut load_uncommitted_diff = None;
 1782        if let Some(project) = project.clone() {
 1783            load_uncommitted_diff = Some(
 1784                update_uncommitted_diff_for_buffer(
 1785                    cx.entity(),
 1786                    &project,
 1787                    buffer.read(cx).all_buffers(),
 1788                    buffer.clone(),
 1789                    cx,
 1790                )
 1791                .shared(),
 1792            );
 1793            code_action_providers.push(Rc::new(project) as Rc<_>);
 1794        }
 1795
 1796        let mut this = Self {
 1797            focus_handle,
 1798            show_cursor_when_unfocused: false,
 1799            last_focused_descendant: None,
 1800            buffer: buffer.clone(),
 1801            display_map: display_map.clone(),
 1802            selections,
 1803            scroll_manager: ScrollManager::new(cx),
 1804            columnar_selection_tail: None,
 1805            columnar_display_point: None,
 1806            add_selections_state: None,
 1807            select_next_state: None,
 1808            select_prev_state: None,
 1809            selection_history: SelectionHistory::default(),
 1810            defer_selection_effects: false,
 1811            deferred_selection_effects_state: None,
 1812            autoclose_regions: Vec::new(),
 1813            snippet_stack: InvalidationStack::default(),
 1814            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 1815            ime_transaction: None,
 1816            active_diagnostics: ActiveDiagnostic::None,
 1817            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 1818            inline_diagnostics_update: Task::ready(()),
 1819            inline_diagnostics: Vec::new(),
 1820            soft_wrap_mode_override,
 1821            diagnostics_max_severity,
 1822            hard_wrap: None,
 1823            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 1824            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 1825            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 1826            project,
 1827            blink_manager: blink_manager.clone(),
 1828            show_local_selections: true,
 1829            show_scrollbars: ScrollbarAxes {
 1830                horizontal: full_mode,
 1831                vertical: full_mode,
 1832            },
 1833            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 1834            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 1835            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 1836            show_gutter: mode.is_full(),
 1837            show_line_numbers: None,
 1838            use_relative_line_numbers: None,
 1839            disable_expand_excerpt_buttons: false,
 1840            show_git_diff_gutter: None,
 1841            show_code_actions: None,
 1842            show_runnables: None,
 1843            show_breakpoints: None,
 1844            show_wrap_guides: None,
 1845            show_indent_guides,
 1846            placeholder_text: None,
 1847            highlight_order: 0,
 1848            highlighted_rows: HashMap::default(),
 1849            background_highlights: TreeMap::default(),
 1850            gutter_highlights: TreeMap::default(),
 1851            scrollbar_marker_state: ScrollbarMarkerState::default(),
 1852            active_indent_guides_state: ActiveIndentGuidesState::default(),
 1853            nav_history: None,
 1854            context_menu: RefCell::new(None),
 1855            context_menu_options: None,
 1856            mouse_context_menu: None,
 1857            completion_tasks: Vec::new(),
 1858            inline_blame_popover: None,
 1859            signature_help_state: SignatureHelpState::default(),
 1860            auto_signature_help: None,
 1861            find_all_references_task_sources: Vec::new(),
 1862            next_completion_id: 0,
 1863            next_inlay_id: 0,
 1864            code_action_providers,
 1865            available_code_actions: None,
 1866            code_actions_task: None,
 1867            quick_selection_highlight_task: None,
 1868            debounced_selection_highlight_task: None,
 1869            document_highlights_task: None,
 1870            linked_editing_range_task: None,
 1871            pending_rename: None,
 1872            searchable: true,
 1873            cursor_shape: EditorSettings::get_global(cx)
 1874                .cursor_shape
 1875                .unwrap_or_default(),
 1876            current_line_highlight: None,
 1877            autoindent_mode: Some(AutoindentMode::EachLine),
 1878            collapse_matches: false,
 1879            workspace: None,
 1880            input_enabled: true,
 1881            use_modal_editing: mode.is_full(),
 1882            read_only: mode.is_minimap(),
 1883            use_autoclose: true,
 1884            use_auto_surround: true,
 1885            auto_replace_emoji_shortcode: false,
 1886            jsx_tag_auto_close_enabled_in_any_buffer: false,
 1887            leader_id: None,
 1888            remote_id: None,
 1889            hover_state: HoverState::default(),
 1890            pending_mouse_down: None,
 1891            hovered_link_state: None,
 1892            edit_prediction_provider: None,
 1893            active_inline_completion: None,
 1894            stale_inline_completion_in_menu: None,
 1895            edit_prediction_preview: EditPredictionPreview::Inactive {
 1896                released_too_fast: false,
 1897            },
 1898            inline_diagnostics_enabled: mode.is_full(),
 1899            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 1900            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 1901
 1902            gutter_hovered: false,
 1903            pixel_position_of_newest_cursor: None,
 1904            last_bounds: None,
 1905            last_position_map: None,
 1906            expect_bounds_change: None,
 1907            gutter_dimensions: GutterDimensions::default(),
 1908            style: None,
 1909            show_cursor_names: false,
 1910            hovered_cursors: HashMap::default(),
 1911            next_editor_action_id: EditorActionId::default(),
 1912            editor_actions: Rc::default(),
 1913            inline_completions_hidden_for_vim_mode: false,
 1914            show_inline_completions_override: None,
 1915            menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider,
 1916            edit_prediction_settings: EditPredictionSettings::Disabled,
 1917            edit_prediction_indent_conflict: false,
 1918            edit_prediction_requires_modifier_in_indent_conflict: true,
 1919            custom_context_menu: None,
 1920            show_git_blame_gutter: false,
 1921            show_git_blame_inline: false,
 1922            show_selection_menu: None,
 1923            show_git_blame_inline_delay_task: None,
 1924            git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 1925            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 1926            serialize_dirty_buffers: !mode.is_minimap()
 1927                && ProjectSettings::get_global(cx)
 1928                    .session
 1929                    .restore_unsaved_buffers,
 1930            blame: None,
 1931            blame_subscription: None,
 1932            tasks: BTreeMap::default(),
 1933
 1934            breakpoint_store,
 1935            gutter_breakpoint_indicator: (None, None),
 1936            _subscriptions: vec![
 1937                cx.observe(&buffer, Self::on_buffer_changed),
 1938                cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 1939                cx.observe_in(&display_map, window, Self::on_display_map_changed),
 1940                cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 1941                cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 1942                observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 1943                cx.observe_window_activation(window, |editor, window, cx| {
 1944                    let active = window.is_window_active();
 1945                    editor.blink_manager.update(cx, |blink_manager, cx| {
 1946                        if active {
 1947                            blink_manager.enable(cx);
 1948                        } else {
 1949                            blink_manager.disable(cx);
 1950                        }
 1951                    });
 1952                    if active {
 1953                        editor.show_mouse_cursor();
 1954                    }
 1955                }),
 1956            ],
 1957            tasks_update_task: None,
 1958            linked_edit_ranges: Default::default(),
 1959            in_project_search: false,
 1960            previous_search_ranges: None,
 1961            breadcrumb_header: None,
 1962            focused_block: None,
 1963            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 1964            addons: HashMap::default(),
 1965            registered_buffers: HashMap::default(),
 1966            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 1967            selection_mark_mode: false,
 1968            toggle_fold_multiple_buffers: Task::ready(()),
 1969            serialize_selections: Task::ready(()),
 1970            serialize_folds: Task::ready(()),
 1971            text_style_refinement: None,
 1972            load_diff_task: load_uncommitted_diff,
 1973            temporary_diff_override: false,
 1974            mouse_cursor_hidden: false,
 1975            minimap: None,
 1976            hide_mouse_mode: EditorSettings::get_global(cx)
 1977                .hide_mouse
 1978                .unwrap_or_default(),
 1979            change_list: ChangeList::new(),
 1980            mode,
 1981        };
 1982        if let Some(breakpoints) = this.breakpoint_store.as_ref() {
 1983            this._subscriptions
 1984                .push(cx.observe(breakpoints, |_, _, cx| {
 1985                    cx.notify();
 1986                }));
 1987        }
 1988        this.tasks_update_task = Some(this.refresh_runnables(window, cx));
 1989        this._subscriptions.extend(project_subscriptions);
 1990
 1991        this._subscriptions.push(cx.subscribe_in(
 1992            &cx.entity(),
 1993            window,
 1994            |editor, _, e: &EditorEvent, window, cx| match e {
 1995                EditorEvent::ScrollPositionChanged { local, .. } => {
 1996                    if *local {
 1997                        let new_anchor = editor.scroll_manager.anchor();
 1998                        let snapshot = editor.snapshot(window, cx);
 1999                        editor.update_restoration_data(cx, move |data| {
 2000                            data.scroll_position = (
 2001                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2002                                new_anchor.offset,
 2003                            );
 2004                        });
 2005                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2006                        editor.inline_blame_popover.take();
 2007                    }
 2008                }
 2009                EditorEvent::Edited { .. } => {
 2010                    if !vim_enabled(cx) {
 2011                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2012                        let pop_state = editor
 2013                            .change_list
 2014                            .last()
 2015                            .map(|previous| {
 2016                                previous.len() == selections.len()
 2017                                    && previous.iter().enumerate().all(|(ix, p)| {
 2018                                        p.to_display_point(&map).row()
 2019                                            == selections[ix].head().row()
 2020                                    })
 2021                            })
 2022                            .unwrap_or(false);
 2023                        let new_positions = selections
 2024                            .into_iter()
 2025                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2026                            .collect();
 2027                        editor
 2028                            .change_list
 2029                            .push_to_change_list(pop_state, new_positions);
 2030                    }
 2031                }
 2032                _ => (),
 2033            },
 2034        ));
 2035
 2036        if let Some(dap_store) = this
 2037            .project
 2038            .as_ref()
 2039            .map(|project| project.read(cx).dap_store())
 2040        {
 2041            let weak_editor = cx.weak_entity();
 2042
 2043            this._subscriptions
 2044                .push(
 2045                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2046                        let session_entity = cx.entity();
 2047                        weak_editor
 2048                            .update(cx, |editor, cx| {
 2049                                editor._subscriptions.push(
 2050                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2051                                );
 2052                            })
 2053                            .ok();
 2054                    }),
 2055                );
 2056
 2057            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2058                this._subscriptions
 2059                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2060            }
 2061        }
 2062
 2063        this.end_selection(window, cx);
 2064        this.scroll_manager.show_scrollbars(window, cx);
 2065        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut this, &buffer, cx);
 2066
 2067        if full_mode {
 2068            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2069            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2070
 2071            if this.git_blame_inline_enabled {
 2072                this.start_git_blame_inline(false, window, cx);
 2073            }
 2074
 2075            this.go_to_active_debug_line(window, cx);
 2076
 2077            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2078                if let Some(project) = this.project.as_ref() {
 2079                    let handle = project.update(cx, |project, cx| {
 2080                        project.register_buffer_with_language_servers(&buffer, cx)
 2081                    });
 2082                    this.registered_buffers
 2083                        .insert(buffer.read(cx).remote_id(), handle);
 2084                }
 2085            }
 2086
 2087            this.minimap = this.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2088        }
 2089
 2090        this.report_editor_event("Editor Opened", None, cx);
 2091        this
 2092    }
 2093
 2094    pub fn deploy_mouse_context_menu(
 2095        &mut self,
 2096        position: gpui::Point<Pixels>,
 2097        context_menu: Entity<ContextMenu>,
 2098        window: &mut Window,
 2099        cx: &mut Context<Self>,
 2100    ) {
 2101        self.mouse_context_menu = Some(MouseContextMenu::new(
 2102            self,
 2103            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2104            context_menu,
 2105            window,
 2106            cx,
 2107        ));
 2108    }
 2109
 2110    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2111        self.mouse_context_menu
 2112            .as_ref()
 2113            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2114    }
 2115
 2116    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2117        self.key_context_internal(self.has_active_inline_completion(), window, cx)
 2118    }
 2119
 2120    fn key_context_internal(
 2121        &self,
 2122        has_active_edit_prediction: bool,
 2123        window: &Window,
 2124        cx: &App,
 2125    ) -> KeyContext {
 2126        let mut key_context = KeyContext::new_with_defaults();
 2127        key_context.add("Editor");
 2128        let mode = match self.mode {
 2129            EditorMode::SingleLine { .. } => "single_line",
 2130            EditorMode::AutoHeight { .. } => "auto_height",
 2131            EditorMode::Minimap { .. } => "minimap",
 2132            EditorMode::Full { .. } => "full",
 2133        };
 2134
 2135        if EditorSettings::jupyter_enabled(cx) {
 2136            key_context.add("jupyter");
 2137        }
 2138
 2139        key_context.set("mode", mode);
 2140        if self.pending_rename.is_some() {
 2141            key_context.add("renaming");
 2142        }
 2143
 2144        match self.context_menu.borrow().as_ref() {
 2145            Some(CodeContextMenu::Completions(_)) => {
 2146                key_context.add("menu");
 2147                key_context.add("showing_completions");
 2148            }
 2149            Some(CodeContextMenu::CodeActions(_)) => {
 2150                key_context.add("menu");
 2151                key_context.add("showing_code_actions")
 2152            }
 2153            None => {}
 2154        }
 2155
 2156        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2157        if !self.focus_handle(cx).contains_focused(window, cx)
 2158            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2159        {
 2160            for addon in self.addons.values() {
 2161                addon.extend_key_context(&mut key_context, cx)
 2162            }
 2163        }
 2164
 2165        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2166            if let Some(extension) = singleton_buffer
 2167                .read(cx)
 2168                .file()
 2169                .and_then(|file| file.path().extension()?.to_str())
 2170            {
 2171                key_context.set("extension", extension.to_string());
 2172            }
 2173        } else {
 2174            key_context.add("multibuffer");
 2175        }
 2176
 2177        if has_active_edit_prediction {
 2178            if self.edit_prediction_in_conflict() {
 2179                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2180            } else {
 2181                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2182                key_context.add("copilot_suggestion");
 2183            }
 2184        }
 2185
 2186        if self.selection_mark_mode {
 2187            key_context.add("selection_mode");
 2188        }
 2189
 2190        key_context
 2191    }
 2192
 2193    fn show_mouse_cursor(&mut self) {
 2194        self.mouse_cursor_hidden = false;
 2195    }
 2196
 2197    pub fn hide_mouse_cursor(&mut self, origin: &HideMouseCursorOrigin) {
 2198        self.mouse_cursor_hidden = match origin {
 2199            HideMouseCursorOrigin::TypingAction => {
 2200                matches!(
 2201                    self.hide_mouse_mode,
 2202                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2203                )
 2204            }
 2205            HideMouseCursorOrigin::MovementAction => {
 2206                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2207            }
 2208        };
 2209    }
 2210
 2211    pub fn edit_prediction_in_conflict(&self) -> bool {
 2212        if !self.show_edit_predictions_in_menu() {
 2213            return false;
 2214        }
 2215
 2216        let showing_completions = self
 2217            .context_menu
 2218            .borrow()
 2219            .as_ref()
 2220            .map_or(false, |context| {
 2221                matches!(context, CodeContextMenu::Completions(_))
 2222            });
 2223
 2224        showing_completions
 2225            || self.edit_prediction_requires_modifier()
 2226            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2227            // bindings to insert tab characters.
 2228            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2229    }
 2230
 2231    pub fn accept_edit_prediction_keybind(
 2232        &self,
 2233        window: &Window,
 2234        cx: &App,
 2235    ) -> AcceptEditPredictionBinding {
 2236        let key_context = self.key_context_internal(true, window, cx);
 2237        let in_conflict = self.edit_prediction_in_conflict();
 2238
 2239        AcceptEditPredictionBinding(
 2240            window
 2241                .bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2242                .into_iter()
 2243                .filter(|binding| {
 2244                    !in_conflict
 2245                        || binding
 2246                            .keystrokes()
 2247                            .first()
 2248                            .map_or(false, |keystroke| keystroke.modifiers.modified())
 2249                })
 2250                .rev()
 2251                .min_by_key(|binding| {
 2252                    binding
 2253                        .keystrokes()
 2254                        .first()
 2255                        .map_or(u8::MAX, |k| k.modifiers.number_of_modifiers())
 2256                }),
 2257        )
 2258    }
 2259
 2260    pub fn new_file(
 2261        workspace: &mut Workspace,
 2262        _: &workspace::NewFile,
 2263        window: &mut Window,
 2264        cx: &mut Context<Workspace>,
 2265    ) {
 2266        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2267            "Failed to create buffer",
 2268            window,
 2269            cx,
 2270            |e, _, _| match e.error_code() {
 2271                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2272                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2273                e.error_tag("required").unwrap_or("the latest version")
 2274            )),
 2275                _ => None,
 2276            },
 2277        );
 2278    }
 2279
 2280    pub fn new_in_workspace(
 2281        workspace: &mut Workspace,
 2282        window: &mut Window,
 2283        cx: &mut Context<Workspace>,
 2284    ) -> Task<Result<Entity<Editor>>> {
 2285        let project = workspace.project().clone();
 2286        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2287
 2288        cx.spawn_in(window, async move |workspace, cx| {
 2289            let buffer = create.await?;
 2290            workspace.update_in(cx, |workspace, window, cx| {
 2291                let editor =
 2292                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2293                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2294                editor
 2295            })
 2296        })
 2297    }
 2298
 2299    fn new_file_vertical(
 2300        workspace: &mut Workspace,
 2301        _: &workspace::NewFileSplitVertical,
 2302        window: &mut Window,
 2303        cx: &mut Context<Workspace>,
 2304    ) {
 2305        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2306    }
 2307
 2308    fn new_file_horizontal(
 2309        workspace: &mut Workspace,
 2310        _: &workspace::NewFileSplitHorizontal,
 2311        window: &mut Window,
 2312        cx: &mut Context<Workspace>,
 2313    ) {
 2314        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2315    }
 2316
 2317    fn new_file_in_direction(
 2318        workspace: &mut Workspace,
 2319        direction: SplitDirection,
 2320        window: &mut Window,
 2321        cx: &mut Context<Workspace>,
 2322    ) {
 2323        let project = workspace.project().clone();
 2324        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2325
 2326        cx.spawn_in(window, async move |workspace, cx| {
 2327            let buffer = create.await?;
 2328            workspace.update_in(cx, move |workspace, window, cx| {
 2329                workspace.split_item(
 2330                    direction,
 2331                    Box::new(
 2332                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2333                    ),
 2334                    window,
 2335                    cx,
 2336                )
 2337            })?;
 2338            anyhow::Ok(())
 2339        })
 2340        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2341            match e.error_code() {
 2342                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2343                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2344                e.error_tag("required").unwrap_or("the latest version")
 2345            )),
 2346                _ => None,
 2347            }
 2348        });
 2349    }
 2350
 2351    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2352        self.leader_id
 2353    }
 2354
 2355    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2356        &self.buffer
 2357    }
 2358
 2359    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2360        self.workspace.as_ref()?.0.upgrade()
 2361    }
 2362
 2363    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2364        self.buffer().read(cx).title(cx)
 2365    }
 2366
 2367    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2368        let git_blame_gutter_max_author_length = self
 2369            .render_git_blame_gutter(cx)
 2370            .then(|| {
 2371                if let Some(blame) = self.blame.as_ref() {
 2372                    let max_author_length =
 2373                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2374                    Some(max_author_length)
 2375                } else {
 2376                    None
 2377                }
 2378            })
 2379            .flatten();
 2380
 2381        EditorSnapshot {
 2382            mode: self.mode.clone(),
 2383            show_gutter: self.show_gutter,
 2384            show_line_numbers: self.show_line_numbers,
 2385            show_git_diff_gutter: self.show_git_diff_gutter,
 2386            show_code_actions: self.show_code_actions,
 2387            show_runnables: self.show_runnables,
 2388            show_breakpoints: self.show_breakpoints,
 2389            git_blame_gutter_max_author_length,
 2390            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2391            scroll_anchor: self.scroll_manager.anchor(),
 2392            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2393            placeholder_text: self.placeholder_text.clone(),
 2394            is_focused: self.focus_handle.is_focused(window),
 2395            current_line_highlight: self
 2396                .current_line_highlight
 2397                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2398            gutter_hovered: self.gutter_hovered,
 2399        }
 2400    }
 2401
 2402    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2403        self.buffer.read(cx).language_at(point, cx)
 2404    }
 2405
 2406    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2407        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2408    }
 2409
 2410    pub fn active_excerpt(
 2411        &self,
 2412        cx: &App,
 2413    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2414        self.buffer
 2415            .read(cx)
 2416            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2417    }
 2418
 2419    pub fn mode(&self) -> &EditorMode {
 2420        &self.mode
 2421    }
 2422
 2423    pub fn set_mode(&mut self, mode: EditorMode) {
 2424        self.mode = mode;
 2425    }
 2426
 2427    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2428        self.collaboration_hub.as_deref()
 2429    }
 2430
 2431    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2432        self.collaboration_hub = Some(hub);
 2433    }
 2434
 2435    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2436        self.in_project_search = in_project_search;
 2437    }
 2438
 2439    pub fn set_custom_context_menu(
 2440        &mut self,
 2441        f: impl 'static
 2442        + Fn(
 2443            &mut Self,
 2444            DisplayPoint,
 2445            &mut Window,
 2446            &mut Context<Self>,
 2447        ) -> Option<Entity<ui::ContextMenu>>,
 2448    ) {
 2449        self.custom_context_menu = Some(Box::new(f))
 2450    }
 2451
 2452    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2453        self.completion_provider = provider;
 2454    }
 2455
 2456    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2457        self.semantics_provider.clone()
 2458    }
 2459
 2460    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2461        self.semantics_provider = provider;
 2462    }
 2463
 2464    pub fn set_edit_prediction_provider<T>(
 2465        &mut self,
 2466        provider: Option<Entity<T>>,
 2467        window: &mut Window,
 2468        cx: &mut Context<Self>,
 2469    ) where
 2470        T: EditPredictionProvider,
 2471    {
 2472        self.edit_prediction_provider =
 2473            provider.map(|provider| RegisteredInlineCompletionProvider {
 2474                _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2475                    if this.focus_handle.is_focused(window) {
 2476                        this.update_visible_inline_completion(window, cx);
 2477                    }
 2478                }),
 2479                provider: Arc::new(provider),
 2480            });
 2481        self.update_edit_prediction_settings(cx);
 2482        self.refresh_inline_completion(false, false, window, cx);
 2483    }
 2484
 2485    pub fn placeholder_text(&self) -> Option<&str> {
 2486        self.placeholder_text.as_deref()
 2487    }
 2488
 2489    pub fn set_placeholder_text(
 2490        &mut self,
 2491        placeholder_text: impl Into<Arc<str>>,
 2492        cx: &mut Context<Self>,
 2493    ) {
 2494        let placeholder_text = Some(placeholder_text.into());
 2495        if self.placeholder_text != placeholder_text {
 2496            self.placeholder_text = placeholder_text;
 2497            cx.notify();
 2498        }
 2499    }
 2500
 2501    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2502        self.cursor_shape = cursor_shape;
 2503
 2504        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2505        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2506
 2507        cx.notify();
 2508    }
 2509
 2510    pub fn set_current_line_highlight(
 2511        &mut self,
 2512        current_line_highlight: Option<CurrentLineHighlight>,
 2513    ) {
 2514        self.current_line_highlight = current_line_highlight;
 2515    }
 2516
 2517    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2518        self.collapse_matches = collapse_matches;
 2519    }
 2520
 2521    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2522        let buffers = self.buffer.read(cx).all_buffers();
 2523        let Some(project) = self.project.as_ref() else {
 2524            return;
 2525        };
 2526        project.update(cx, |project, cx| {
 2527            for buffer in buffers {
 2528                self.registered_buffers
 2529                    .entry(buffer.read(cx).remote_id())
 2530                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2531            }
 2532        })
 2533    }
 2534
 2535    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2536        if self.collapse_matches {
 2537            return range.start..range.start;
 2538        }
 2539        range.clone()
 2540    }
 2541
 2542    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2543        if self.display_map.read(cx).clip_at_line_ends != clip {
 2544            self.display_map
 2545                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2546        }
 2547    }
 2548
 2549    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2550        self.input_enabled = input_enabled;
 2551    }
 2552
 2553    pub fn set_inline_completions_hidden_for_vim_mode(
 2554        &mut self,
 2555        hidden: bool,
 2556        window: &mut Window,
 2557        cx: &mut Context<Self>,
 2558    ) {
 2559        if hidden != self.inline_completions_hidden_for_vim_mode {
 2560            self.inline_completions_hidden_for_vim_mode = hidden;
 2561            if hidden {
 2562                self.update_visible_inline_completion(window, cx);
 2563            } else {
 2564                self.refresh_inline_completion(true, false, window, cx);
 2565            }
 2566        }
 2567    }
 2568
 2569    pub fn set_menu_inline_completions_policy(&mut self, value: MenuInlineCompletionsPolicy) {
 2570        self.menu_inline_completions_policy = value;
 2571    }
 2572
 2573    pub fn set_autoindent(&mut self, autoindent: bool) {
 2574        if autoindent {
 2575            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2576        } else {
 2577            self.autoindent_mode = None;
 2578        }
 2579    }
 2580
 2581    pub fn read_only(&self, cx: &App) -> bool {
 2582        self.read_only || self.buffer.read(cx).read_only()
 2583    }
 2584
 2585    pub fn set_read_only(&mut self, read_only: bool) {
 2586        self.read_only = read_only;
 2587    }
 2588
 2589    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2590        self.use_autoclose = autoclose;
 2591    }
 2592
 2593    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2594        self.use_auto_surround = auto_surround;
 2595    }
 2596
 2597    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2598        self.auto_replace_emoji_shortcode = auto_replace;
 2599    }
 2600
 2601    pub fn toggle_edit_predictions(
 2602        &mut self,
 2603        _: &ToggleEditPrediction,
 2604        window: &mut Window,
 2605        cx: &mut Context<Self>,
 2606    ) {
 2607        if self.show_inline_completions_override.is_some() {
 2608            self.set_show_edit_predictions(None, window, cx);
 2609        } else {
 2610            let show_edit_predictions = !self.edit_predictions_enabled();
 2611            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2612        }
 2613    }
 2614
 2615    pub fn set_show_edit_predictions(
 2616        &mut self,
 2617        show_edit_predictions: Option<bool>,
 2618        window: &mut Window,
 2619        cx: &mut Context<Self>,
 2620    ) {
 2621        self.show_inline_completions_override = show_edit_predictions;
 2622        self.update_edit_prediction_settings(cx);
 2623
 2624        if let Some(false) = show_edit_predictions {
 2625            self.discard_inline_completion(false, cx);
 2626        } else {
 2627            self.refresh_inline_completion(false, true, window, cx);
 2628        }
 2629    }
 2630
 2631    fn inline_completions_disabled_in_scope(
 2632        &self,
 2633        buffer: &Entity<Buffer>,
 2634        buffer_position: language::Anchor,
 2635        cx: &App,
 2636    ) -> bool {
 2637        let snapshot = buffer.read(cx).snapshot();
 2638        let settings = snapshot.settings_at(buffer_position, cx);
 2639
 2640        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2641            return false;
 2642        };
 2643
 2644        scope.override_name().map_or(false, |scope_name| {
 2645            settings
 2646                .edit_predictions_disabled_in
 2647                .iter()
 2648                .any(|s| s == scope_name)
 2649        })
 2650    }
 2651
 2652    pub fn set_use_modal_editing(&mut self, to: bool) {
 2653        self.use_modal_editing = to;
 2654    }
 2655
 2656    pub fn use_modal_editing(&self) -> bool {
 2657        self.use_modal_editing
 2658    }
 2659
 2660    fn selections_did_change(
 2661        &mut self,
 2662        local: bool,
 2663        old_cursor_position: &Anchor,
 2664        should_update_completions: bool,
 2665        window: &mut Window,
 2666        cx: &mut Context<Self>,
 2667    ) {
 2668        window.invalidate_character_coordinates();
 2669
 2670        // Copy selections to primary selection buffer
 2671        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2672        if local {
 2673            let selections = self.selections.all::<usize>(cx);
 2674            let buffer_handle = self.buffer.read(cx).read(cx);
 2675
 2676            let mut text = String::new();
 2677            for (index, selection) in selections.iter().enumerate() {
 2678                let text_for_selection = buffer_handle
 2679                    .text_for_range(selection.start..selection.end)
 2680                    .collect::<String>();
 2681
 2682                text.push_str(&text_for_selection);
 2683                if index != selections.len() - 1 {
 2684                    text.push('\n');
 2685                }
 2686            }
 2687
 2688            if !text.is_empty() {
 2689                cx.write_to_primary(ClipboardItem::new_string(text));
 2690            }
 2691        }
 2692
 2693        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2694            self.buffer.update(cx, |buffer, cx| {
 2695                buffer.set_active_selections(
 2696                    &self.selections.disjoint_anchors(),
 2697                    self.selections.line_mode,
 2698                    self.cursor_shape,
 2699                    cx,
 2700                )
 2701            });
 2702        }
 2703        let display_map = self
 2704            .display_map
 2705            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2706        let buffer = &display_map.buffer_snapshot;
 2707        self.add_selections_state = None;
 2708        self.select_next_state = None;
 2709        self.select_prev_state = None;
 2710        self.select_syntax_node_history.try_clear();
 2711        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), buffer);
 2712        self.snippet_stack
 2713            .invalidate(&self.selections.disjoint_anchors(), buffer);
 2714        self.take_rename(false, window, cx);
 2715
 2716        let new_cursor_position = self.selections.newest_anchor().head();
 2717
 2718        self.push_to_nav_history(
 2719            *old_cursor_position,
 2720            Some(new_cursor_position.to_point(buffer)),
 2721            false,
 2722            cx,
 2723        );
 2724
 2725        if local {
 2726            let new_cursor_position = self.selections.newest_anchor().head();
 2727
 2728            if let Some(buffer_id) = new_cursor_position.buffer_id {
 2729                if !self.registered_buffers.contains_key(&buffer_id) {
 2730                    if let Some(project) = self.project.as_ref() {
 2731                        project.update(cx, |project, cx| {
 2732                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 2733                                return;
 2734                            };
 2735                            self.registered_buffers.insert(
 2736                                buffer_id,
 2737                                project.register_buffer_with_language_servers(&buffer, cx),
 2738                            );
 2739                        })
 2740                    }
 2741                }
 2742            }
 2743
 2744            let mut context_menu = self.context_menu.borrow_mut();
 2745            let completion_menu = match context_menu.as_ref() {
 2746                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 2747                Some(CodeContextMenu::CodeActions(_)) => {
 2748                    *context_menu = None;
 2749                    None
 2750                }
 2751                None => None,
 2752            };
 2753            let completion_position = completion_menu.map(|menu| menu.initial_position);
 2754            drop(context_menu);
 2755
 2756            if should_update_completions {
 2757                if let Some(completion_position) = completion_position {
 2758                    let new_cursor_offset = new_cursor_position.to_offset(buffer);
 2759                    let position_matches =
 2760                        new_cursor_offset == completion_position.to_offset(buffer);
 2761                    let continue_showing = if position_matches {
 2762                        let (word_range, kind) = buffer.surrounding_word(new_cursor_offset, true);
 2763                        if let Some(CharKind::Word) = kind {
 2764                            word_range.start < new_cursor_offset
 2765                        } else {
 2766                            false
 2767                        }
 2768                    } else {
 2769                        false
 2770                    };
 2771
 2772                    if continue_showing {
 2773                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 2774                    } else {
 2775                        self.hide_context_menu(window, cx);
 2776                    }
 2777                }
 2778            }
 2779
 2780            hide_hover(self, cx);
 2781
 2782            if old_cursor_position.to_display_point(&display_map).row()
 2783                != new_cursor_position.to_display_point(&display_map).row()
 2784            {
 2785                self.available_code_actions.take();
 2786            }
 2787            self.refresh_code_actions(window, cx);
 2788            self.refresh_document_highlights(cx);
 2789            self.refresh_selected_text_highlights(false, window, cx);
 2790            refresh_matching_bracket_highlights(self, window, cx);
 2791            self.update_visible_inline_completion(window, cx);
 2792            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 2793            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 2794            self.inline_blame_popover.take();
 2795            if self.git_blame_inline_enabled {
 2796                self.start_inline_blame_timer(window, cx);
 2797            }
 2798        }
 2799
 2800        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 2801        cx.emit(EditorEvent::SelectionsChanged { local });
 2802
 2803        let selections = &self.selections.disjoint;
 2804        if selections.len() == 1 {
 2805            cx.emit(SearchEvent::ActiveMatchChanged)
 2806        }
 2807        if local {
 2808            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 2809                let inmemory_selections = selections
 2810                    .iter()
 2811                    .map(|s| {
 2812                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 2813                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 2814                    })
 2815                    .collect();
 2816                self.update_restoration_data(cx, |data| {
 2817                    data.selections = inmemory_selections;
 2818                });
 2819
 2820                if WorkspaceSettings::get(None, cx).restore_on_startup
 2821                    != RestoreOnStartupBehavior::None
 2822                {
 2823                    if let Some(workspace_id) =
 2824                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 2825                    {
 2826                        let snapshot = self.buffer().read(cx).snapshot(cx);
 2827                        let selections = selections.clone();
 2828                        let background_executor = cx.background_executor().clone();
 2829                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2830                        self.serialize_selections = cx.background_spawn(async move {
 2831                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2832                    let db_selections = selections
 2833                        .iter()
 2834                        .map(|selection| {
 2835                            (
 2836                                selection.start.to_offset(&snapshot),
 2837                                selection.end.to_offset(&snapshot),
 2838                            )
 2839                        })
 2840                        .collect();
 2841
 2842                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 2843                        .await
 2844                        .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 2845                        .log_err();
 2846                });
 2847                    }
 2848                }
 2849            }
 2850        }
 2851
 2852        cx.notify();
 2853    }
 2854
 2855    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 2856        use text::ToOffset as _;
 2857        use text::ToPoint as _;
 2858
 2859        if self.mode.is_minimap()
 2860            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 2861        {
 2862            return;
 2863        }
 2864
 2865        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 2866            return;
 2867        };
 2868
 2869        let snapshot = singleton.read(cx).snapshot();
 2870        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 2871            let display_snapshot = display_map.snapshot(cx);
 2872
 2873            display_snapshot
 2874                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 2875                .map(|fold| {
 2876                    fold.range.start.text_anchor.to_point(&snapshot)
 2877                        ..fold.range.end.text_anchor.to_point(&snapshot)
 2878                })
 2879                .collect()
 2880        });
 2881        self.update_restoration_data(cx, |data| {
 2882            data.folds = inmemory_folds;
 2883        });
 2884
 2885        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 2886            return;
 2887        };
 2888        let background_executor = cx.background_executor().clone();
 2889        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 2890        let db_folds = self.display_map.update(cx, |display_map, cx| {
 2891            display_map
 2892                .snapshot(cx)
 2893                .folds_in_range(0..snapshot.len())
 2894                .map(|fold| {
 2895                    (
 2896                        fold.range.start.text_anchor.to_offset(&snapshot),
 2897                        fold.range.end.text_anchor.to_offset(&snapshot),
 2898                    )
 2899                })
 2900                .collect()
 2901        });
 2902        self.serialize_folds = cx.background_spawn(async move {
 2903            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 2904            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 2905                .await
 2906                .with_context(|| {
 2907                    format!(
 2908                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 2909                    )
 2910                })
 2911                .log_err();
 2912        });
 2913    }
 2914
 2915    pub fn sync_selections(
 2916        &mut self,
 2917        other: Entity<Editor>,
 2918        cx: &mut Context<Self>,
 2919    ) -> gpui::Subscription {
 2920        let other_selections = other.read(cx).selections.disjoint.to_vec();
 2921        self.selections.change_with(cx, |selections| {
 2922            selections.select_anchors(other_selections);
 2923        });
 2924
 2925        let other_subscription =
 2926            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 2927                EditorEvent::SelectionsChanged { local: true } => {
 2928                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 2929                    if other_selections.is_empty() {
 2930                        return;
 2931                    }
 2932                    this.selections.change_with(cx, |selections| {
 2933                        selections.select_anchors(other_selections);
 2934                    });
 2935                }
 2936                _ => {}
 2937            });
 2938
 2939        let this_subscription =
 2940            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 2941                EditorEvent::SelectionsChanged { local: true } => {
 2942                    let these_selections = this.selections.disjoint.to_vec();
 2943                    if these_selections.is_empty() {
 2944                        return;
 2945                    }
 2946                    other.update(cx, |other_editor, cx| {
 2947                        other_editor.selections.change_with(cx, |selections| {
 2948                            selections.select_anchors(these_selections);
 2949                        })
 2950                    });
 2951                }
 2952                _ => {}
 2953            });
 2954
 2955        Subscription::join(other_subscription, this_subscription)
 2956    }
 2957
 2958    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 2959    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 2960    /// effects of selection change occur at the end of the transaction.
 2961    pub fn change_selections<R>(
 2962        &mut self,
 2963        autoscroll: Option<Autoscroll>,
 2964        window: &mut Window,
 2965        cx: &mut Context<Self>,
 2966        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2967    ) -> R {
 2968        self.change_selections_inner(true, autoscroll, window, cx, change)
 2969    }
 2970
 2971    pub(crate) fn change_selections_without_updating_completions<R>(
 2972        &mut self,
 2973        autoscroll: Option<Autoscroll>,
 2974        window: &mut Window,
 2975        cx: &mut Context<Self>,
 2976        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2977    ) -> R {
 2978        self.change_selections_inner(false, autoscroll, window, cx, change)
 2979    }
 2980
 2981    fn change_selections_inner<R>(
 2982        &mut self,
 2983        should_update_completions: bool,
 2984        autoscroll: Option<Autoscroll>,
 2985        window: &mut Window,
 2986        cx: &mut Context<Self>,
 2987        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 2988    ) -> R {
 2989        if let Some(state) = &mut self.deferred_selection_effects_state {
 2990            state.autoscroll = autoscroll.or(state.autoscroll);
 2991            state.should_update_completions = should_update_completions;
 2992            let (changed, result) = self.selections.change_with(cx, change);
 2993            state.changed |= changed;
 2994            return result;
 2995        }
 2996        let mut state = DeferredSelectionEffectsState {
 2997            changed: false,
 2998            should_update_completions,
 2999            autoscroll,
 3000            old_cursor_position: self.selections.newest_anchor().head(),
 3001            history_entry: SelectionHistoryEntry {
 3002                selections: self.selections.disjoint_anchors(),
 3003                select_next_state: self.select_next_state.clone(),
 3004                select_prev_state: self.select_prev_state.clone(),
 3005                add_selections_state: self.add_selections_state.clone(),
 3006            },
 3007        };
 3008        let (changed, result) = self.selections.change_with(cx, change);
 3009        state.changed = state.changed || changed;
 3010        if self.defer_selection_effects {
 3011            self.deferred_selection_effects_state = Some(state);
 3012        } else {
 3013            self.apply_selection_effects(state, window, cx);
 3014        }
 3015        result
 3016    }
 3017
 3018    /// Defers the effects of selection change, so that the effects of multiple calls to
 3019    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3020    /// to selection history and the state of popovers based on selection position aren't
 3021    /// erroneously updated.
 3022    pub fn with_selection_effects_deferred<R>(
 3023        &mut self,
 3024        window: &mut Window,
 3025        cx: &mut Context<Self>,
 3026        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3027    ) -> R {
 3028        let already_deferred = self.defer_selection_effects;
 3029        self.defer_selection_effects = true;
 3030        let result = update(self, window, cx);
 3031        if !already_deferred {
 3032            self.defer_selection_effects = false;
 3033            if let Some(state) = self.deferred_selection_effects_state.take() {
 3034                self.apply_selection_effects(state, window, cx);
 3035            }
 3036        }
 3037        result
 3038    }
 3039
 3040    fn apply_selection_effects(
 3041        &mut self,
 3042        state: DeferredSelectionEffectsState,
 3043        window: &mut Window,
 3044        cx: &mut Context<Self>,
 3045    ) {
 3046        if state.changed {
 3047            self.selection_history.push(state.history_entry);
 3048
 3049            if let Some(autoscroll) = state.autoscroll {
 3050                self.request_autoscroll(autoscroll, cx);
 3051            }
 3052
 3053            let old_cursor_position = &state.old_cursor_position;
 3054
 3055            self.selections_did_change(
 3056                true,
 3057                &old_cursor_position,
 3058                state.should_update_completions,
 3059                window,
 3060                cx,
 3061            );
 3062
 3063            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3064                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3065            }
 3066        }
 3067    }
 3068
 3069    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3070    where
 3071        I: IntoIterator<Item = (Range<S>, T)>,
 3072        S: ToOffset,
 3073        T: Into<Arc<str>>,
 3074    {
 3075        if self.read_only(cx) {
 3076            return;
 3077        }
 3078
 3079        self.buffer
 3080            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3081    }
 3082
 3083    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3084    where
 3085        I: IntoIterator<Item = (Range<S>, T)>,
 3086        S: ToOffset,
 3087        T: Into<Arc<str>>,
 3088    {
 3089        if self.read_only(cx) {
 3090            return;
 3091        }
 3092
 3093        self.buffer.update(cx, |buffer, cx| {
 3094            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3095        });
 3096    }
 3097
 3098    pub fn edit_with_block_indent<I, S, T>(
 3099        &mut self,
 3100        edits: I,
 3101        original_indent_columns: Vec<Option<u32>>,
 3102        cx: &mut Context<Self>,
 3103    ) where
 3104        I: IntoIterator<Item = (Range<S>, T)>,
 3105        S: ToOffset,
 3106        T: Into<Arc<str>>,
 3107    {
 3108        if self.read_only(cx) {
 3109            return;
 3110        }
 3111
 3112        self.buffer.update(cx, |buffer, cx| {
 3113            buffer.edit(
 3114                edits,
 3115                Some(AutoindentMode::Block {
 3116                    original_indent_columns,
 3117                }),
 3118                cx,
 3119            )
 3120        });
 3121    }
 3122
 3123    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3124        self.hide_context_menu(window, cx);
 3125
 3126        match phase {
 3127            SelectPhase::Begin {
 3128                position,
 3129                add,
 3130                click_count,
 3131            } => self.begin_selection(position, add, click_count, window, cx),
 3132            SelectPhase::BeginColumnar {
 3133                position,
 3134                goal_column,
 3135                reset,
 3136            } => self.begin_columnar_selection(position, goal_column, reset, window, cx),
 3137            SelectPhase::Extend {
 3138                position,
 3139                click_count,
 3140            } => self.extend_selection(position, click_count, window, cx),
 3141            SelectPhase::Update {
 3142                position,
 3143                goal_column,
 3144                scroll_delta,
 3145            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3146            SelectPhase::End => self.end_selection(window, cx),
 3147        }
 3148    }
 3149
 3150    fn extend_selection(
 3151        &mut self,
 3152        position: DisplayPoint,
 3153        click_count: usize,
 3154        window: &mut Window,
 3155        cx: &mut Context<Self>,
 3156    ) {
 3157        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3158        let tail = self.selections.newest::<usize>(cx).tail();
 3159        self.begin_selection(position, false, click_count, window, cx);
 3160
 3161        let position = position.to_offset(&display_map, Bias::Left);
 3162        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3163
 3164        let mut pending_selection = self
 3165            .selections
 3166            .pending_anchor()
 3167            .expect("extend_selection not called with pending selection");
 3168        if position >= tail {
 3169            pending_selection.start = tail_anchor;
 3170        } else {
 3171            pending_selection.end = tail_anchor;
 3172            pending_selection.reversed = true;
 3173        }
 3174
 3175        let mut pending_mode = self.selections.pending_mode().unwrap();
 3176        match &mut pending_mode {
 3177            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3178            _ => {}
 3179        }
 3180
 3181        let auto_scroll = EditorSettings::get_global(cx).autoscroll_on_clicks;
 3182
 3183        self.change_selections(auto_scroll.then(Autoscroll::fit), window, cx, |s| {
 3184            s.set_pending(pending_selection, pending_mode)
 3185        });
 3186    }
 3187
 3188    fn begin_selection(
 3189        &mut self,
 3190        position: DisplayPoint,
 3191        add: bool,
 3192        click_count: usize,
 3193        window: &mut Window,
 3194        cx: &mut Context<Self>,
 3195    ) {
 3196        if !self.focus_handle.is_focused(window) {
 3197            self.last_focused_descendant = None;
 3198            window.focus(&self.focus_handle);
 3199        }
 3200
 3201        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3202        let buffer = &display_map.buffer_snapshot;
 3203        let position = display_map.clip_point(position, Bias::Left);
 3204
 3205        let start;
 3206        let end;
 3207        let mode;
 3208        let mut auto_scroll;
 3209        match click_count {
 3210            1 => {
 3211                start = buffer.anchor_before(position.to_point(&display_map));
 3212                end = start;
 3213                mode = SelectMode::Character;
 3214                auto_scroll = true;
 3215            }
 3216            2 => {
 3217                let range = movement::surrounding_word(&display_map, position);
 3218                start = buffer.anchor_before(range.start.to_point(&display_map));
 3219                end = buffer.anchor_before(range.end.to_point(&display_map));
 3220                mode = SelectMode::Word(start..end);
 3221                auto_scroll = true;
 3222            }
 3223            3 => {
 3224                let position = display_map
 3225                    .clip_point(position, Bias::Left)
 3226                    .to_point(&display_map);
 3227                let line_start = display_map.prev_line_boundary(position).0;
 3228                let next_line_start = buffer.clip_point(
 3229                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3230                    Bias::Left,
 3231                );
 3232                start = buffer.anchor_before(line_start);
 3233                end = buffer.anchor_before(next_line_start);
 3234                mode = SelectMode::Line(start..end);
 3235                auto_scroll = true;
 3236            }
 3237            _ => {
 3238                start = buffer.anchor_before(0);
 3239                end = buffer.anchor_before(buffer.len());
 3240                mode = SelectMode::All;
 3241                auto_scroll = false;
 3242            }
 3243        }
 3244        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3245
 3246        let point_to_delete: Option<usize> = {
 3247            let selected_points: Vec<Selection<Point>> =
 3248                self.selections.disjoint_in_range(start..end, cx);
 3249
 3250            if !add || click_count > 1 {
 3251                None
 3252            } else if !selected_points.is_empty() {
 3253                Some(selected_points[0].id)
 3254            } else {
 3255                let clicked_point_already_selected =
 3256                    self.selections.disjoint.iter().find(|selection| {
 3257                        selection.start.to_point(buffer) == start.to_point(buffer)
 3258                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3259                    });
 3260
 3261                clicked_point_already_selected.map(|selection| selection.id)
 3262            }
 3263        };
 3264
 3265        let selections_count = self.selections.count();
 3266
 3267        self.change_selections(auto_scroll.then(Autoscroll::newest), window, cx, |s| {
 3268            if let Some(point_to_delete) = point_to_delete {
 3269                s.delete(point_to_delete);
 3270
 3271                if selections_count == 1 {
 3272                    s.set_pending_anchor_range(start..end, mode);
 3273                }
 3274            } else {
 3275                if !add {
 3276                    s.clear_disjoint();
 3277                }
 3278
 3279                s.set_pending_anchor_range(start..end, mode);
 3280            }
 3281        });
 3282    }
 3283
 3284    fn begin_columnar_selection(
 3285        &mut self,
 3286        position: DisplayPoint,
 3287        goal_column: u32,
 3288        reset: bool,
 3289        window: &mut Window,
 3290        cx: &mut Context<Self>,
 3291    ) {
 3292        if !self.focus_handle.is_focused(window) {
 3293            self.last_focused_descendant = None;
 3294            window.focus(&self.focus_handle);
 3295        }
 3296
 3297        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3298
 3299        if reset {
 3300            let pointer_position = display_map
 3301                .buffer_snapshot
 3302                .anchor_before(position.to_point(&display_map));
 3303
 3304            self.change_selections(Some(Autoscroll::newest()), window, cx, |s| {
 3305                s.clear_disjoint();
 3306                s.set_pending_anchor_range(
 3307                    pointer_position..pointer_position,
 3308                    SelectMode::Character,
 3309                );
 3310            });
 3311            if position.column() != goal_column {
 3312                self.columnar_display_point = Some(DisplayPoint::new(position.row(), goal_column));
 3313            } else {
 3314                self.columnar_display_point = None;
 3315            }
 3316        }
 3317
 3318        let tail = self.selections.newest::<Point>(cx).tail();
 3319        self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail));
 3320
 3321        if !reset {
 3322            self.columnar_display_point = None;
 3323            self.select_columns(
 3324                tail.to_display_point(&display_map),
 3325                position,
 3326                goal_column,
 3327                &display_map,
 3328                window,
 3329                cx,
 3330            );
 3331        }
 3332    }
 3333
 3334    fn update_selection(
 3335        &mut self,
 3336        position: DisplayPoint,
 3337        goal_column: u32,
 3338        scroll_delta: gpui::Point<f32>,
 3339        window: &mut Window,
 3340        cx: &mut Context<Self>,
 3341    ) {
 3342        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3343
 3344        if let Some(tail) = self.columnar_selection_tail.as_ref() {
 3345            let tail = self
 3346                .columnar_display_point
 3347                .unwrap_or_else(|| tail.to_display_point(&display_map));
 3348            self.select_columns(tail, position, goal_column, &display_map, window, cx);
 3349        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3350            let buffer = self.buffer.read(cx).snapshot(cx);
 3351            let head;
 3352            let tail;
 3353            let mode = self.selections.pending_mode().unwrap();
 3354            match &mode {
 3355                SelectMode::Character => {
 3356                    head = position.to_point(&display_map);
 3357                    tail = pending.tail().to_point(&buffer);
 3358                }
 3359                SelectMode::Word(original_range) => {
 3360                    let original_display_range = original_range.start.to_display_point(&display_map)
 3361                        ..original_range.end.to_display_point(&display_map);
 3362                    let original_buffer_range = original_display_range.start.to_point(&display_map)
 3363                        ..original_display_range.end.to_point(&display_map);
 3364                    if movement::is_inside_word(&display_map, position)
 3365                        || original_display_range.contains(&position)
 3366                    {
 3367                        let word_range = movement::surrounding_word(&display_map, position);
 3368                        if word_range.start < original_display_range.start {
 3369                            head = word_range.start.to_point(&display_map);
 3370                        } else {
 3371                            head = word_range.end.to_point(&display_map);
 3372                        }
 3373                    } else {
 3374                        head = position.to_point(&display_map);
 3375                    }
 3376
 3377                    if head <= original_buffer_range.start {
 3378                        tail = original_buffer_range.end;
 3379                    } else {
 3380                        tail = original_buffer_range.start;
 3381                    }
 3382                }
 3383                SelectMode::Line(original_range) => {
 3384                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3385
 3386                    let position = display_map
 3387                        .clip_point(position, Bias::Left)
 3388                        .to_point(&display_map);
 3389                    let line_start = display_map.prev_line_boundary(position).0;
 3390                    let next_line_start = buffer.clip_point(
 3391                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3392                        Bias::Left,
 3393                    );
 3394
 3395                    if line_start < original_range.start {
 3396                        head = line_start
 3397                    } else {
 3398                        head = next_line_start
 3399                    }
 3400
 3401                    if head <= original_range.start {
 3402                        tail = original_range.end;
 3403                    } else {
 3404                        tail = original_range.start;
 3405                    }
 3406                }
 3407                SelectMode::All => {
 3408                    return;
 3409                }
 3410            };
 3411
 3412            if head < tail {
 3413                pending.start = buffer.anchor_before(head);
 3414                pending.end = buffer.anchor_before(tail);
 3415                pending.reversed = true;
 3416            } else {
 3417                pending.start = buffer.anchor_before(tail);
 3418                pending.end = buffer.anchor_before(head);
 3419                pending.reversed = false;
 3420            }
 3421
 3422            self.change_selections(None, window, cx, |s| {
 3423                s.set_pending(pending, mode);
 3424            });
 3425        } else {
 3426            log::error!("update_selection dispatched with no pending selection");
 3427            return;
 3428        }
 3429
 3430        self.apply_scroll_delta(scroll_delta, window, cx);
 3431        cx.notify();
 3432    }
 3433
 3434    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3435        self.columnar_selection_tail.take();
 3436        if self.selections.pending_anchor().is_some() {
 3437            let selections = self.selections.all::<usize>(cx);
 3438            self.change_selections(None, window, cx, |s| {
 3439                s.select(selections);
 3440                s.clear_pending();
 3441            });
 3442        }
 3443    }
 3444
 3445    fn select_columns(
 3446        &mut self,
 3447        tail: DisplayPoint,
 3448        head: DisplayPoint,
 3449        goal_column: u32,
 3450        display_map: &DisplaySnapshot,
 3451        window: &mut Window,
 3452        cx: &mut Context<Self>,
 3453    ) {
 3454        let start_row = cmp::min(tail.row(), head.row());
 3455        let end_row = cmp::max(tail.row(), head.row());
 3456        let start_column = cmp::min(tail.column(), goal_column);
 3457        let end_column = cmp::max(tail.column(), goal_column);
 3458        let reversed = start_column < tail.column();
 3459
 3460        let selection_ranges = (start_row.0..=end_row.0)
 3461            .map(DisplayRow)
 3462            .filter_map(|row| {
 3463                if !display_map.is_block_line(row) {
 3464                    let start = display_map
 3465                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3466                        .to_point(display_map);
 3467                    let end = display_map
 3468                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3469                        .to_point(display_map);
 3470                    if reversed {
 3471                        Some(end..start)
 3472                    } else {
 3473                        Some(start..end)
 3474                    }
 3475                } else {
 3476                    None
 3477                }
 3478            })
 3479            .collect::<Vec<_>>();
 3480
 3481        let mut non_empty_ranges = selection_ranges
 3482            .iter()
 3483            .filter(|selection_range| selection_range.start != selection_range.end)
 3484            .peekable();
 3485
 3486        let ranges = if non_empty_ranges.peek().is_some() {
 3487            non_empty_ranges.cloned().collect()
 3488        } else {
 3489            selection_ranges
 3490        };
 3491
 3492        self.change_selections(None, window, cx, |s| {
 3493            s.select_ranges(ranges);
 3494        });
 3495        cx.notify();
 3496    }
 3497
 3498    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3499        self.selections
 3500            .all_adjusted(cx)
 3501            .iter()
 3502            .any(|selection| !selection.is_empty())
 3503    }
 3504
 3505    pub fn has_pending_nonempty_selection(&self) -> bool {
 3506        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3507            Some(Selection { start, end, .. }) => start != end,
 3508            None => false,
 3509        };
 3510
 3511        pending_nonempty_selection
 3512            || (self.columnar_selection_tail.is_some() && self.selections.disjoint.len() > 1)
 3513    }
 3514
 3515    pub fn has_pending_selection(&self) -> bool {
 3516        self.selections.pending_anchor().is_some() || self.columnar_selection_tail.is_some()
 3517    }
 3518
 3519    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3520        self.selection_mark_mode = false;
 3521
 3522        if self.clear_expanded_diff_hunks(cx) {
 3523            cx.notify();
 3524            return;
 3525        }
 3526        if self.dismiss_menus_and_popups(true, window, cx) {
 3527            return;
 3528        }
 3529
 3530        if self.mode.is_full()
 3531            && self.change_selections(Some(Autoscroll::fit()), window, cx, |s| s.try_cancel())
 3532        {
 3533            return;
 3534        }
 3535
 3536        cx.propagate();
 3537    }
 3538
 3539    pub fn dismiss_menus_and_popups(
 3540        &mut self,
 3541        is_user_requested: bool,
 3542        window: &mut Window,
 3543        cx: &mut Context<Self>,
 3544    ) -> bool {
 3545        if self.take_rename(false, window, cx).is_some() {
 3546            return true;
 3547        }
 3548
 3549        if hide_hover(self, cx) {
 3550            return true;
 3551        }
 3552
 3553        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3554            return true;
 3555        }
 3556
 3557        if self.hide_context_menu(window, cx).is_some() {
 3558            return true;
 3559        }
 3560
 3561        if self.mouse_context_menu.take().is_some() {
 3562            return true;
 3563        }
 3564
 3565        if is_user_requested && self.discard_inline_completion(true, cx) {
 3566            return true;
 3567        }
 3568
 3569        if self.snippet_stack.pop().is_some() {
 3570            return true;
 3571        }
 3572
 3573        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3574            self.dismiss_diagnostics(cx);
 3575            return true;
 3576        }
 3577
 3578        false
 3579    }
 3580
 3581    fn linked_editing_ranges_for(
 3582        &self,
 3583        selection: Range<text::Anchor>,
 3584        cx: &App,
 3585    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3586        if self.linked_edit_ranges.is_empty() {
 3587            return None;
 3588        }
 3589        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3590            selection.end.buffer_id.and_then(|end_buffer_id| {
 3591                if selection.start.buffer_id != Some(end_buffer_id) {
 3592                    return None;
 3593                }
 3594                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3595                let snapshot = buffer.read(cx).snapshot();
 3596                self.linked_edit_ranges
 3597                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3598                    .map(|ranges| (ranges, snapshot, buffer))
 3599            })?;
 3600        use text::ToOffset as TO;
 3601        // find offset from the start of current range to current cursor position
 3602        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3603
 3604        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3605        let start_difference = start_offset - start_byte_offset;
 3606        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3607        let end_difference = end_offset - start_byte_offset;
 3608        // Current range has associated linked ranges.
 3609        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3610        for range in linked_ranges.iter() {
 3611            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3612            let end_offset = start_offset + end_difference;
 3613            let start_offset = start_offset + start_difference;
 3614            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3615                continue;
 3616            }
 3617            if self.selections.disjoint_anchor_ranges().any(|s| {
 3618                if s.start.buffer_id != selection.start.buffer_id
 3619                    || s.end.buffer_id != selection.end.buffer_id
 3620                {
 3621                    return false;
 3622                }
 3623                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3624                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3625            }) {
 3626                continue;
 3627            }
 3628            let start = buffer_snapshot.anchor_after(start_offset);
 3629            let end = buffer_snapshot.anchor_after(end_offset);
 3630            linked_edits
 3631                .entry(buffer.clone())
 3632                .or_default()
 3633                .push(start..end);
 3634        }
 3635        Some(linked_edits)
 3636    }
 3637
 3638    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3639        let text: Arc<str> = text.into();
 3640
 3641        if self.read_only(cx) {
 3642            return;
 3643        }
 3644
 3645        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 3646
 3647        let selections = self.selections.all_adjusted(cx);
 3648        let mut bracket_inserted = false;
 3649        let mut edits = Vec::new();
 3650        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3651        let mut new_selections = Vec::with_capacity(selections.len());
 3652        let mut new_autoclose_regions = Vec::new();
 3653        let snapshot = self.buffer.read(cx).read(cx);
 3654        let mut clear_linked_edit_ranges = false;
 3655
 3656        for (selection, autoclose_region) in
 3657            self.selections_with_autoclose_regions(selections, &snapshot)
 3658        {
 3659            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3660                // Determine if the inserted text matches the opening or closing
 3661                // bracket of any of this language's bracket pairs.
 3662                let mut bracket_pair = None;
 3663                let mut is_bracket_pair_start = false;
 3664                let mut is_bracket_pair_end = false;
 3665                if !text.is_empty() {
 3666                    let mut bracket_pair_matching_end = None;
 3667                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3668                    //  and they are removing the character that triggered IME popup.
 3669                    for (pair, enabled) in scope.brackets() {
 3670                        if !pair.close && !pair.surround {
 3671                            continue;
 3672                        }
 3673
 3674                        if enabled && pair.start.ends_with(text.as_ref()) {
 3675                            let prefix_len = pair.start.len() - text.len();
 3676                            let preceding_text_matches_prefix = prefix_len == 0
 3677                                || (selection.start.column >= (prefix_len as u32)
 3678                                    && snapshot.contains_str_at(
 3679                                        Point::new(
 3680                                            selection.start.row,
 3681                                            selection.start.column - (prefix_len as u32),
 3682                                        ),
 3683                                        &pair.start[..prefix_len],
 3684                                    ));
 3685                            if preceding_text_matches_prefix {
 3686                                bracket_pair = Some(pair.clone());
 3687                                is_bracket_pair_start = true;
 3688                                break;
 3689                            }
 3690                        }
 3691                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3692                        {
 3693                            // take first bracket pair matching end, but don't break in case a later bracket
 3694                            // pair matches start
 3695                            bracket_pair_matching_end = Some(pair.clone());
 3696                        }
 3697                    }
 3698                    if bracket_pair.is_none() && bracket_pair_matching_end.is_some() {
 3699                        bracket_pair = Some(bracket_pair_matching_end.unwrap());
 3700                        is_bracket_pair_end = true;
 3701                    }
 3702                }
 3703
 3704                if let Some(bracket_pair) = bracket_pair {
 3705                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 3706                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 3707                    let auto_surround =
 3708                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 3709                    if selection.is_empty() {
 3710                        if is_bracket_pair_start {
 3711                            // If the inserted text is a suffix of an opening bracket and the
 3712                            // selection is preceded by the rest of the opening bracket, then
 3713                            // insert the closing bracket.
 3714                            let following_text_allows_autoclose = snapshot
 3715                                .chars_at(selection.start)
 3716                                .next()
 3717                                .map_or(true, |c| scope.should_autoclose_before(c));
 3718
 3719                            let preceding_text_allows_autoclose = selection.start.column == 0
 3720                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 3721                                    true,
 3722                                    |c| {
 3723                                        bracket_pair.start != bracket_pair.end
 3724                                            || !snapshot
 3725                                                .char_classifier_at(selection.start)
 3726                                                .is_word(c)
 3727                                    },
 3728                                );
 3729
 3730                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 3731                                && bracket_pair.start.len() == 1
 3732                            {
 3733                                let target = bracket_pair.start.chars().next().unwrap();
 3734                                let current_line_count = snapshot
 3735                                    .reversed_chars_at(selection.start)
 3736                                    .take_while(|&c| c != '\n')
 3737                                    .filter(|&c| c == target)
 3738                                    .count();
 3739                                current_line_count % 2 == 1
 3740                            } else {
 3741                                false
 3742                            };
 3743
 3744                            if autoclose
 3745                                && bracket_pair.close
 3746                                && following_text_allows_autoclose
 3747                                && preceding_text_allows_autoclose
 3748                                && !is_closing_quote
 3749                            {
 3750                                let anchor = snapshot.anchor_before(selection.end);
 3751                                new_selections.push((selection.map(|_| anchor), text.len()));
 3752                                new_autoclose_regions.push((
 3753                                    anchor,
 3754                                    text.len(),
 3755                                    selection.id,
 3756                                    bracket_pair.clone(),
 3757                                ));
 3758                                edits.push((
 3759                                    selection.range(),
 3760                                    format!("{}{}", text, bracket_pair.end).into(),
 3761                                ));
 3762                                bracket_inserted = true;
 3763                                continue;
 3764                            }
 3765                        }
 3766
 3767                        if let Some(region) = autoclose_region {
 3768                            // If the selection is followed by an auto-inserted closing bracket,
 3769                            // then don't insert that closing bracket again; just move the selection
 3770                            // past the closing bracket.
 3771                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 3772                                && text.as_ref() == region.pair.end.as_str();
 3773                            if should_skip {
 3774                                let anchor = snapshot.anchor_after(selection.end);
 3775                                new_selections
 3776                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 3777                                continue;
 3778                            }
 3779                        }
 3780
 3781                        let always_treat_brackets_as_autoclosed = snapshot
 3782                            .language_settings_at(selection.start, cx)
 3783                            .always_treat_brackets_as_autoclosed;
 3784                        if always_treat_brackets_as_autoclosed
 3785                            && is_bracket_pair_end
 3786                            && snapshot.contains_str_at(selection.end, text.as_ref())
 3787                        {
 3788                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 3789                            // and the inserted text is a closing bracket and the selection is followed
 3790                            // by the closing bracket then move the selection past the closing bracket.
 3791                            let anchor = snapshot.anchor_after(selection.end);
 3792                            new_selections.push((selection.map(|_| anchor), text.len()));
 3793                            continue;
 3794                        }
 3795                    }
 3796                    // If an opening bracket is 1 character long and is typed while
 3797                    // text is selected, then surround that text with the bracket pair.
 3798                    else if auto_surround
 3799                        && bracket_pair.surround
 3800                        && is_bracket_pair_start
 3801                        && bracket_pair.start.chars().count() == 1
 3802                    {
 3803                        edits.push((selection.start..selection.start, text.clone()));
 3804                        edits.push((
 3805                            selection.end..selection.end,
 3806                            bracket_pair.end.as_str().into(),
 3807                        ));
 3808                        bracket_inserted = true;
 3809                        new_selections.push((
 3810                            Selection {
 3811                                id: selection.id,
 3812                                start: snapshot.anchor_after(selection.start),
 3813                                end: snapshot.anchor_before(selection.end),
 3814                                reversed: selection.reversed,
 3815                                goal: selection.goal,
 3816                            },
 3817                            0,
 3818                        ));
 3819                        continue;
 3820                    }
 3821                }
 3822            }
 3823
 3824            if self.auto_replace_emoji_shortcode
 3825                && selection.is_empty()
 3826                && text.as_ref().ends_with(':')
 3827            {
 3828                if let Some(possible_emoji_short_code) =
 3829                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 3830                {
 3831                    if !possible_emoji_short_code.is_empty() {
 3832                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 3833                            let emoji_shortcode_start = Point::new(
 3834                                selection.start.row,
 3835                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 3836                            );
 3837
 3838                            // Remove shortcode from buffer
 3839                            edits.push((
 3840                                emoji_shortcode_start..selection.start,
 3841                                "".to_string().into(),
 3842                            ));
 3843                            new_selections.push((
 3844                                Selection {
 3845                                    id: selection.id,
 3846                                    start: snapshot.anchor_after(emoji_shortcode_start),
 3847                                    end: snapshot.anchor_before(selection.start),
 3848                                    reversed: selection.reversed,
 3849                                    goal: selection.goal,
 3850                                },
 3851                                0,
 3852                            ));
 3853
 3854                            // Insert emoji
 3855                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 3856                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 3857                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 3858
 3859                            continue;
 3860                        }
 3861                    }
 3862                }
 3863            }
 3864
 3865            // If not handling any auto-close operation, then just replace the selected
 3866            // text with the given input and move the selection to the end of the
 3867            // newly inserted text.
 3868            let anchor = snapshot.anchor_after(selection.end);
 3869            if !self.linked_edit_ranges.is_empty() {
 3870                let start_anchor = snapshot.anchor_before(selection.start);
 3871
 3872                let is_word_char = text.chars().next().map_or(true, |char| {
 3873                    let classifier = snapshot
 3874                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 3875                        .ignore_punctuation(true);
 3876                    classifier.is_word(char)
 3877                });
 3878
 3879                if is_word_char {
 3880                    if let Some(ranges) = self
 3881                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 3882                    {
 3883                        for (buffer, edits) in ranges {
 3884                            linked_edits
 3885                                .entry(buffer.clone())
 3886                                .or_default()
 3887                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 3888                        }
 3889                    }
 3890                } else {
 3891                    clear_linked_edit_ranges = true;
 3892                }
 3893            }
 3894
 3895            new_selections.push((selection.map(|_| anchor), 0));
 3896            edits.push((selection.start..selection.end, text.clone()));
 3897        }
 3898
 3899        drop(snapshot);
 3900
 3901        self.transact(window, cx, |this, window, cx| {
 3902            if clear_linked_edit_ranges {
 3903                this.linked_edit_ranges.clear();
 3904            }
 3905            let initial_buffer_versions =
 3906                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 3907
 3908            this.buffer.update(cx, |buffer, cx| {
 3909                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 3910            });
 3911            for (buffer, edits) in linked_edits {
 3912                buffer.update(cx, |buffer, cx| {
 3913                    let snapshot = buffer.snapshot();
 3914                    let edits = edits
 3915                        .into_iter()
 3916                        .map(|(range, text)| {
 3917                            use text::ToPoint as TP;
 3918                            let end_point = TP::to_point(&range.end, &snapshot);
 3919                            let start_point = TP::to_point(&range.start, &snapshot);
 3920                            (start_point..end_point, text)
 3921                        })
 3922                        .sorted_by_key(|(range, _)| range.start);
 3923                    buffer.edit(edits, None, cx);
 3924                })
 3925            }
 3926            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 3927            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 3928            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 3929            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 3930                .zip(new_selection_deltas)
 3931                .map(|(selection, delta)| Selection {
 3932                    id: selection.id,
 3933                    start: selection.start + delta,
 3934                    end: selection.end + delta,
 3935                    reversed: selection.reversed,
 3936                    goal: SelectionGoal::None,
 3937                })
 3938                .collect::<Vec<_>>();
 3939
 3940            let mut i = 0;
 3941            for (position, delta, selection_id, pair) in new_autoclose_regions {
 3942                let position = position.to_offset(&map.buffer_snapshot) + delta;
 3943                let start = map.buffer_snapshot.anchor_before(position);
 3944                let end = map.buffer_snapshot.anchor_after(position);
 3945                while let Some(existing_state) = this.autoclose_regions.get(i) {
 3946                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 3947                        Ordering::Less => i += 1,
 3948                        Ordering::Greater => break,
 3949                        Ordering::Equal => {
 3950                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 3951                                Ordering::Less => i += 1,
 3952                                Ordering::Equal => break,
 3953                                Ordering::Greater => break,
 3954                            }
 3955                        }
 3956                    }
 3957                }
 3958                this.autoclose_regions.insert(
 3959                    i,
 3960                    AutocloseRegion {
 3961                        selection_id,
 3962                        range: start..end,
 3963                        pair,
 3964                    },
 3965                );
 3966            }
 3967
 3968            let had_active_inline_completion = this.has_active_inline_completion();
 3969            this.change_selections_without_updating_completions(
 3970                Some(Autoscroll::fit()),
 3971                window,
 3972                cx,
 3973                |s| s.select(new_selections),
 3974            );
 3975
 3976            if !bracket_inserted {
 3977                if let Some(on_type_format_task) =
 3978                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 3979                {
 3980                    on_type_format_task.detach_and_log_err(cx);
 3981                }
 3982            }
 3983
 3984            let editor_settings = EditorSettings::get_global(cx);
 3985            if bracket_inserted
 3986                && (editor_settings.auto_signature_help
 3987                    || editor_settings.show_signature_help_after_edits)
 3988            {
 3989                this.show_signature_help(&ShowSignatureHelp, window, cx);
 3990            }
 3991
 3992            let trigger_in_words =
 3993                this.show_edit_predictions_in_menu() || !had_active_inline_completion;
 3994            if this.hard_wrap.is_some() {
 3995                let latest: Range<Point> = this.selections.newest(cx).range();
 3996                if latest.is_empty()
 3997                    && this
 3998                        .buffer()
 3999                        .read(cx)
 4000                        .snapshot(cx)
 4001                        .line_len(MultiBufferRow(latest.start.row))
 4002                        == latest.start.column
 4003                {
 4004                    this.rewrap_impl(
 4005                        RewrapOptions {
 4006                            override_language_settings: true,
 4007                            preserve_existing_whitespace: true,
 4008                        },
 4009                        cx,
 4010                    )
 4011                }
 4012            }
 4013            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4014            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4015            this.refresh_inline_completion(true, false, window, cx);
 4016            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4017        });
 4018    }
 4019
 4020    fn find_possible_emoji_shortcode_at_position(
 4021        snapshot: &MultiBufferSnapshot,
 4022        position: Point,
 4023    ) -> Option<String> {
 4024        let mut chars = Vec::new();
 4025        let mut found_colon = false;
 4026        for char in snapshot.reversed_chars_at(position).take(100) {
 4027            // Found a possible emoji shortcode in the middle of the buffer
 4028            if found_colon {
 4029                if char.is_whitespace() {
 4030                    chars.reverse();
 4031                    return Some(chars.iter().collect());
 4032                }
 4033                // If the previous character is not a whitespace, we are in the middle of a word
 4034                // and we only want to complete the shortcode if the word is made up of other emojis
 4035                let mut containing_word = String::new();
 4036                for ch in snapshot
 4037                    .reversed_chars_at(position)
 4038                    .skip(chars.len() + 1)
 4039                    .take(100)
 4040                {
 4041                    if ch.is_whitespace() {
 4042                        break;
 4043                    }
 4044                    containing_word.push(ch);
 4045                }
 4046                let containing_word = containing_word.chars().rev().collect::<String>();
 4047                if util::word_consists_of_emojis(containing_word.as_str()) {
 4048                    chars.reverse();
 4049                    return Some(chars.iter().collect());
 4050                }
 4051            }
 4052
 4053            if char.is_whitespace() || !char.is_ascii() {
 4054                return None;
 4055            }
 4056            if char == ':' {
 4057                found_colon = true;
 4058            } else {
 4059                chars.push(char);
 4060            }
 4061        }
 4062        // Found a possible emoji shortcode at the beginning of the buffer
 4063        chars.reverse();
 4064        Some(chars.iter().collect())
 4065    }
 4066
 4067    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4068        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4069        self.transact(window, cx, |this, window, cx| {
 4070            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4071                let selections = this.selections.all::<usize>(cx);
 4072                let multi_buffer = this.buffer.read(cx);
 4073                let buffer = multi_buffer.snapshot(cx);
 4074                selections
 4075                    .iter()
 4076                    .map(|selection| {
 4077                        let start_point = selection.start.to_point(&buffer);
 4078                        let mut existing_indent =
 4079                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4080                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4081                        let start = selection.start;
 4082                        let end = selection.end;
 4083                        let selection_is_empty = start == end;
 4084                        let language_scope = buffer.language_scope_at(start);
 4085                        let (
 4086                            comment_delimiter,
 4087                            doc_delimiter,
 4088                            insert_extra_newline,
 4089                            indent_on_newline,
 4090                            indent_on_extra_newline,
 4091                        ) = if let Some(language) = &language_scope {
 4092                            let mut insert_extra_newline =
 4093                                insert_extra_newline_brackets(&buffer, start..end, language)
 4094                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4095
 4096                            // Comment extension on newline is allowed only for cursor selections
 4097                            let comment_delimiter = maybe!({
 4098                                if !selection_is_empty {
 4099                                    return None;
 4100                                }
 4101
 4102                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4103                                    return None;
 4104                                }
 4105
 4106                                let delimiters = language.line_comment_prefixes();
 4107                                let max_len_of_delimiter =
 4108                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4109                                let (snapshot, range) =
 4110                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4111
 4112                                let num_of_whitespaces = snapshot
 4113                                    .chars_for_range(range.clone())
 4114                                    .take_while(|c| c.is_whitespace())
 4115                                    .count();
 4116                                let comment_candidate = snapshot
 4117                                    .chars_for_range(range)
 4118                                    .skip(num_of_whitespaces)
 4119                                    .take(max_len_of_delimiter)
 4120                                    .collect::<String>();
 4121                                let (delimiter, trimmed_len) = delimiters
 4122                                    .iter()
 4123                                    .filter_map(|delimiter| {
 4124                                        let prefix = delimiter.trim_end();
 4125                                        if comment_candidate.starts_with(prefix) {
 4126                                            Some((delimiter, prefix.len()))
 4127                                        } else {
 4128                                            None
 4129                                        }
 4130                                    })
 4131                                    .max_by_key(|(_, len)| *len)?;
 4132
 4133                                let cursor_is_placed_after_comment_marker =
 4134                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4135                                if cursor_is_placed_after_comment_marker {
 4136                                    Some(delimiter.clone())
 4137                                } else {
 4138                                    None
 4139                                }
 4140                            });
 4141
 4142                            let mut indent_on_newline = IndentSize::spaces(0);
 4143                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4144
 4145                            let doc_delimiter = maybe!({
 4146                                if !selection_is_empty {
 4147                                    return None;
 4148                                }
 4149
 4150                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4151                                    return None;
 4152                                }
 4153
 4154                                let DocumentationConfig {
 4155                                    start: start_tag,
 4156                                    end: end_tag,
 4157                                    prefix: delimiter,
 4158                                    tab_size: len,
 4159                                } = language.documentation()?;
 4160
 4161                                let is_within_block_comment = buffer
 4162                                    .language_scope_at(start_point)
 4163                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4164                                if !is_within_block_comment {
 4165                                    return None;
 4166                                }
 4167
 4168                                let (snapshot, range) =
 4169                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4170
 4171                                let num_of_whitespaces = snapshot
 4172                                    .chars_for_range(range.clone())
 4173                                    .take_while(|c| c.is_whitespace())
 4174                                    .count();
 4175
 4176                                // 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.
 4177                                let column = start_point.column;
 4178                                let cursor_is_after_start_tag = {
 4179                                    let start_tag_len = start_tag.len();
 4180                                    let start_tag_line = snapshot
 4181                                        .chars_for_range(range.clone())
 4182                                        .skip(num_of_whitespaces)
 4183                                        .take(start_tag_len)
 4184                                        .collect::<String>();
 4185                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4186                                        num_of_whitespaces + start_tag_len <= column as usize
 4187                                    } else {
 4188                                        false
 4189                                    }
 4190                                };
 4191
 4192                                let cursor_is_after_delimiter = {
 4193                                    let delimiter_trim = delimiter.trim_end();
 4194                                    let delimiter_line = snapshot
 4195                                        .chars_for_range(range.clone())
 4196                                        .skip(num_of_whitespaces)
 4197                                        .take(delimiter_trim.len())
 4198                                        .collect::<String>();
 4199                                    if delimiter_line.starts_with(delimiter_trim) {
 4200                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4201                                    } else {
 4202                                        false
 4203                                    }
 4204                                };
 4205
 4206                                let cursor_is_before_end_tag_if_exists = {
 4207                                    let mut char_position = 0u32;
 4208                                    let mut end_tag_offset = None;
 4209
 4210                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4211                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4212                                            let chars_before_match =
 4213                                                chunk[..byte_pos].chars().count() as u32;
 4214                                            end_tag_offset =
 4215                                                Some(char_position + chars_before_match);
 4216                                            break 'outer;
 4217                                        }
 4218                                        char_position += chunk.chars().count() as u32;
 4219                                    }
 4220
 4221                                    if let Some(end_tag_offset) = end_tag_offset {
 4222                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4223                                        if cursor_is_after_start_tag {
 4224                                            if cursor_is_before_end_tag {
 4225                                                insert_extra_newline = true;
 4226                                            }
 4227                                            let cursor_is_at_start_of_end_tag =
 4228                                                column == end_tag_offset;
 4229                                            if cursor_is_at_start_of_end_tag {
 4230                                                indent_on_extra_newline.len = (*len).into();
 4231                                            }
 4232                                        }
 4233                                        cursor_is_before_end_tag
 4234                                    } else {
 4235                                        true
 4236                                    }
 4237                                };
 4238
 4239                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4240                                    && cursor_is_before_end_tag_if_exists
 4241                                {
 4242                                    if cursor_is_after_start_tag {
 4243                                        indent_on_newline.len = (*len).into();
 4244                                    }
 4245                                    Some(delimiter.clone())
 4246                                } else {
 4247                                    None
 4248                                }
 4249                            });
 4250
 4251                            (
 4252                                comment_delimiter,
 4253                                doc_delimiter,
 4254                                insert_extra_newline,
 4255                                indent_on_newline,
 4256                                indent_on_extra_newline,
 4257                            )
 4258                        } else {
 4259                            (
 4260                                None,
 4261                                None,
 4262                                false,
 4263                                IndentSize::default(),
 4264                                IndentSize::default(),
 4265                            )
 4266                        };
 4267
 4268                        let prevent_auto_indent = doc_delimiter.is_some();
 4269                        let delimiter = comment_delimiter.or(doc_delimiter);
 4270
 4271                        let capacity_for_delimiter =
 4272                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4273                        let mut new_text = String::with_capacity(
 4274                            1 + capacity_for_delimiter
 4275                                + existing_indent.len as usize
 4276                                + indent_on_newline.len as usize
 4277                                + indent_on_extra_newline.len as usize,
 4278                        );
 4279                        new_text.push('\n');
 4280                        new_text.extend(existing_indent.chars());
 4281                        new_text.extend(indent_on_newline.chars());
 4282
 4283                        if let Some(delimiter) = &delimiter {
 4284                            new_text.push_str(delimiter);
 4285                        }
 4286
 4287                        if insert_extra_newline {
 4288                            new_text.push('\n');
 4289                            new_text.extend(existing_indent.chars());
 4290                            new_text.extend(indent_on_extra_newline.chars());
 4291                        }
 4292
 4293                        let anchor = buffer.anchor_after(end);
 4294                        let new_selection = selection.map(|_| anchor);
 4295                        (
 4296                            ((start..end, new_text), prevent_auto_indent),
 4297                            (insert_extra_newline, new_selection),
 4298                        )
 4299                    })
 4300                    .unzip()
 4301            };
 4302
 4303            let mut auto_indent_edits = Vec::new();
 4304            let mut edits = Vec::new();
 4305            for (edit, prevent_auto_indent) in edits_with_flags {
 4306                if prevent_auto_indent {
 4307                    edits.push(edit);
 4308                } else {
 4309                    auto_indent_edits.push(edit);
 4310                }
 4311            }
 4312            if !edits.is_empty() {
 4313                this.edit(edits, cx);
 4314            }
 4315            if !auto_indent_edits.is_empty() {
 4316                this.edit_with_autoindent(auto_indent_edits, cx);
 4317            }
 4318
 4319            let buffer = this.buffer.read(cx).snapshot(cx);
 4320            let new_selections = selection_info
 4321                .into_iter()
 4322                .map(|(extra_newline_inserted, new_selection)| {
 4323                    let mut cursor = new_selection.end.to_point(&buffer);
 4324                    if extra_newline_inserted {
 4325                        cursor.row -= 1;
 4326                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4327                    }
 4328                    new_selection.map(|_| cursor)
 4329                })
 4330                .collect();
 4331
 4332            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4333                s.select(new_selections)
 4334            });
 4335            this.refresh_inline_completion(true, false, window, cx);
 4336        });
 4337    }
 4338
 4339    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4340        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4341
 4342        let buffer = self.buffer.read(cx);
 4343        let snapshot = buffer.snapshot(cx);
 4344
 4345        let mut edits = Vec::new();
 4346        let mut rows = Vec::new();
 4347
 4348        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4349            let cursor = selection.head();
 4350            let row = cursor.row;
 4351
 4352            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4353
 4354            let newline = "\n".to_string();
 4355            edits.push((start_of_line..start_of_line, newline));
 4356
 4357            rows.push(row + rows_inserted as u32);
 4358        }
 4359
 4360        self.transact(window, cx, |editor, window, cx| {
 4361            editor.edit(edits, cx);
 4362
 4363            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4364                let mut index = 0;
 4365                s.move_cursors_with(|map, _, _| {
 4366                    let row = rows[index];
 4367                    index += 1;
 4368
 4369                    let point = Point::new(row, 0);
 4370                    let boundary = map.next_line_boundary(point).1;
 4371                    let clipped = map.clip_point(boundary, Bias::Left);
 4372
 4373                    (clipped, SelectionGoal::None)
 4374                });
 4375            });
 4376
 4377            let mut indent_edits = Vec::new();
 4378            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4379            for row in rows {
 4380                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4381                for (row, indent) in indents {
 4382                    if indent.len == 0 {
 4383                        continue;
 4384                    }
 4385
 4386                    let text = match indent.kind {
 4387                        IndentKind::Space => " ".repeat(indent.len as usize),
 4388                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4389                    };
 4390                    let point = Point::new(row.0, 0);
 4391                    indent_edits.push((point..point, text));
 4392                }
 4393            }
 4394            editor.edit(indent_edits, cx);
 4395        });
 4396    }
 4397
 4398    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4399        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 4400
 4401        let buffer = self.buffer.read(cx);
 4402        let snapshot = buffer.snapshot(cx);
 4403
 4404        let mut edits = Vec::new();
 4405        let mut rows = Vec::new();
 4406        let mut rows_inserted = 0;
 4407
 4408        for selection in self.selections.all_adjusted(cx) {
 4409            let cursor = selection.head();
 4410            let row = cursor.row;
 4411
 4412            let point = Point::new(row + 1, 0);
 4413            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4414
 4415            let newline = "\n".to_string();
 4416            edits.push((start_of_line..start_of_line, newline));
 4417
 4418            rows_inserted += 1;
 4419            rows.push(row + rows_inserted);
 4420        }
 4421
 4422        self.transact(window, cx, |editor, window, cx| {
 4423            editor.edit(edits, cx);
 4424
 4425            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4426                let mut index = 0;
 4427                s.move_cursors_with(|map, _, _| {
 4428                    let row = rows[index];
 4429                    index += 1;
 4430
 4431                    let point = Point::new(row, 0);
 4432                    let boundary = map.next_line_boundary(point).1;
 4433                    let clipped = map.clip_point(boundary, Bias::Left);
 4434
 4435                    (clipped, SelectionGoal::None)
 4436                });
 4437            });
 4438
 4439            let mut indent_edits = Vec::new();
 4440            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4441            for row in rows {
 4442                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4443                for (row, indent) in indents {
 4444                    if indent.len == 0 {
 4445                        continue;
 4446                    }
 4447
 4448                    let text = match indent.kind {
 4449                        IndentKind::Space => " ".repeat(indent.len as usize),
 4450                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4451                    };
 4452                    let point = Point::new(row.0, 0);
 4453                    indent_edits.push((point..point, text));
 4454                }
 4455            }
 4456            editor.edit(indent_edits, cx);
 4457        });
 4458    }
 4459
 4460    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4461        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4462            original_indent_columns: Vec::new(),
 4463        });
 4464        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4465    }
 4466
 4467    fn insert_with_autoindent_mode(
 4468        &mut self,
 4469        text: &str,
 4470        autoindent_mode: Option<AutoindentMode>,
 4471        window: &mut Window,
 4472        cx: &mut Context<Self>,
 4473    ) {
 4474        if self.read_only(cx) {
 4475            return;
 4476        }
 4477
 4478        let text: Arc<str> = text.into();
 4479        self.transact(window, cx, |this, window, cx| {
 4480            let old_selections = this.selections.all_adjusted(cx);
 4481            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4482                let anchors = {
 4483                    let snapshot = buffer.read(cx);
 4484                    old_selections
 4485                        .iter()
 4486                        .map(|s| {
 4487                            let anchor = snapshot.anchor_after(s.head());
 4488                            s.map(|_| anchor)
 4489                        })
 4490                        .collect::<Vec<_>>()
 4491                };
 4492                buffer.edit(
 4493                    old_selections
 4494                        .iter()
 4495                        .map(|s| (s.start..s.end, text.clone())),
 4496                    autoindent_mode,
 4497                    cx,
 4498                );
 4499                anchors
 4500            });
 4501
 4502            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 4503                s.select_anchors(selection_anchors);
 4504            });
 4505
 4506            cx.notify();
 4507        });
 4508    }
 4509
 4510    fn trigger_completion_on_input(
 4511        &mut self,
 4512        text: &str,
 4513        trigger_in_words: bool,
 4514        window: &mut Window,
 4515        cx: &mut Context<Self>,
 4516    ) {
 4517        let completions_source = self
 4518            .context_menu
 4519            .borrow()
 4520            .as_ref()
 4521            .and_then(|menu| match menu {
 4522                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4523                CodeContextMenu::CodeActions(_) => None,
 4524            });
 4525
 4526        match completions_source {
 4527            Some(CompletionsMenuSource::Words) => {
 4528                self.show_word_completions(&ShowWordCompletions, window, cx)
 4529            }
 4530            Some(CompletionsMenuSource::Normal)
 4531            | Some(CompletionsMenuSource::SnippetChoices)
 4532            | None
 4533                if self.is_completion_trigger(
 4534                    text,
 4535                    trigger_in_words,
 4536                    completions_source.is_some(),
 4537                    cx,
 4538                ) =>
 4539            {
 4540                self.show_completions(
 4541                    &ShowCompletions {
 4542                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4543                    },
 4544                    window,
 4545                    cx,
 4546                )
 4547            }
 4548            _ => {
 4549                self.hide_context_menu(window, cx);
 4550            }
 4551        }
 4552    }
 4553
 4554    fn is_completion_trigger(
 4555        &self,
 4556        text: &str,
 4557        trigger_in_words: bool,
 4558        menu_is_open: bool,
 4559        cx: &mut Context<Self>,
 4560    ) -> bool {
 4561        let position = self.selections.newest_anchor().head();
 4562        let multibuffer = self.buffer.read(cx);
 4563        let Some(buffer) = position
 4564            .buffer_id
 4565            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4566        else {
 4567            return false;
 4568        };
 4569
 4570        if let Some(completion_provider) = &self.completion_provider {
 4571            completion_provider.is_completion_trigger(
 4572                &buffer,
 4573                position.text_anchor,
 4574                text,
 4575                trigger_in_words,
 4576                menu_is_open,
 4577                cx,
 4578            )
 4579        } else {
 4580            false
 4581        }
 4582    }
 4583
 4584    /// If any empty selections is touching the start of its innermost containing autoclose
 4585    /// region, expand it to select the brackets.
 4586    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4587        let selections = self.selections.all::<usize>(cx);
 4588        let buffer = self.buffer.read(cx).read(cx);
 4589        let new_selections = self
 4590            .selections_with_autoclose_regions(selections, &buffer)
 4591            .map(|(mut selection, region)| {
 4592                if !selection.is_empty() {
 4593                    return selection;
 4594                }
 4595
 4596                if let Some(region) = region {
 4597                    let mut range = region.range.to_offset(&buffer);
 4598                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4599                        range.start -= region.pair.start.len();
 4600                        if buffer.contains_str_at(range.start, &region.pair.start)
 4601                            && buffer.contains_str_at(range.end, &region.pair.end)
 4602                        {
 4603                            range.end += region.pair.end.len();
 4604                            selection.start = range.start;
 4605                            selection.end = range.end;
 4606
 4607                            return selection;
 4608                        }
 4609                    }
 4610                }
 4611
 4612                let always_treat_brackets_as_autoclosed = buffer
 4613                    .language_settings_at(selection.start, cx)
 4614                    .always_treat_brackets_as_autoclosed;
 4615
 4616                if !always_treat_brackets_as_autoclosed {
 4617                    return selection;
 4618                }
 4619
 4620                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4621                    for (pair, enabled) in scope.brackets() {
 4622                        if !enabled || !pair.close {
 4623                            continue;
 4624                        }
 4625
 4626                        if buffer.contains_str_at(selection.start, &pair.end) {
 4627                            let pair_start_len = pair.start.len();
 4628                            if buffer.contains_str_at(
 4629                                selection.start.saturating_sub(pair_start_len),
 4630                                &pair.start,
 4631                            ) {
 4632                                selection.start -= pair_start_len;
 4633                                selection.end += pair.end.len();
 4634
 4635                                return selection;
 4636                            }
 4637                        }
 4638                    }
 4639                }
 4640
 4641                selection
 4642            })
 4643            .collect();
 4644
 4645        drop(buffer);
 4646        self.change_selections(None, window, cx, |selections| {
 4647            selections.select(new_selections)
 4648        });
 4649    }
 4650
 4651    /// Iterate the given selections, and for each one, find the smallest surrounding
 4652    /// autoclose region. This uses the ordering of the selections and the autoclose
 4653    /// regions to avoid repeated comparisons.
 4654    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4655        &'a self,
 4656        selections: impl IntoIterator<Item = Selection<D>>,
 4657        buffer: &'a MultiBufferSnapshot,
 4658    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4659        let mut i = 0;
 4660        let mut regions = self.autoclose_regions.as_slice();
 4661        selections.into_iter().map(move |selection| {
 4662            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4663
 4664            let mut enclosing = None;
 4665            while let Some(pair_state) = regions.get(i) {
 4666                if pair_state.range.end.to_offset(buffer) < range.start {
 4667                    regions = &regions[i + 1..];
 4668                    i = 0;
 4669                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4670                    break;
 4671                } else {
 4672                    if pair_state.selection_id == selection.id {
 4673                        enclosing = Some(pair_state);
 4674                    }
 4675                    i += 1;
 4676                }
 4677            }
 4678
 4679            (selection, enclosing)
 4680        })
 4681    }
 4682
 4683    /// Remove any autoclose regions that no longer contain their selection.
 4684    fn invalidate_autoclose_regions(
 4685        &mut self,
 4686        mut selections: &[Selection<Anchor>],
 4687        buffer: &MultiBufferSnapshot,
 4688    ) {
 4689        self.autoclose_regions.retain(|state| {
 4690            let mut i = 0;
 4691            while let Some(selection) = selections.get(i) {
 4692                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 4693                    selections = &selections[1..];
 4694                    continue;
 4695                }
 4696                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 4697                    break;
 4698                }
 4699                if selection.id == state.selection_id {
 4700                    return true;
 4701                } else {
 4702                    i += 1;
 4703                }
 4704            }
 4705            false
 4706        });
 4707    }
 4708
 4709    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 4710        let offset = position.to_offset(buffer);
 4711        let (word_range, kind) = buffer.surrounding_word(offset, true);
 4712        if offset > word_range.start && kind == Some(CharKind::Word) {
 4713            Some(
 4714                buffer
 4715                    .text_for_range(word_range.start..offset)
 4716                    .collect::<String>(),
 4717            )
 4718        } else {
 4719            None
 4720        }
 4721    }
 4722
 4723    pub fn toggle_inline_values(
 4724        &mut self,
 4725        _: &ToggleInlineValues,
 4726        _: &mut Window,
 4727        cx: &mut Context<Self>,
 4728    ) {
 4729        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 4730
 4731        self.refresh_inline_values(cx);
 4732    }
 4733
 4734    pub fn toggle_inlay_hints(
 4735        &mut self,
 4736        _: &ToggleInlayHints,
 4737        _: &mut Window,
 4738        cx: &mut Context<Self>,
 4739    ) {
 4740        self.refresh_inlay_hints(
 4741            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 4742            cx,
 4743        );
 4744    }
 4745
 4746    pub fn inlay_hints_enabled(&self) -> bool {
 4747        self.inlay_hint_cache.enabled
 4748    }
 4749
 4750    pub fn inline_values_enabled(&self) -> bool {
 4751        self.inline_value_cache.enabled
 4752    }
 4753
 4754    #[cfg(any(test, feature = "test-support"))]
 4755    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 4756        self.display_map
 4757            .read(cx)
 4758            .current_inlays()
 4759            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 4760            .cloned()
 4761            .collect()
 4762    }
 4763
 4764    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 4765        if self.semantics_provider.is_none() || !self.mode.is_full() {
 4766            return;
 4767        }
 4768
 4769        let reason_description = reason.description();
 4770        let ignore_debounce = matches!(
 4771            reason,
 4772            InlayHintRefreshReason::SettingsChange(_)
 4773                | InlayHintRefreshReason::Toggle(_)
 4774                | InlayHintRefreshReason::ExcerptsRemoved(_)
 4775                | InlayHintRefreshReason::ModifiersChanged(_)
 4776        );
 4777        let (invalidate_cache, required_languages) = match reason {
 4778            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 4779                match self.inlay_hint_cache.modifiers_override(enabled) {
 4780                    Some(enabled) => {
 4781                        if enabled {
 4782                            (InvalidationStrategy::RefreshRequested, None)
 4783                        } else {
 4784                            self.splice_inlays(
 4785                                &self
 4786                                    .visible_inlay_hints(cx)
 4787                                    .iter()
 4788                                    .map(|inlay| inlay.id)
 4789                                    .collect::<Vec<InlayId>>(),
 4790                                Vec::new(),
 4791                                cx,
 4792                            );
 4793                            return;
 4794                        }
 4795                    }
 4796                    None => return,
 4797                }
 4798            }
 4799            InlayHintRefreshReason::Toggle(enabled) => {
 4800                if self.inlay_hint_cache.toggle(enabled) {
 4801                    if enabled {
 4802                        (InvalidationStrategy::RefreshRequested, None)
 4803                    } else {
 4804                        self.splice_inlays(
 4805                            &self
 4806                                .visible_inlay_hints(cx)
 4807                                .iter()
 4808                                .map(|inlay| inlay.id)
 4809                                .collect::<Vec<InlayId>>(),
 4810                            Vec::new(),
 4811                            cx,
 4812                        );
 4813                        return;
 4814                    }
 4815                } else {
 4816                    return;
 4817                }
 4818            }
 4819            InlayHintRefreshReason::SettingsChange(new_settings) => {
 4820                match self.inlay_hint_cache.update_settings(
 4821                    &self.buffer,
 4822                    new_settings,
 4823                    self.visible_inlay_hints(cx),
 4824                    cx,
 4825                ) {
 4826                    ControlFlow::Break(Some(InlaySplice {
 4827                        to_remove,
 4828                        to_insert,
 4829                    })) => {
 4830                        self.splice_inlays(&to_remove, to_insert, cx);
 4831                        return;
 4832                    }
 4833                    ControlFlow::Break(None) => return,
 4834                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 4835                }
 4836            }
 4837            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 4838                if let Some(InlaySplice {
 4839                    to_remove,
 4840                    to_insert,
 4841                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 4842                {
 4843                    self.splice_inlays(&to_remove, to_insert, cx);
 4844                }
 4845                self.display_map.update(cx, |display_map, _| {
 4846                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 4847                });
 4848                return;
 4849            }
 4850            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 4851            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 4852                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 4853            }
 4854            InlayHintRefreshReason::RefreshRequested => {
 4855                (InvalidationStrategy::RefreshRequested, None)
 4856            }
 4857        };
 4858
 4859        if let Some(InlaySplice {
 4860            to_remove,
 4861            to_insert,
 4862        }) = self.inlay_hint_cache.spawn_hint_refresh(
 4863            reason_description,
 4864            self.excerpts_for_inlay_hints_query(required_languages.as_ref(), cx),
 4865            invalidate_cache,
 4866            ignore_debounce,
 4867            cx,
 4868        ) {
 4869            self.splice_inlays(&to_remove, to_insert, cx);
 4870        }
 4871    }
 4872
 4873    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 4874        self.display_map
 4875            .read(cx)
 4876            .current_inlays()
 4877            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 4878            .cloned()
 4879            .collect()
 4880    }
 4881
 4882    pub fn excerpts_for_inlay_hints_query(
 4883        &self,
 4884        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 4885        cx: &mut Context<Editor>,
 4886    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 4887        let Some(project) = self.project.as_ref() else {
 4888            return HashMap::default();
 4889        };
 4890        let project = project.read(cx);
 4891        let multi_buffer = self.buffer().read(cx);
 4892        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 4893        let multi_buffer_visible_start = self
 4894            .scroll_manager
 4895            .anchor()
 4896            .anchor
 4897            .to_point(&multi_buffer_snapshot);
 4898        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 4899            multi_buffer_visible_start
 4900                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 4901            Bias::Left,
 4902        );
 4903        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 4904        multi_buffer_snapshot
 4905            .range_to_buffer_ranges(multi_buffer_visible_range)
 4906            .into_iter()
 4907            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 4908            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 4909                let buffer_file = project::File::from_dyn(buffer.file())?;
 4910                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 4911                let worktree_entry = buffer_worktree
 4912                    .read(cx)
 4913                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 4914                if worktree_entry.is_ignored {
 4915                    return None;
 4916                }
 4917
 4918                let language = buffer.language()?;
 4919                if let Some(restrict_to_languages) = restrict_to_languages {
 4920                    if !restrict_to_languages.contains(language) {
 4921                        return None;
 4922                    }
 4923                }
 4924                Some((
 4925                    excerpt_id,
 4926                    (
 4927                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 4928                        buffer.version().clone(),
 4929                        excerpt_visible_range,
 4930                    ),
 4931                ))
 4932            })
 4933            .collect()
 4934    }
 4935
 4936    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 4937        TextLayoutDetails {
 4938            text_system: window.text_system().clone(),
 4939            editor_style: self.style.clone().unwrap(),
 4940            rem_size: window.rem_size(),
 4941            scroll_anchor: self.scroll_manager.anchor(),
 4942            visible_rows: self.visible_line_count(),
 4943            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 4944        }
 4945    }
 4946
 4947    pub fn splice_inlays(
 4948        &self,
 4949        to_remove: &[InlayId],
 4950        to_insert: Vec<Inlay>,
 4951        cx: &mut Context<Self>,
 4952    ) {
 4953        self.display_map.update(cx, |display_map, cx| {
 4954            display_map.splice_inlays(to_remove, to_insert, cx)
 4955        });
 4956        cx.notify();
 4957    }
 4958
 4959    fn trigger_on_type_formatting(
 4960        &self,
 4961        input: String,
 4962        window: &mut Window,
 4963        cx: &mut Context<Self>,
 4964    ) -> Option<Task<Result<()>>> {
 4965        if input.len() != 1 {
 4966            return None;
 4967        }
 4968
 4969        let project = self.project.as_ref()?;
 4970        let position = self.selections.newest_anchor().head();
 4971        let (buffer, buffer_position) = self
 4972            .buffer
 4973            .read(cx)
 4974            .text_anchor_for_position(position, cx)?;
 4975
 4976        let settings = language_settings::language_settings(
 4977            buffer
 4978                .read(cx)
 4979                .language_at(buffer_position)
 4980                .map(|l| l.name()),
 4981            buffer.read(cx).file(),
 4982            cx,
 4983        );
 4984        if !settings.use_on_type_format {
 4985            return None;
 4986        }
 4987
 4988        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 4989        // hence we do LSP request & edit on host side only — add formats to host's history.
 4990        let push_to_lsp_host_history = true;
 4991        // If this is not the host, append its history with new edits.
 4992        let push_to_client_history = project.read(cx).is_via_collab();
 4993
 4994        let on_type_formatting = project.update(cx, |project, cx| {
 4995            project.on_type_format(
 4996                buffer.clone(),
 4997                buffer_position,
 4998                input,
 4999                push_to_lsp_host_history,
 5000                cx,
 5001            )
 5002        });
 5003        Some(cx.spawn_in(window, async move |editor, cx| {
 5004            if let Some(transaction) = on_type_formatting.await? {
 5005                if push_to_client_history {
 5006                    buffer
 5007                        .update(cx, |buffer, _| {
 5008                            buffer.push_transaction(transaction, Instant::now());
 5009                            buffer.finalize_last_transaction();
 5010                        })
 5011                        .ok();
 5012                }
 5013                editor.update(cx, |editor, cx| {
 5014                    editor.refresh_document_highlights(cx);
 5015                })?;
 5016            }
 5017            Ok(())
 5018        }))
 5019    }
 5020
 5021    pub fn show_word_completions(
 5022        &mut self,
 5023        _: &ShowWordCompletions,
 5024        window: &mut Window,
 5025        cx: &mut Context<Self>,
 5026    ) {
 5027        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5028    }
 5029
 5030    pub fn show_completions(
 5031        &mut self,
 5032        options: &ShowCompletions,
 5033        window: &mut Window,
 5034        cx: &mut Context<Self>,
 5035    ) {
 5036        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5037    }
 5038
 5039    fn open_or_update_completions_menu(
 5040        &mut self,
 5041        requested_source: Option<CompletionsMenuSource>,
 5042        trigger: Option<&str>,
 5043        window: &mut Window,
 5044        cx: &mut Context<Self>,
 5045    ) {
 5046        if self.pending_rename.is_some() {
 5047            return;
 5048        }
 5049
 5050        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5051
 5052        let position = self
 5053            .selections
 5054            .newest_anchor()
 5055            .head()
 5056            .bias_right(&multibuffer_snapshot);
 5057        if position.diff_base_anchor.is_some() {
 5058            return;
 5059        }
 5060        let (buffer, buffer_position) =
 5061            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5062                output
 5063            } else {
 5064                return;
 5065            };
 5066        let buffer_snapshot = buffer.read(cx).snapshot();
 5067
 5068        let query: Option<Arc<String>> =
 5069            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5070
 5071        drop(multibuffer_snapshot);
 5072
 5073        let provider = match requested_source {
 5074            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5075            Some(CompletionsMenuSource::Words) => None,
 5076            Some(CompletionsMenuSource::SnippetChoices) => {
 5077                log::error!("bug: SnippetChoices requested_source is not handled");
 5078                None
 5079            }
 5080        };
 5081
 5082        let sort_completions = provider
 5083            .as_ref()
 5084            .map_or(false, |provider| provider.sort_completions());
 5085
 5086        let filter_completions = provider
 5087            .as_ref()
 5088            .map_or(true, |provider| provider.filter_completions());
 5089
 5090        // When `is_incomplete` is false, can filter completions instead of re-querying when the
 5091        // current query is a suffix of the initial query.
 5092        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5093            if !menu.is_incomplete && filter_completions {
 5094                // If the new query is a suffix of the old query (typing more characters) and
 5095                // the previous result was complete, the existing completions can be filtered.
 5096                //
 5097                // Note that this is always true for snippet completions.
 5098                let query_matches = match (&menu.initial_query, &query) {
 5099                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5100                    (None, _) => true,
 5101                    _ => false,
 5102                };
 5103                if query_matches {
 5104                    let position_matches = if menu.initial_position == position {
 5105                        true
 5106                    } else {
 5107                        let snapshot = self.buffer.read(cx).read(cx);
 5108                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5109                    };
 5110                    if position_matches {
 5111                        menu.filter(query.clone(), provider.clone(), window, cx);
 5112                        return;
 5113                    }
 5114                }
 5115            }
 5116        };
 5117
 5118        let trigger_kind = match trigger {
 5119            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5120                CompletionTriggerKind::TRIGGER_CHARACTER
 5121            }
 5122            _ => CompletionTriggerKind::INVOKED,
 5123        };
 5124        let completion_context = CompletionContext {
 5125            trigger_character: trigger.and_then(|trigger| {
 5126                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5127                    Some(String::from(trigger))
 5128                } else {
 5129                    None
 5130                }
 5131            }),
 5132            trigger_kind,
 5133        };
 5134
 5135        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5136            buffer_snapshot.surrounding_word(buffer_position)
 5137        {
 5138            let word_to_exclude = buffer_snapshot
 5139                .text_for_range(word_range.clone())
 5140                .collect::<String>();
 5141            (
 5142                buffer_snapshot.anchor_before(word_range.start)
 5143                    ..buffer_snapshot.anchor_after(buffer_position),
 5144                Some(word_to_exclude),
 5145            )
 5146        } else {
 5147            (buffer_position..buffer_position, None)
 5148        };
 5149
 5150        let language = buffer_snapshot
 5151            .language_at(buffer_position)
 5152            .map(|language| language.name());
 5153
 5154        let completion_settings =
 5155            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5156
 5157        let show_completion_documentation = buffer_snapshot
 5158            .settings_at(buffer_position, cx)
 5159            .show_completion_documentation;
 5160
 5161        // The document can be large, so stay in reasonable bounds when searching for words,
 5162        // otherwise completion pop-up might be slow to appear.
 5163        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5164        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5165        let min_word_search = buffer_snapshot.clip_point(
 5166            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5167            Bias::Left,
 5168        );
 5169        let max_word_search = buffer_snapshot.clip_point(
 5170            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5171            Bias::Right,
 5172        );
 5173        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5174            ..buffer_snapshot.point_to_offset(max_word_search);
 5175
 5176        let skip_digits = query
 5177            .as_ref()
 5178            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5179
 5180        let (mut words, provider_responses) = match &provider {
 5181            Some(provider) => {
 5182                let provider_responses = provider.completions(
 5183                    position.excerpt_id,
 5184                    &buffer,
 5185                    buffer_position,
 5186                    completion_context,
 5187                    window,
 5188                    cx,
 5189                );
 5190
 5191                let words = match completion_settings.words {
 5192                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5193                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5194                        .background_spawn(async move {
 5195                            buffer_snapshot.words_in_range(WordsQuery {
 5196                                fuzzy_contents: None,
 5197                                range: word_search_range,
 5198                                skip_digits,
 5199                            })
 5200                        }),
 5201                };
 5202
 5203                (words, provider_responses)
 5204            }
 5205            None => (
 5206                cx.background_spawn(async move {
 5207                    buffer_snapshot.words_in_range(WordsQuery {
 5208                        fuzzy_contents: None,
 5209                        range: word_search_range,
 5210                        skip_digits,
 5211                    })
 5212                }),
 5213                Task::ready(Ok(Vec::new())),
 5214            ),
 5215        };
 5216
 5217        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5218
 5219        let id = post_inc(&mut self.next_completion_id);
 5220        let task = cx.spawn_in(window, async move |editor, cx| {
 5221            let Ok(()) = editor.update(cx, |this, _| {
 5222                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5223            }) else {
 5224                return;
 5225            };
 5226
 5227            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5228            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5229            let mut completions = Vec::new();
 5230            let mut is_incomplete = false;
 5231            if let Some(provider_responses) = provider_responses.await.log_err() {
 5232                if !provider_responses.is_empty() {
 5233                    for response in provider_responses {
 5234                        completions.extend(response.completions);
 5235                        is_incomplete = is_incomplete || response.is_incomplete;
 5236                    }
 5237                    if completion_settings.words == WordsCompletionMode::Fallback {
 5238                        words = Task::ready(BTreeMap::default());
 5239                    }
 5240                }
 5241            }
 5242
 5243            let mut words = words.await;
 5244            if let Some(word_to_exclude) = &word_to_exclude {
 5245                words.remove(word_to_exclude);
 5246            }
 5247            for lsp_completion in &completions {
 5248                words.remove(&lsp_completion.new_text);
 5249            }
 5250            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5251                replace_range: word_replace_range.clone(),
 5252                new_text: word.clone(),
 5253                label: CodeLabel::plain(word, None),
 5254                icon_path: None,
 5255                documentation: None,
 5256                source: CompletionSource::BufferWord {
 5257                    word_range,
 5258                    resolved: false,
 5259                },
 5260                insert_text_mode: Some(InsertTextMode::AS_IS),
 5261                confirm: None,
 5262            }));
 5263
 5264            let menu = if completions.is_empty() {
 5265                None
 5266            } else {
 5267                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5268                    let languages = editor
 5269                        .workspace
 5270                        .as_ref()
 5271                        .and_then(|(workspace, _)| workspace.upgrade())
 5272                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5273                    let menu = CompletionsMenu::new(
 5274                        id,
 5275                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5276                        sort_completions,
 5277                        show_completion_documentation,
 5278                        position,
 5279                        query.clone(),
 5280                        is_incomplete,
 5281                        buffer.clone(),
 5282                        completions.into(),
 5283                        snippet_sort_order,
 5284                        languages,
 5285                        language,
 5286                        cx,
 5287                    );
 5288
 5289                    let query = if filter_completions { query } else { None };
 5290                    let matches_task = if let Some(query) = query {
 5291                        menu.do_async_filtering(query, cx)
 5292                    } else {
 5293                        Task::ready(menu.unfiltered_matches())
 5294                    };
 5295                    (menu, matches_task)
 5296                }) else {
 5297                    return;
 5298                };
 5299
 5300                let matches = matches_task.await;
 5301
 5302                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5303                    // Newer menu already set, so exit.
 5304                    match editor.context_menu.borrow().as_ref() {
 5305                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5306                            if prev_menu.id > id {
 5307                                return;
 5308                            }
 5309                        }
 5310                        _ => {}
 5311                    };
 5312
 5313                    // Only valid to take prev_menu because it the new menu is immediately set
 5314                    // below, or the menu is hidden.
 5315                    match editor.context_menu.borrow_mut().take() {
 5316                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5317                            let position_matches =
 5318                                if prev_menu.initial_position == menu.initial_position {
 5319                                    true
 5320                                } else {
 5321                                    let snapshot = editor.buffer.read(cx).read(cx);
 5322                                    prev_menu.initial_position.to_offset(&snapshot)
 5323                                        == menu.initial_position.to_offset(&snapshot)
 5324                                };
 5325                            if position_matches {
 5326                                // Preserve markdown cache before `set_filter_results` because it will
 5327                                // try to populate the documentation cache.
 5328                                menu.preserve_markdown_cache(prev_menu);
 5329                            }
 5330                        }
 5331                        _ => {}
 5332                    };
 5333
 5334                    menu.set_filter_results(matches, provider, window, cx);
 5335                }) else {
 5336                    return;
 5337                };
 5338
 5339                menu.visible().then_some(menu)
 5340            };
 5341
 5342            editor
 5343                .update_in(cx, |editor, window, cx| {
 5344                    if editor.focus_handle.is_focused(window) {
 5345                        if let Some(menu) = menu {
 5346                            *editor.context_menu.borrow_mut() =
 5347                                Some(CodeContextMenu::Completions(menu));
 5348
 5349                            crate::hover_popover::hide_hover(editor, cx);
 5350                            if editor.show_edit_predictions_in_menu() {
 5351                                editor.update_visible_inline_completion(window, cx);
 5352                            } else {
 5353                                editor.discard_inline_completion(false, cx);
 5354                            }
 5355
 5356                            cx.notify();
 5357                            return;
 5358                        }
 5359                    }
 5360
 5361                    if editor.completion_tasks.len() <= 1 {
 5362                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5363                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5364                        // If it was already hidden and we don't show inline completions in the menu, we should
 5365                        // also show the inline-completion when available.
 5366                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5367                            editor.update_visible_inline_completion(window, cx);
 5368                        }
 5369                    }
 5370                })
 5371                .ok();
 5372        });
 5373
 5374        self.completion_tasks.push((id, task));
 5375    }
 5376
 5377    #[cfg(feature = "test-support")]
 5378    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5379        let menu = self.context_menu.borrow();
 5380        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5381            let completions = menu.completions.borrow();
 5382            Some(completions.to_vec())
 5383        } else {
 5384            None
 5385        }
 5386    }
 5387
 5388    pub fn with_completions_menu_matching_id<R>(
 5389        &self,
 5390        id: CompletionId,
 5391        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5392    ) -> R {
 5393        let mut context_menu = self.context_menu.borrow_mut();
 5394        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5395            return f(None);
 5396        };
 5397        if completions_menu.id != id {
 5398            return f(None);
 5399        }
 5400        f(Some(completions_menu))
 5401    }
 5402
 5403    pub fn confirm_completion(
 5404        &mut self,
 5405        action: &ConfirmCompletion,
 5406        window: &mut Window,
 5407        cx: &mut Context<Self>,
 5408    ) -> Option<Task<Result<()>>> {
 5409        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5410        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5411    }
 5412
 5413    pub fn confirm_completion_insert(
 5414        &mut self,
 5415        _: &ConfirmCompletionInsert,
 5416        window: &mut Window,
 5417        cx: &mut Context<Self>,
 5418    ) -> Option<Task<Result<()>>> {
 5419        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5420        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5421    }
 5422
 5423    pub fn confirm_completion_replace(
 5424        &mut self,
 5425        _: &ConfirmCompletionReplace,
 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::CompleteWithReplace, window, cx)
 5431    }
 5432
 5433    pub fn compose_completion(
 5434        &mut self,
 5435        action: &ComposeCompletion,
 5436        window: &mut Window,
 5437        cx: &mut Context<Self>,
 5438    ) -> Option<Task<Result<()>>> {
 5439        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5440        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5441    }
 5442
 5443    fn do_completion(
 5444        &mut self,
 5445        item_ix: Option<usize>,
 5446        intent: CompletionIntent,
 5447        window: &mut Window,
 5448        cx: &mut Context<Editor>,
 5449    ) -> Option<Task<Result<()>>> {
 5450        use language::ToOffset as _;
 5451
 5452        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5453        else {
 5454            return None;
 5455        };
 5456
 5457        let candidate_id = {
 5458            let entries = completions_menu.entries.borrow();
 5459            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5460            if self.show_edit_predictions_in_menu() {
 5461                self.discard_inline_completion(true, cx);
 5462            }
 5463            mat.candidate_id
 5464        };
 5465
 5466        let completion = completions_menu
 5467            .completions
 5468            .borrow()
 5469            .get(candidate_id)?
 5470            .clone();
 5471        cx.stop_propagation();
 5472
 5473        let buffer_handle = completions_menu.buffer.clone();
 5474
 5475        let CompletionEdit {
 5476            new_text,
 5477            snippet,
 5478            replace_range,
 5479        } = process_completion_for_edit(
 5480            &completion,
 5481            intent,
 5482            &buffer_handle,
 5483            &completions_menu.initial_position.text_anchor,
 5484            cx,
 5485        );
 5486
 5487        let buffer = buffer_handle.read(cx);
 5488        let snapshot = self.buffer.read(cx).snapshot(cx);
 5489        let newest_anchor = self.selections.newest_anchor();
 5490        let replace_range_multibuffer = {
 5491            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5492            let multibuffer_anchor = snapshot
 5493                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5494                .unwrap()
 5495                ..snapshot
 5496                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5497                    .unwrap();
 5498            multibuffer_anchor.start.to_offset(&snapshot)
 5499                ..multibuffer_anchor.end.to_offset(&snapshot)
 5500        };
 5501        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5502            return None;
 5503        }
 5504
 5505        let old_text = buffer
 5506            .text_for_range(replace_range.clone())
 5507            .collect::<String>();
 5508        let lookbehind = newest_anchor
 5509            .start
 5510            .text_anchor
 5511            .to_offset(buffer)
 5512            .saturating_sub(replace_range.start);
 5513        let lookahead = replace_range
 5514            .end
 5515            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5516        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5517        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5518
 5519        let selections = self.selections.all::<usize>(cx);
 5520        let mut ranges = Vec::new();
 5521        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5522
 5523        for selection in &selections {
 5524            let range = if selection.id == newest_anchor.id {
 5525                replace_range_multibuffer.clone()
 5526            } else {
 5527                let mut range = selection.range();
 5528
 5529                // if prefix is present, don't duplicate it
 5530                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5531                    range.start = range.start.saturating_sub(lookbehind);
 5532
 5533                    // if suffix is also present, mimic the newest cursor and replace it
 5534                    if selection.id != newest_anchor.id
 5535                        && snapshot.contains_str_at(range.end, suffix)
 5536                    {
 5537                        range.end += lookahead;
 5538                    }
 5539                }
 5540                range
 5541            };
 5542
 5543            ranges.push(range.clone());
 5544
 5545            if !self.linked_edit_ranges.is_empty() {
 5546                let start_anchor = snapshot.anchor_before(range.start);
 5547                let end_anchor = snapshot.anchor_after(range.end);
 5548                if let Some(ranges) = self
 5549                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5550                {
 5551                    for (buffer, edits) in ranges {
 5552                        linked_edits
 5553                            .entry(buffer.clone())
 5554                            .or_default()
 5555                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5556                    }
 5557                }
 5558            }
 5559        }
 5560
 5561        let common_prefix_len = old_text
 5562            .chars()
 5563            .zip(new_text.chars())
 5564            .take_while(|(a, b)| a == b)
 5565            .map(|(a, _)| a.len_utf8())
 5566            .sum::<usize>();
 5567
 5568        cx.emit(EditorEvent::InputHandled {
 5569            utf16_range_to_replace: None,
 5570            text: new_text[common_prefix_len..].into(),
 5571        });
 5572
 5573        self.transact(window, cx, |this, window, cx| {
 5574            if let Some(mut snippet) = snippet {
 5575                snippet.text = new_text.to_string();
 5576                this.insert_snippet(&ranges, snippet, window, cx).log_err();
 5577            } else {
 5578                this.buffer.update(cx, |buffer, cx| {
 5579                    let auto_indent = match completion.insert_text_mode {
 5580                        Some(InsertTextMode::AS_IS) => None,
 5581                        _ => this.autoindent_mode.clone(),
 5582                    };
 5583                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5584                    buffer.edit(edits, auto_indent, cx);
 5585                });
 5586            }
 5587            for (buffer, edits) in linked_edits {
 5588                buffer.update(cx, |buffer, cx| {
 5589                    let snapshot = buffer.snapshot();
 5590                    let edits = edits
 5591                        .into_iter()
 5592                        .map(|(range, text)| {
 5593                            use text::ToPoint as TP;
 5594                            let end_point = TP::to_point(&range.end, &snapshot);
 5595                            let start_point = TP::to_point(&range.start, &snapshot);
 5596                            (start_point..end_point, text)
 5597                        })
 5598                        .sorted_by_key(|(range, _)| range.start);
 5599                    buffer.edit(edits, None, cx);
 5600                })
 5601            }
 5602
 5603            this.refresh_inline_completion(true, false, window, cx);
 5604        });
 5605
 5606        let show_new_completions_on_confirm = completion
 5607            .confirm
 5608            .as_ref()
 5609            .map_or(false, |confirm| confirm(intent, window, cx));
 5610        if show_new_completions_on_confirm {
 5611            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5612        }
 5613
 5614        let provider = self.completion_provider.as_ref()?;
 5615        drop(completion);
 5616        let apply_edits = provider.apply_additional_edits_for_completion(
 5617            buffer_handle,
 5618            completions_menu.completions.clone(),
 5619            candidate_id,
 5620            true,
 5621            cx,
 5622        );
 5623
 5624        let editor_settings = EditorSettings::get_global(cx);
 5625        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5626            // After the code completion is finished, users often want to know what signatures are needed.
 5627            // so we should automatically call signature_help
 5628            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5629        }
 5630
 5631        Some(cx.foreground_executor().spawn(async move {
 5632            apply_edits.await?;
 5633            Ok(())
 5634        }))
 5635    }
 5636
 5637    pub fn toggle_code_actions(
 5638        &mut self,
 5639        action: &ToggleCodeActions,
 5640        window: &mut Window,
 5641        cx: &mut Context<Self>,
 5642    ) {
 5643        let quick_launch = action.quick_launch;
 5644        let mut context_menu = self.context_menu.borrow_mut();
 5645        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5646            if code_actions.deployed_from == action.deployed_from {
 5647                // Toggle if we're selecting the same one
 5648                *context_menu = None;
 5649                cx.notify();
 5650                return;
 5651            } else {
 5652                // Otherwise, clear it and start a new one
 5653                *context_menu = None;
 5654                cx.notify();
 5655            }
 5656        }
 5657        drop(context_menu);
 5658        let snapshot = self.snapshot(window, cx);
 5659        let deployed_from = action.deployed_from.clone();
 5660        let mut task = self.code_actions_task.take();
 5661        let action = action.clone();
 5662        cx.spawn_in(window, async move |editor, cx| {
 5663            while let Some(prev_task) = task {
 5664                prev_task.await.log_err();
 5665                task = editor.update(cx, |this, _| this.code_actions_task.take())?;
 5666            }
 5667
 5668            let spawned_test_task = editor.update_in(cx, |editor, window, cx| {
 5669                if editor.focus_handle.is_focused(window) {
 5670                    let multibuffer_point = match &action.deployed_from {
 5671                        Some(CodeActionSource::Indicator(row)) => {
 5672                            DisplayPoint::new(*row, 0).to_point(&snapshot)
 5673                        }
 5674                        _ => editor.selections.newest::<Point>(cx).head(),
 5675                    };
 5676                    let (buffer, buffer_row) = snapshot
 5677                        .buffer_snapshot
 5678                        .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5679                        .and_then(|(buffer_snapshot, range)| {
 5680                            editor
 5681                                .buffer
 5682                                .read(cx)
 5683                                .buffer(buffer_snapshot.remote_id())
 5684                                .map(|buffer| (buffer, range.start.row))
 5685                        })?;
 5686                    let (_, code_actions) = editor
 5687                        .available_code_actions
 5688                        .clone()
 5689                        .and_then(|(location, code_actions)| {
 5690                            let snapshot = location.buffer.read(cx).snapshot();
 5691                            let point_range = location.range.to_point(&snapshot);
 5692                            let point_range = point_range.start.row..=point_range.end.row;
 5693                            if point_range.contains(&buffer_row) {
 5694                                Some((location, code_actions))
 5695                            } else {
 5696                                None
 5697                            }
 5698                        })
 5699                        .unzip();
 5700                    let buffer_id = buffer.read(cx).remote_id();
 5701                    let tasks = editor
 5702                        .tasks
 5703                        .get(&(buffer_id, buffer_row))
 5704                        .map(|t| Arc::new(t.to_owned()));
 5705                    if tasks.is_none() && code_actions.is_none() {
 5706                        return None;
 5707                    }
 5708
 5709                    editor.completion_tasks.clear();
 5710                    editor.discard_inline_completion(false, cx);
 5711                    let task_context =
 5712                        tasks
 5713                            .as_ref()
 5714                            .zip(editor.project.clone())
 5715                            .map(|(tasks, project)| {
 5716                                Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx)
 5717                            });
 5718
 5719                    Some(cx.spawn_in(window, async move |editor, cx| {
 5720                        let task_context = match task_context {
 5721                            Some(task_context) => task_context.await,
 5722                            None => None,
 5723                        };
 5724                        let resolved_tasks =
 5725                            tasks
 5726                                .zip(task_context.clone())
 5727                                .map(|(tasks, task_context)| ResolvedTasks {
 5728                                    templates: tasks.resolve(&task_context).collect(),
 5729                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 5730                                        multibuffer_point.row,
 5731                                        tasks.column,
 5732                                    )),
 5733                                });
 5734                        let debug_scenarios = editor.update(cx, |editor, cx| {
 5735                            if cx.has_flag::<DebuggerFeatureFlag>() {
 5736                                maybe!({
 5737                                    let project = editor.project.as_ref()?;
 5738                                    let dap_store = project.read(cx).dap_store();
 5739                                    let mut scenarios = vec![];
 5740                                    let resolved_tasks = resolved_tasks.as_ref()?;
 5741                                    let buffer = buffer.read(cx);
 5742                                    let language = buffer.language()?;
 5743                                    let file = buffer.file();
 5744                                    let debug_adapter =
 5745                                        language_settings(language.name().into(), file, cx)
 5746                                            .debuggers
 5747                                            .first()
 5748                                            .map(SharedString::from)
 5749                                            .or_else(|| {
 5750                                                language
 5751                                                    .config()
 5752                                                    .debuggers
 5753                                                    .first()
 5754                                                    .map(SharedString::from)
 5755                                            })?;
 5756
 5757                                    dap_store.update(cx, |dap_store, cx| {
 5758                                        for (_, task) in &resolved_tasks.templates {
 5759                                            if let Some(scenario) = dap_store
 5760                                                .debug_scenario_for_build_task(
 5761                                                    task.original_task().clone(),
 5762                                                    debug_adapter.clone().into(),
 5763                                                    task.display_label().to_owned().into(),
 5764                                                    cx,
 5765                                                )
 5766                                            {
 5767                                                scenarios.push(scenario);
 5768                                            }
 5769                                        }
 5770                                    });
 5771                                    Some(scenarios)
 5772                                })
 5773                                .unwrap_or_default()
 5774                            } else {
 5775                                vec![]
 5776                            }
 5777                        })?;
 5778                        let spawn_straight_away = quick_launch
 5779                            && resolved_tasks
 5780                                .as_ref()
 5781                                .map_or(false, |tasks| tasks.templates.len() == 1)
 5782                            && code_actions
 5783                                .as_ref()
 5784                                .map_or(true, |actions| actions.is_empty())
 5785                            && debug_scenarios.is_empty();
 5786                        if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
 5787                            crate::hover_popover::hide_hover(editor, cx);
 5788                            *editor.context_menu.borrow_mut() =
 5789                                Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 5790                                    buffer,
 5791                                    actions: CodeActionContents::new(
 5792                                        resolved_tasks,
 5793                                        code_actions,
 5794                                        debug_scenarios,
 5795                                        task_context.unwrap_or_default(),
 5796                                    ),
 5797                                    selected_item: Default::default(),
 5798                                    scroll_handle: UniformListScrollHandle::default(),
 5799                                    deployed_from,
 5800                                }));
 5801                            if spawn_straight_away {
 5802                                if let Some(task) = editor.confirm_code_action(
 5803                                    &ConfirmCodeAction { item_ix: Some(0) },
 5804                                    window,
 5805                                    cx,
 5806                                ) {
 5807                                    cx.notify();
 5808                                    return task;
 5809                                }
 5810                            }
 5811                            cx.notify();
 5812                            Task::ready(Ok(()))
 5813                        }) {
 5814                            task.await
 5815                        } else {
 5816                            Ok(())
 5817                        }
 5818                    }))
 5819                } else {
 5820                    Some(Task::ready(Ok(())))
 5821                }
 5822            })?;
 5823            if let Some(task) = spawned_test_task {
 5824                task.await?;
 5825            }
 5826
 5827            anyhow::Ok(())
 5828        })
 5829        .detach_and_log_err(cx);
 5830    }
 5831
 5832    pub fn confirm_code_action(
 5833        &mut self,
 5834        action: &ConfirmCodeAction,
 5835        window: &mut Window,
 5836        cx: &mut Context<Self>,
 5837    ) -> Option<Task<Result<()>>> {
 5838        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 5839
 5840        let actions_menu =
 5841            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 5842                menu
 5843            } else {
 5844                return None;
 5845            };
 5846
 5847        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 5848        let action = actions_menu.actions.get(action_ix)?;
 5849        let title = action.label();
 5850        let buffer = actions_menu.buffer;
 5851        let workspace = self.workspace()?;
 5852
 5853        match action {
 5854            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 5855                workspace.update(cx, |workspace, cx| {
 5856                    workspace.schedule_resolved_task(
 5857                        task_source_kind,
 5858                        resolved_task,
 5859                        false,
 5860                        window,
 5861                        cx,
 5862                    );
 5863
 5864                    Some(Task::ready(Ok(())))
 5865                })
 5866            }
 5867            CodeActionsItem::CodeAction {
 5868                excerpt_id,
 5869                action,
 5870                provider,
 5871            } => {
 5872                let apply_code_action =
 5873                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 5874                let workspace = workspace.downgrade();
 5875                Some(cx.spawn_in(window, async move |editor, cx| {
 5876                    let project_transaction = apply_code_action.await?;
 5877                    Self::open_project_transaction(
 5878                        &editor,
 5879                        workspace,
 5880                        project_transaction,
 5881                        title,
 5882                        cx,
 5883                    )
 5884                    .await
 5885                }))
 5886            }
 5887            CodeActionsItem::DebugScenario(scenario) => {
 5888                let context = actions_menu.actions.context.clone();
 5889
 5890                workspace.update(cx, |workspace, cx| {
 5891                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 5892                    workspace.start_debug_session(scenario, context, Some(buffer), window, cx);
 5893                });
 5894                Some(Task::ready(Ok(())))
 5895            }
 5896        }
 5897    }
 5898
 5899    pub async fn open_project_transaction(
 5900        this: &WeakEntity<Editor>,
 5901        workspace: WeakEntity<Workspace>,
 5902        transaction: ProjectTransaction,
 5903        title: String,
 5904        cx: &mut AsyncWindowContext,
 5905    ) -> Result<()> {
 5906        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 5907        cx.update(|_, cx| {
 5908            entries.sort_unstable_by_key(|(buffer, _)| {
 5909                buffer.read(cx).file().map(|f| f.path().clone())
 5910            });
 5911        })?;
 5912
 5913        // If the project transaction's edits are all contained within this editor, then
 5914        // avoid opening a new editor to display them.
 5915
 5916        if let Some((buffer, transaction)) = entries.first() {
 5917            if entries.len() == 1 {
 5918                let excerpt = this.update(cx, |editor, cx| {
 5919                    editor
 5920                        .buffer()
 5921                        .read(cx)
 5922                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 5923                })?;
 5924                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 5925                    if excerpted_buffer == *buffer {
 5926                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 5927                            let excerpt_range = excerpt_range.to_offset(buffer);
 5928                            buffer
 5929                                .edited_ranges_for_transaction::<usize>(transaction)
 5930                                .all(|range| {
 5931                                    excerpt_range.start <= range.start
 5932                                        && excerpt_range.end >= range.end
 5933                                })
 5934                        })?;
 5935
 5936                        if all_edits_within_excerpt {
 5937                            return Ok(());
 5938                        }
 5939                    }
 5940                }
 5941            }
 5942        } else {
 5943            return Ok(());
 5944        }
 5945
 5946        let mut ranges_to_highlight = Vec::new();
 5947        let excerpt_buffer = cx.new(|cx| {
 5948            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 5949            for (buffer_handle, transaction) in &entries {
 5950                let edited_ranges = buffer_handle
 5951                    .read(cx)
 5952                    .edited_ranges_for_transaction::<Point>(transaction)
 5953                    .collect::<Vec<_>>();
 5954                let (ranges, _) = multibuffer.set_excerpts_for_path(
 5955                    PathKey::for_buffer(buffer_handle, cx),
 5956                    buffer_handle.clone(),
 5957                    edited_ranges,
 5958                    DEFAULT_MULTIBUFFER_CONTEXT,
 5959                    cx,
 5960                );
 5961
 5962                ranges_to_highlight.extend(ranges);
 5963            }
 5964            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 5965            multibuffer
 5966        })?;
 5967
 5968        workspace.update_in(cx, |workspace, window, cx| {
 5969            let project = workspace.project().clone();
 5970            let editor =
 5971                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 5972            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 5973            editor.update(cx, |editor, cx| {
 5974                editor.highlight_background::<Self>(
 5975                    &ranges_to_highlight,
 5976                    |theme| theme.editor_highlighted_line_background,
 5977                    cx,
 5978                );
 5979            });
 5980        })?;
 5981
 5982        Ok(())
 5983    }
 5984
 5985    pub fn clear_code_action_providers(&mut self) {
 5986        self.code_action_providers.clear();
 5987        self.available_code_actions.take();
 5988    }
 5989
 5990    pub fn add_code_action_provider(
 5991        &mut self,
 5992        provider: Rc<dyn CodeActionProvider>,
 5993        window: &mut Window,
 5994        cx: &mut Context<Self>,
 5995    ) {
 5996        if self
 5997            .code_action_providers
 5998            .iter()
 5999            .any(|existing_provider| existing_provider.id() == provider.id())
 6000        {
 6001            return;
 6002        }
 6003
 6004        self.code_action_providers.push(provider);
 6005        self.refresh_code_actions(window, cx);
 6006    }
 6007
 6008    pub fn remove_code_action_provider(
 6009        &mut self,
 6010        id: Arc<str>,
 6011        window: &mut Window,
 6012        cx: &mut Context<Self>,
 6013    ) {
 6014        self.code_action_providers
 6015            .retain(|provider| provider.id() != id);
 6016        self.refresh_code_actions(window, cx);
 6017    }
 6018
 6019    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6020        !self.code_action_providers.is_empty()
 6021            && EditorSettings::get_global(cx).toolbar.code_actions
 6022    }
 6023
 6024    pub fn has_available_code_actions(&self) -> bool {
 6025        self.available_code_actions
 6026            .as_ref()
 6027            .is_some_and(|(_, actions)| !actions.is_empty())
 6028    }
 6029
 6030    fn render_inline_code_actions(
 6031        &self,
 6032        icon_size: ui::IconSize,
 6033        display_row: DisplayRow,
 6034        is_active: bool,
 6035        cx: &mut Context<Self>,
 6036    ) -> AnyElement {
 6037        let show_tooltip = !self.context_menu_visible();
 6038        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6039            .icon_size(icon_size)
 6040            .shape(ui::IconButtonShape::Square)
 6041            .style(ButtonStyle::Transparent)
 6042            .icon_color(ui::Color::Hidden)
 6043            .toggle_state(is_active)
 6044            .when(show_tooltip, |this| {
 6045                this.tooltip({
 6046                    let focus_handle = self.focus_handle.clone();
 6047                    move |window, cx| {
 6048                        Tooltip::for_action_in(
 6049                            "Toggle Code Actions",
 6050                            &ToggleCodeActions {
 6051                                deployed_from: None,
 6052                                quick_launch: false,
 6053                            },
 6054                            &focus_handle,
 6055                            window,
 6056                            cx,
 6057                        )
 6058                    }
 6059                })
 6060            })
 6061            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6062                window.focus(&editor.focus_handle(cx));
 6063                editor.toggle_code_actions(
 6064                    &crate::actions::ToggleCodeActions {
 6065                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6066                            display_row,
 6067                        )),
 6068                        quick_launch: false,
 6069                    },
 6070                    window,
 6071                    cx,
 6072                );
 6073            }))
 6074            .into_any_element()
 6075    }
 6076
 6077    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6078        &self.context_menu
 6079    }
 6080
 6081    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6082        let newest_selection = self.selections.newest_anchor().clone();
 6083        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6084        let buffer = self.buffer.read(cx);
 6085        if newest_selection.head().diff_base_anchor.is_some() {
 6086            return None;
 6087        }
 6088        let (start_buffer, start) =
 6089            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6090        let (end_buffer, end) =
 6091            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6092        if start_buffer != end_buffer {
 6093            return None;
 6094        }
 6095
 6096        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6097            cx.background_executor()
 6098                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6099                .await;
 6100
 6101            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6102                let providers = this.code_action_providers.clone();
 6103                let tasks = this
 6104                    .code_action_providers
 6105                    .iter()
 6106                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6107                    .collect::<Vec<_>>();
 6108                (providers, tasks)
 6109            })?;
 6110
 6111            let mut actions = Vec::new();
 6112            for (provider, provider_actions) in
 6113                providers.into_iter().zip(future::join_all(tasks).await)
 6114            {
 6115                if let Some(provider_actions) = provider_actions.log_err() {
 6116                    actions.extend(provider_actions.into_iter().map(|action| {
 6117                        AvailableCodeAction {
 6118                            excerpt_id: newest_selection.start.excerpt_id,
 6119                            action,
 6120                            provider: provider.clone(),
 6121                        }
 6122                    }));
 6123                }
 6124            }
 6125
 6126            this.update(cx, |this, cx| {
 6127                this.available_code_actions = if actions.is_empty() {
 6128                    None
 6129                } else {
 6130                    Some((
 6131                        Location {
 6132                            buffer: start_buffer,
 6133                            range: start..end,
 6134                        },
 6135                        actions.into(),
 6136                    ))
 6137                };
 6138                cx.notify();
 6139            })
 6140        }));
 6141        None
 6142    }
 6143
 6144    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6145        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6146            self.show_git_blame_inline = false;
 6147
 6148            self.show_git_blame_inline_delay_task =
 6149                Some(cx.spawn_in(window, async move |this, cx| {
 6150                    cx.background_executor().timer(delay).await;
 6151
 6152                    this.update(cx, |this, cx| {
 6153                        this.show_git_blame_inline = true;
 6154                        cx.notify();
 6155                    })
 6156                    .log_err();
 6157                }));
 6158        }
 6159    }
 6160
 6161    fn show_blame_popover(
 6162        &mut self,
 6163        blame_entry: &BlameEntry,
 6164        position: gpui::Point<Pixels>,
 6165        cx: &mut Context<Self>,
 6166    ) {
 6167        if let Some(state) = &mut self.inline_blame_popover {
 6168            state.hide_task.take();
 6169            cx.notify();
 6170        } else {
 6171            let delay = EditorSettings::get_global(cx).hover_popover_delay;
 6172            let show_task = cx.spawn(async move |editor, cx| {
 6173                cx.background_executor()
 6174                    .timer(std::time::Duration::from_millis(delay))
 6175                    .await;
 6176                editor
 6177                    .update(cx, |editor, cx| {
 6178                        if let Some(state) = &mut editor.inline_blame_popover {
 6179                            state.show_task = None;
 6180                            cx.notify();
 6181                        }
 6182                    })
 6183                    .ok();
 6184            });
 6185            let Some(blame) = self.blame.as_ref() else {
 6186                return;
 6187            };
 6188            let blame = blame.read(cx);
 6189            let details = blame.details_for_entry(&blame_entry);
 6190            let markdown = cx.new(|cx| {
 6191                Markdown::new(
 6192                    details
 6193                        .as_ref()
 6194                        .map(|message| message.message.clone())
 6195                        .unwrap_or_default(),
 6196                    None,
 6197                    None,
 6198                    cx,
 6199                )
 6200            });
 6201            self.inline_blame_popover = Some(InlineBlamePopover {
 6202                position,
 6203                show_task: Some(show_task),
 6204                hide_task: None,
 6205                popover_bounds: None,
 6206                popover_state: InlineBlamePopoverState {
 6207                    scroll_handle: ScrollHandle::new(),
 6208                    commit_message: details,
 6209                    markdown,
 6210                },
 6211            });
 6212        }
 6213    }
 6214
 6215    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6216        if let Some(state) = &mut self.inline_blame_popover {
 6217            if state.show_task.is_some() {
 6218                self.inline_blame_popover.take();
 6219                cx.notify();
 6220            } else {
 6221                let hide_task = cx.spawn(async move |editor, cx| {
 6222                    cx.background_executor()
 6223                        .timer(std::time::Duration::from_millis(100))
 6224                        .await;
 6225                    editor
 6226                        .update(cx, |editor, cx| {
 6227                            editor.inline_blame_popover.take();
 6228                            cx.notify();
 6229                        })
 6230                        .ok();
 6231                });
 6232                state.hide_task = Some(hide_task);
 6233            }
 6234        }
 6235    }
 6236
 6237    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6238        if self.pending_rename.is_some() {
 6239            return None;
 6240        }
 6241
 6242        let provider = self.semantics_provider.clone()?;
 6243        let buffer = self.buffer.read(cx);
 6244        let newest_selection = self.selections.newest_anchor().clone();
 6245        let cursor_position = newest_selection.head();
 6246        let (cursor_buffer, cursor_buffer_position) =
 6247            buffer.text_anchor_for_position(cursor_position, cx)?;
 6248        let (tail_buffer, tail_buffer_position) =
 6249            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6250        if cursor_buffer != tail_buffer {
 6251            return None;
 6252        }
 6253
 6254        let snapshot = cursor_buffer.read(cx).snapshot();
 6255        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position);
 6256        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position);
 6257        if start_word_range != end_word_range {
 6258            self.document_highlights_task.take();
 6259            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6260            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6261            return None;
 6262        }
 6263
 6264        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6265        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6266            cx.background_executor()
 6267                .timer(Duration::from_millis(debounce))
 6268                .await;
 6269
 6270            let highlights = if let Some(highlights) = cx
 6271                .update(|cx| {
 6272                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6273                })
 6274                .ok()
 6275                .flatten()
 6276            {
 6277                highlights.await.log_err()
 6278            } else {
 6279                None
 6280            };
 6281
 6282            if let Some(highlights) = highlights {
 6283                this.update(cx, |this, cx| {
 6284                    if this.pending_rename.is_some() {
 6285                        return;
 6286                    }
 6287
 6288                    let buffer_id = cursor_position.buffer_id;
 6289                    let buffer = this.buffer.read(cx);
 6290                    if !buffer
 6291                        .text_anchor_for_position(cursor_position, cx)
 6292                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6293                    {
 6294                        return;
 6295                    }
 6296
 6297                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6298                    let mut write_ranges = Vec::new();
 6299                    let mut read_ranges = Vec::new();
 6300                    for highlight in highlights {
 6301                        for (excerpt_id, excerpt_range) in
 6302                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6303                        {
 6304                            let start = highlight
 6305                                .range
 6306                                .start
 6307                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6308                            let end = highlight
 6309                                .range
 6310                                .end
 6311                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6312                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6313                                continue;
 6314                            }
 6315
 6316                            let range = Anchor {
 6317                                buffer_id,
 6318                                excerpt_id,
 6319                                text_anchor: start,
 6320                                diff_base_anchor: None,
 6321                            }..Anchor {
 6322                                buffer_id,
 6323                                excerpt_id,
 6324                                text_anchor: end,
 6325                                diff_base_anchor: None,
 6326                            };
 6327                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6328                                write_ranges.push(range);
 6329                            } else {
 6330                                read_ranges.push(range);
 6331                            }
 6332                        }
 6333                    }
 6334
 6335                    this.highlight_background::<DocumentHighlightRead>(
 6336                        &read_ranges,
 6337                        |theme| theme.editor_document_highlight_read_background,
 6338                        cx,
 6339                    );
 6340                    this.highlight_background::<DocumentHighlightWrite>(
 6341                        &write_ranges,
 6342                        |theme| theme.editor_document_highlight_write_background,
 6343                        cx,
 6344                    );
 6345                    cx.notify();
 6346                })
 6347                .log_err();
 6348            }
 6349        }));
 6350        None
 6351    }
 6352
 6353    fn prepare_highlight_query_from_selection(
 6354        &mut self,
 6355        cx: &mut Context<Editor>,
 6356    ) -> Option<(String, Range<Anchor>)> {
 6357        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6358            return None;
 6359        }
 6360        if !EditorSettings::get_global(cx).selection_highlight {
 6361            return None;
 6362        }
 6363        if self.selections.count() != 1 || self.selections.line_mode {
 6364            return None;
 6365        }
 6366        let selection = self.selections.newest::<Point>(cx);
 6367        if selection.is_empty() || selection.start.row != selection.end.row {
 6368            return None;
 6369        }
 6370        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6371        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6372        let query = multi_buffer_snapshot
 6373            .text_for_range(selection_anchor_range.clone())
 6374            .collect::<String>();
 6375        if query.trim().is_empty() {
 6376            return None;
 6377        }
 6378        Some((query, selection_anchor_range))
 6379    }
 6380
 6381    fn update_selection_occurrence_highlights(
 6382        &mut self,
 6383        query_text: String,
 6384        query_range: Range<Anchor>,
 6385        multi_buffer_range_to_query: Range<Point>,
 6386        use_debounce: bool,
 6387        window: &mut Window,
 6388        cx: &mut Context<Editor>,
 6389    ) -> Task<()> {
 6390        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6391        cx.spawn_in(window, async move |editor, cx| {
 6392            if use_debounce {
 6393                cx.background_executor()
 6394                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6395                    .await;
 6396            }
 6397            let match_task = cx.background_spawn(async move {
 6398                let buffer_ranges = multi_buffer_snapshot
 6399                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6400                    .into_iter()
 6401                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6402                let mut match_ranges = Vec::new();
 6403                let Ok(regex) = project::search::SearchQuery::text(
 6404                    query_text.clone(),
 6405                    false,
 6406                    false,
 6407                    false,
 6408                    Default::default(),
 6409                    Default::default(),
 6410                    false,
 6411                    None,
 6412                ) else {
 6413                    return Vec::default();
 6414                };
 6415                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6416                    match_ranges.extend(
 6417                        regex
 6418                            .search(&buffer_snapshot, Some(search_range.clone()))
 6419                            .await
 6420                            .into_iter()
 6421                            .filter_map(|match_range| {
 6422                                let match_start = buffer_snapshot
 6423                                    .anchor_after(search_range.start + match_range.start);
 6424                                let match_end = buffer_snapshot
 6425                                    .anchor_before(search_range.start + match_range.end);
 6426                                let match_anchor_range = Anchor::range_in_buffer(
 6427                                    excerpt_id,
 6428                                    buffer_snapshot.remote_id(),
 6429                                    match_start..match_end,
 6430                                );
 6431                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6432                            }),
 6433                    );
 6434                }
 6435                match_ranges
 6436            });
 6437            let match_ranges = match_task.await;
 6438            editor
 6439                .update_in(cx, |editor, _, cx| {
 6440                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6441                    if !match_ranges.is_empty() {
 6442                        editor.highlight_background::<SelectedTextHighlight>(
 6443                            &match_ranges,
 6444                            |theme| theme.editor_document_highlight_bracket_background,
 6445                            cx,
 6446                        )
 6447                    }
 6448                })
 6449                .log_err();
 6450        })
 6451    }
 6452
 6453    fn refresh_selected_text_highlights(
 6454        &mut self,
 6455        on_buffer_edit: bool,
 6456        window: &mut Window,
 6457        cx: &mut Context<Editor>,
 6458    ) {
 6459        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6460        else {
 6461            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6462            self.quick_selection_highlight_task.take();
 6463            self.debounced_selection_highlight_task.take();
 6464            return;
 6465        };
 6466        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6467        if on_buffer_edit
 6468            || self
 6469                .quick_selection_highlight_task
 6470                .as_ref()
 6471                .map_or(true, |(prev_anchor_range, _)| {
 6472                    prev_anchor_range != &query_range
 6473                })
 6474        {
 6475            let multi_buffer_visible_start = self
 6476                .scroll_manager
 6477                .anchor()
 6478                .anchor
 6479                .to_point(&multi_buffer_snapshot);
 6480            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6481                multi_buffer_visible_start
 6482                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6483                Bias::Left,
 6484            );
 6485            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6486            self.quick_selection_highlight_task = Some((
 6487                query_range.clone(),
 6488                self.update_selection_occurrence_highlights(
 6489                    query_text.clone(),
 6490                    query_range.clone(),
 6491                    multi_buffer_visible_range,
 6492                    false,
 6493                    window,
 6494                    cx,
 6495                ),
 6496            ));
 6497        }
 6498        if on_buffer_edit
 6499            || self
 6500                .debounced_selection_highlight_task
 6501                .as_ref()
 6502                .map_or(true, |(prev_anchor_range, _)| {
 6503                    prev_anchor_range != &query_range
 6504                })
 6505        {
 6506            let multi_buffer_start = multi_buffer_snapshot
 6507                .anchor_before(0)
 6508                .to_point(&multi_buffer_snapshot);
 6509            let multi_buffer_end = multi_buffer_snapshot
 6510                .anchor_after(multi_buffer_snapshot.len())
 6511                .to_point(&multi_buffer_snapshot);
 6512            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6513            self.debounced_selection_highlight_task = Some((
 6514                query_range.clone(),
 6515                self.update_selection_occurrence_highlights(
 6516                    query_text,
 6517                    query_range,
 6518                    multi_buffer_full_range,
 6519                    true,
 6520                    window,
 6521                    cx,
 6522                ),
 6523            ));
 6524        }
 6525    }
 6526
 6527    pub fn refresh_inline_completion(
 6528        &mut self,
 6529        debounce: bool,
 6530        user_requested: bool,
 6531        window: &mut Window,
 6532        cx: &mut Context<Self>,
 6533    ) -> Option<()> {
 6534        let provider = self.edit_prediction_provider()?;
 6535        let cursor = self.selections.newest_anchor().head();
 6536        let (buffer, cursor_buffer_position) =
 6537            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6538
 6539        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 6540            self.discard_inline_completion(false, cx);
 6541            return None;
 6542        }
 6543
 6544        if !user_requested
 6545            && (!self.should_show_edit_predictions()
 6546                || !self.is_focused(window)
 6547                || buffer.read(cx).is_empty())
 6548        {
 6549            self.discard_inline_completion(false, cx);
 6550            return None;
 6551        }
 6552
 6553        self.update_visible_inline_completion(window, cx);
 6554        provider.refresh(
 6555            self.project.clone(),
 6556            buffer,
 6557            cursor_buffer_position,
 6558            debounce,
 6559            cx,
 6560        );
 6561        Some(())
 6562    }
 6563
 6564    fn show_edit_predictions_in_menu(&self) -> bool {
 6565        match self.edit_prediction_settings {
 6566            EditPredictionSettings::Disabled => false,
 6567            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 6568        }
 6569    }
 6570
 6571    pub fn edit_predictions_enabled(&self) -> bool {
 6572        match self.edit_prediction_settings {
 6573            EditPredictionSettings::Disabled => false,
 6574            EditPredictionSettings::Enabled { .. } => true,
 6575        }
 6576    }
 6577
 6578    fn edit_prediction_requires_modifier(&self) -> bool {
 6579        match self.edit_prediction_settings {
 6580            EditPredictionSettings::Disabled => false,
 6581            EditPredictionSettings::Enabled {
 6582                preview_requires_modifier,
 6583                ..
 6584            } => preview_requires_modifier,
 6585        }
 6586    }
 6587
 6588    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 6589        if self.edit_prediction_provider.is_none() {
 6590            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 6591        } else {
 6592            let selection = self.selections.newest_anchor();
 6593            let cursor = selection.head();
 6594
 6595            if let Some((buffer, cursor_buffer_position)) =
 6596                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6597            {
 6598                self.edit_prediction_settings =
 6599                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 6600            }
 6601        }
 6602    }
 6603
 6604    fn edit_prediction_settings_at_position(
 6605        &self,
 6606        buffer: &Entity<Buffer>,
 6607        buffer_position: language::Anchor,
 6608        cx: &App,
 6609    ) -> EditPredictionSettings {
 6610        if !self.mode.is_full()
 6611            || !self.show_inline_completions_override.unwrap_or(true)
 6612            || self.inline_completions_disabled_in_scope(buffer, buffer_position, cx)
 6613        {
 6614            return EditPredictionSettings::Disabled;
 6615        }
 6616
 6617        let buffer = buffer.read(cx);
 6618
 6619        let file = buffer.file();
 6620
 6621        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 6622            return EditPredictionSettings::Disabled;
 6623        };
 6624
 6625        let by_provider = matches!(
 6626            self.menu_inline_completions_policy,
 6627            MenuInlineCompletionsPolicy::ByProvider
 6628        );
 6629
 6630        let show_in_menu = by_provider
 6631            && self
 6632                .edit_prediction_provider
 6633                .as_ref()
 6634                .map_or(false, |provider| {
 6635                    provider.provider.show_completions_in_menu()
 6636                });
 6637
 6638        let preview_requires_modifier =
 6639            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 6640
 6641        EditPredictionSettings::Enabled {
 6642            show_in_menu,
 6643            preview_requires_modifier,
 6644        }
 6645    }
 6646
 6647    fn should_show_edit_predictions(&self) -> bool {
 6648        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 6649    }
 6650
 6651    pub fn edit_prediction_preview_is_active(&self) -> bool {
 6652        matches!(
 6653            self.edit_prediction_preview,
 6654            EditPredictionPreview::Active { .. }
 6655        )
 6656    }
 6657
 6658    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 6659        let cursor = self.selections.newest_anchor().head();
 6660        if let Some((buffer, cursor_position)) =
 6661            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 6662        {
 6663            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 6664        } else {
 6665            false
 6666        }
 6667    }
 6668
 6669    pub fn supports_minimap(&self, cx: &App) -> bool {
 6670        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 6671    }
 6672
 6673    fn edit_predictions_enabled_in_buffer(
 6674        &self,
 6675        buffer: &Entity<Buffer>,
 6676        buffer_position: language::Anchor,
 6677        cx: &App,
 6678    ) -> bool {
 6679        maybe!({
 6680            if self.read_only(cx) {
 6681                return Some(false);
 6682            }
 6683            let provider = self.edit_prediction_provider()?;
 6684            if !provider.is_enabled(&buffer, buffer_position, cx) {
 6685                return Some(false);
 6686            }
 6687            let buffer = buffer.read(cx);
 6688            let Some(file) = buffer.file() else {
 6689                return Some(true);
 6690            };
 6691            let settings = all_language_settings(Some(file), cx);
 6692            Some(settings.edit_predictions_enabled_for_file(file, cx))
 6693        })
 6694        .unwrap_or(false)
 6695    }
 6696
 6697    fn cycle_inline_completion(
 6698        &mut self,
 6699        direction: Direction,
 6700        window: &mut Window,
 6701        cx: &mut Context<Self>,
 6702    ) -> Option<()> {
 6703        let provider = self.edit_prediction_provider()?;
 6704        let cursor = self.selections.newest_anchor().head();
 6705        let (buffer, cursor_buffer_position) =
 6706            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 6707        if self.inline_completions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 6708            return None;
 6709        }
 6710
 6711        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 6712        self.update_visible_inline_completion(window, cx);
 6713
 6714        Some(())
 6715    }
 6716
 6717    pub fn show_inline_completion(
 6718        &mut self,
 6719        _: &ShowEditPrediction,
 6720        window: &mut Window,
 6721        cx: &mut Context<Self>,
 6722    ) {
 6723        if !self.has_active_inline_completion() {
 6724            self.refresh_inline_completion(false, true, window, cx);
 6725            return;
 6726        }
 6727
 6728        self.update_visible_inline_completion(window, cx);
 6729    }
 6730
 6731    pub fn display_cursor_names(
 6732        &mut self,
 6733        _: &DisplayCursorNames,
 6734        window: &mut Window,
 6735        cx: &mut Context<Self>,
 6736    ) {
 6737        self.show_cursor_names(window, cx);
 6738    }
 6739
 6740    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6741        self.show_cursor_names = true;
 6742        cx.notify();
 6743        cx.spawn_in(window, async move |this, cx| {
 6744            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 6745            this.update(cx, |this, cx| {
 6746                this.show_cursor_names = false;
 6747                cx.notify()
 6748            })
 6749            .ok()
 6750        })
 6751        .detach();
 6752    }
 6753
 6754    pub fn next_edit_prediction(
 6755        &mut self,
 6756        _: &NextEditPrediction,
 6757        window: &mut Window,
 6758        cx: &mut Context<Self>,
 6759    ) {
 6760        if self.has_active_inline_completion() {
 6761            self.cycle_inline_completion(Direction::Next, window, cx);
 6762        } else {
 6763            let is_copilot_disabled = self
 6764                .refresh_inline_completion(false, true, window, cx)
 6765                .is_none();
 6766            if is_copilot_disabled {
 6767                cx.propagate();
 6768            }
 6769        }
 6770    }
 6771
 6772    pub fn previous_edit_prediction(
 6773        &mut self,
 6774        _: &PreviousEditPrediction,
 6775        window: &mut Window,
 6776        cx: &mut Context<Self>,
 6777    ) {
 6778        if self.has_active_inline_completion() {
 6779            self.cycle_inline_completion(Direction::Prev, window, cx);
 6780        } else {
 6781            let is_copilot_disabled = self
 6782                .refresh_inline_completion(false, true, window, cx)
 6783                .is_none();
 6784            if is_copilot_disabled {
 6785                cx.propagate();
 6786            }
 6787        }
 6788    }
 6789
 6790    pub fn accept_edit_prediction(
 6791        &mut self,
 6792        _: &AcceptEditPrediction,
 6793        window: &mut Window,
 6794        cx: &mut Context<Self>,
 6795    ) {
 6796        if self.show_edit_predictions_in_menu() {
 6797            self.hide_context_menu(window, cx);
 6798        }
 6799
 6800        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6801            return;
 6802        };
 6803
 6804        self.report_inline_completion_event(
 6805            active_inline_completion.completion_id.clone(),
 6806            true,
 6807            cx,
 6808        );
 6809
 6810        match &active_inline_completion.completion {
 6811            InlineCompletion::Move { target, .. } => {
 6812                let target = *target;
 6813
 6814                if let Some(position_map) = &self.last_position_map {
 6815                    if position_map
 6816                        .visible_row_range
 6817                        .contains(&target.to_display_point(&position_map.snapshot).row())
 6818                        || !self.edit_prediction_requires_modifier()
 6819                    {
 6820                        self.unfold_ranges(&[target..target], true, false, cx);
 6821                        // Note that this is also done in vim's handler of the Tab action.
 6822                        self.change_selections(
 6823                            Some(Autoscroll::newest()),
 6824                            window,
 6825                            cx,
 6826                            |selections| {
 6827                                selections.select_anchor_ranges([target..target]);
 6828                            },
 6829                        );
 6830                        self.clear_row_highlights::<EditPredictionPreview>();
 6831
 6832                        self.edit_prediction_preview
 6833                            .set_previous_scroll_position(None);
 6834                    } else {
 6835                        self.edit_prediction_preview
 6836                            .set_previous_scroll_position(Some(
 6837                                position_map.snapshot.scroll_anchor,
 6838                            ));
 6839
 6840                        self.highlight_rows::<EditPredictionPreview>(
 6841                            target..target,
 6842                            cx.theme().colors().editor_highlighted_line_background,
 6843                            RowHighlightOptions {
 6844                                autoscroll: true,
 6845                                ..Default::default()
 6846                            },
 6847                            cx,
 6848                        );
 6849                        self.request_autoscroll(Autoscroll::fit(), cx);
 6850                    }
 6851                }
 6852            }
 6853            InlineCompletion::Edit { edits, .. } => {
 6854                if let Some(provider) = self.edit_prediction_provider() {
 6855                    provider.accept(cx);
 6856                }
 6857
 6858                // Store the transaction ID and selections before applying the edit
 6859                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 6860
 6861                let snapshot = self.buffer.read(cx).snapshot(cx);
 6862                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 6863
 6864                self.buffer.update(cx, |buffer, cx| {
 6865                    buffer.edit(edits.iter().cloned(), None, cx)
 6866                });
 6867
 6868                self.change_selections(None, window, cx, |s| {
 6869                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 6870                });
 6871
 6872                let selections = self.selections.disjoint_anchors();
 6873                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 6874                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 6875                    if has_new_transaction {
 6876                        self.selection_history
 6877                            .insert_transaction(transaction_id_now, selections);
 6878                    }
 6879                }
 6880
 6881                self.update_visible_inline_completion(window, cx);
 6882                if self.active_inline_completion.is_none() {
 6883                    self.refresh_inline_completion(true, true, window, cx);
 6884                }
 6885
 6886                cx.notify();
 6887            }
 6888        }
 6889
 6890        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 6891    }
 6892
 6893    pub fn accept_partial_inline_completion(
 6894        &mut self,
 6895        _: &AcceptPartialEditPrediction,
 6896        window: &mut Window,
 6897        cx: &mut Context<Self>,
 6898    ) {
 6899        let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
 6900            return;
 6901        };
 6902        if self.selections.count() != 1 {
 6903            return;
 6904        }
 6905
 6906        self.report_inline_completion_event(
 6907            active_inline_completion.completion_id.clone(),
 6908            true,
 6909            cx,
 6910        );
 6911
 6912        match &active_inline_completion.completion {
 6913            InlineCompletion::Move { target, .. } => {
 6914                let target = *target;
 6915                self.change_selections(Some(Autoscroll::newest()), window, cx, |selections| {
 6916                    selections.select_anchor_ranges([target..target]);
 6917                });
 6918            }
 6919            InlineCompletion::Edit { edits, .. } => {
 6920                // Find an insertion that starts at the cursor position.
 6921                let snapshot = self.buffer.read(cx).snapshot(cx);
 6922                let cursor_offset = self.selections.newest::<usize>(cx).head();
 6923                let insertion = edits.iter().find_map(|(range, text)| {
 6924                    let range = range.to_offset(&snapshot);
 6925                    if range.is_empty() && range.start == cursor_offset {
 6926                        Some(text)
 6927                    } else {
 6928                        None
 6929                    }
 6930                });
 6931
 6932                if let Some(text) = insertion {
 6933                    let mut partial_completion = text
 6934                        .chars()
 6935                        .by_ref()
 6936                        .take_while(|c| c.is_alphabetic())
 6937                        .collect::<String>();
 6938                    if partial_completion.is_empty() {
 6939                        partial_completion = text
 6940                            .chars()
 6941                            .by_ref()
 6942                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 6943                            .collect::<String>();
 6944                    }
 6945
 6946                    cx.emit(EditorEvent::InputHandled {
 6947                        utf16_range_to_replace: None,
 6948                        text: partial_completion.clone().into(),
 6949                    });
 6950
 6951                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 6952
 6953                    self.refresh_inline_completion(true, true, window, cx);
 6954                    cx.notify();
 6955                } else {
 6956                    self.accept_edit_prediction(&Default::default(), window, cx);
 6957                }
 6958            }
 6959        }
 6960    }
 6961
 6962    fn discard_inline_completion(
 6963        &mut self,
 6964        should_report_inline_completion_event: bool,
 6965        cx: &mut Context<Self>,
 6966    ) -> bool {
 6967        if should_report_inline_completion_event {
 6968            let completion_id = self
 6969                .active_inline_completion
 6970                .as_ref()
 6971                .and_then(|active_completion| active_completion.completion_id.clone());
 6972
 6973            self.report_inline_completion_event(completion_id, false, cx);
 6974        }
 6975
 6976        if let Some(provider) = self.edit_prediction_provider() {
 6977            provider.discard(cx);
 6978        }
 6979
 6980        self.take_active_inline_completion(cx)
 6981    }
 6982
 6983    fn report_inline_completion_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 6984        let Some(provider) = self.edit_prediction_provider() else {
 6985            return;
 6986        };
 6987
 6988        let Some((_, buffer, _)) = self
 6989            .buffer
 6990            .read(cx)
 6991            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 6992        else {
 6993            return;
 6994        };
 6995
 6996        let extension = buffer
 6997            .read(cx)
 6998            .file()
 6999            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7000
 7001        let event_type = match accepted {
 7002            true => "Edit Prediction Accepted",
 7003            false => "Edit Prediction Discarded",
 7004        };
 7005        telemetry::event!(
 7006            event_type,
 7007            provider = provider.name(),
 7008            prediction_id = id,
 7009            suggestion_accepted = accepted,
 7010            file_extension = extension,
 7011        );
 7012    }
 7013
 7014    pub fn has_active_inline_completion(&self) -> bool {
 7015        self.active_inline_completion.is_some()
 7016    }
 7017
 7018    fn take_active_inline_completion(&mut self, cx: &mut Context<Self>) -> bool {
 7019        let Some(active_inline_completion) = self.active_inline_completion.take() else {
 7020            return false;
 7021        };
 7022
 7023        self.splice_inlays(&active_inline_completion.inlay_ids, Default::default(), cx);
 7024        self.clear_highlights::<InlineCompletionHighlight>(cx);
 7025        self.stale_inline_completion_in_menu = Some(active_inline_completion);
 7026        true
 7027    }
 7028
 7029    /// Returns true when we're displaying the edit prediction popover below the cursor
 7030    /// like we are not previewing and the LSP autocomplete menu is visible
 7031    /// or we are in `when_holding_modifier` mode.
 7032    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7033        if self.edit_prediction_preview_is_active()
 7034            || !self.show_edit_predictions_in_menu()
 7035            || !self.edit_predictions_enabled()
 7036        {
 7037            return false;
 7038        }
 7039
 7040        if self.has_visible_completions_menu() {
 7041            return true;
 7042        }
 7043
 7044        has_completion && self.edit_prediction_requires_modifier()
 7045    }
 7046
 7047    fn handle_modifiers_changed(
 7048        &mut self,
 7049        modifiers: Modifiers,
 7050        position_map: &PositionMap,
 7051        window: &mut Window,
 7052        cx: &mut Context<Self>,
 7053    ) {
 7054        if self.show_edit_predictions_in_menu() {
 7055            self.update_edit_prediction_preview(&modifiers, window, cx);
 7056        }
 7057
 7058        self.update_selection_mode(&modifiers, position_map, window, cx);
 7059
 7060        let mouse_position = window.mouse_position();
 7061        if !position_map.text_hitbox.is_hovered(window) {
 7062            return;
 7063        }
 7064
 7065        self.update_hovered_link(
 7066            position_map.point_for_position(mouse_position),
 7067            &position_map.snapshot,
 7068            modifiers,
 7069            window,
 7070            cx,
 7071        )
 7072    }
 7073
 7074    fn update_selection_mode(
 7075        &mut self,
 7076        modifiers: &Modifiers,
 7077        position_map: &PositionMap,
 7078        window: &mut Window,
 7079        cx: &mut Context<Self>,
 7080    ) {
 7081        if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
 7082            return;
 7083        }
 7084
 7085        let mouse_position = window.mouse_position();
 7086        let point_for_position = position_map.point_for_position(mouse_position);
 7087        let position = point_for_position.previous_valid;
 7088
 7089        self.select(
 7090            SelectPhase::BeginColumnar {
 7091                position,
 7092                reset: false,
 7093                goal_column: point_for_position.exact_unclipped.column(),
 7094            },
 7095            window,
 7096            cx,
 7097        );
 7098    }
 7099
 7100    fn update_edit_prediction_preview(
 7101        &mut self,
 7102        modifiers: &Modifiers,
 7103        window: &mut Window,
 7104        cx: &mut Context<Self>,
 7105    ) {
 7106        let accept_keybind = self.accept_edit_prediction_keybind(window, cx);
 7107        let Some(accept_keystroke) = accept_keybind.keystroke() else {
 7108            return;
 7109        };
 7110
 7111        if &accept_keystroke.modifiers == modifiers && accept_keystroke.modifiers.modified() {
 7112            if matches!(
 7113                self.edit_prediction_preview,
 7114                EditPredictionPreview::Inactive { .. }
 7115            ) {
 7116                self.edit_prediction_preview = EditPredictionPreview::Active {
 7117                    previous_scroll_position: None,
 7118                    since: Instant::now(),
 7119                };
 7120
 7121                self.update_visible_inline_completion(window, cx);
 7122                cx.notify();
 7123            }
 7124        } else if let EditPredictionPreview::Active {
 7125            previous_scroll_position,
 7126            since,
 7127        } = self.edit_prediction_preview
 7128        {
 7129            if let (Some(previous_scroll_position), Some(position_map)) =
 7130                (previous_scroll_position, self.last_position_map.as_ref())
 7131            {
 7132                self.set_scroll_position(
 7133                    previous_scroll_position
 7134                        .scroll_position(&position_map.snapshot.display_snapshot),
 7135                    window,
 7136                    cx,
 7137                );
 7138            }
 7139
 7140            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7141                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7142            };
 7143            self.clear_row_highlights::<EditPredictionPreview>();
 7144            self.update_visible_inline_completion(window, cx);
 7145            cx.notify();
 7146        }
 7147    }
 7148
 7149    fn update_visible_inline_completion(
 7150        &mut self,
 7151        _window: &mut Window,
 7152        cx: &mut Context<Self>,
 7153    ) -> Option<()> {
 7154        let selection = self.selections.newest_anchor();
 7155        let cursor = selection.head();
 7156        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7157        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7158        let excerpt_id = cursor.excerpt_id;
 7159
 7160        let show_in_menu = self.show_edit_predictions_in_menu();
 7161        let completions_menu_has_precedence = !show_in_menu
 7162            && (self.context_menu.borrow().is_some()
 7163                || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
 7164
 7165        if completions_menu_has_precedence
 7166            || !offset_selection.is_empty()
 7167            || self
 7168                .active_inline_completion
 7169                .as_ref()
 7170                .map_or(false, |completion| {
 7171                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7172                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7173                    !invalidation_range.contains(&offset_selection.head())
 7174                })
 7175        {
 7176            self.discard_inline_completion(false, cx);
 7177            return None;
 7178        }
 7179
 7180        self.take_active_inline_completion(cx);
 7181        let Some(provider) = self.edit_prediction_provider() else {
 7182            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7183            return None;
 7184        };
 7185
 7186        let (buffer, cursor_buffer_position) =
 7187            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7188
 7189        self.edit_prediction_settings =
 7190            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7191
 7192        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7193
 7194        if self.edit_prediction_indent_conflict {
 7195            let cursor_point = cursor.to_point(&multibuffer);
 7196
 7197            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7198
 7199            if let Some((_, indent)) = indents.iter().next() {
 7200                if indent.len == cursor_point.column {
 7201                    self.edit_prediction_indent_conflict = false;
 7202                }
 7203            }
 7204        }
 7205
 7206        let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7207        let edits = inline_completion
 7208            .edits
 7209            .into_iter()
 7210            .flat_map(|(range, new_text)| {
 7211                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7212                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7213                Some((start..end, new_text))
 7214            })
 7215            .collect::<Vec<_>>();
 7216        if edits.is_empty() {
 7217            return None;
 7218        }
 7219
 7220        let first_edit_start = edits.first().unwrap().0.start;
 7221        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7222        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7223
 7224        let last_edit_end = edits.last().unwrap().0.end;
 7225        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7226        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7227
 7228        let cursor_row = cursor.to_point(&multibuffer).row;
 7229
 7230        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7231
 7232        let mut inlay_ids = Vec::new();
 7233        let invalidation_row_range;
 7234        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7235            Some(cursor_row..edit_end_row)
 7236        } else if cursor_row > edit_end_row {
 7237            Some(edit_start_row..cursor_row)
 7238        } else {
 7239            None
 7240        };
 7241        let is_move =
 7242            move_invalidation_row_range.is_some() || self.inline_completions_hidden_for_vim_mode;
 7243        let completion = if is_move {
 7244            invalidation_row_range =
 7245                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7246            let target = first_edit_start;
 7247            InlineCompletion::Move { target, snapshot }
 7248        } else {
 7249            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7250                && !self.inline_completions_hidden_for_vim_mode;
 7251
 7252            if show_completions_in_buffer {
 7253                if edits
 7254                    .iter()
 7255                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7256                {
 7257                    let mut inlays = Vec::new();
 7258                    for (range, new_text) in &edits {
 7259                        let inlay = Inlay::inline_completion(
 7260                            post_inc(&mut self.next_inlay_id),
 7261                            range.start,
 7262                            new_text.as_str(),
 7263                        );
 7264                        inlay_ids.push(inlay.id);
 7265                        inlays.push(inlay);
 7266                    }
 7267
 7268                    self.splice_inlays(&[], inlays, cx);
 7269                } else {
 7270                    let background_color = cx.theme().status().deleted_background;
 7271                    self.highlight_text::<InlineCompletionHighlight>(
 7272                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7273                        HighlightStyle {
 7274                            background_color: Some(background_color),
 7275                            ..Default::default()
 7276                        },
 7277                        cx,
 7278                    );
 7279                }
 7280            }
 7281
 7282            invalidation_row_range = edit_start_row..edit_end_row;
 7283
 7284            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7285                if provider.show_tab_accept_marker() {
 7286                    EditDisplayMode::TabAccept
 7287                } else {
 7288                    EditDisplayMode::Inline
 7289                }
 7290            } else {
 7291                EditDisplayMode::DiffPopover
 7292            };
 7293
 7294            InlineCompletion::Edit {
 7295                edits,
 7296                edit_preview: inline_completion.edit_preview,
 7297                display_mode,
 7298                snapshot,
 7299            }
 7300        };
 7301
 7302        let invalidation_range = multibuffer
 7303            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7304            ..multibuffer.anchor_after(Point::new(
 7305                invalidation_row_range.end,
 7306                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7307            ));
 7308
 7309        self.stale_inline_completion_in_menu = None;
 7310        self.active_inline_completion = Some(InlineCompletionState {
 7311            inlay_ids,
 7312            completion,
 7313            completion_id: inline_completion.id,
 7314            invalidation_range,
 7315        });
 7316
 7317        cx.notify();
 7318
 7319        Some(())
 7320    }
 7321
 7322    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn InlineCompletionProviderHandle>> {
 7323        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7324    }
 7325
 7326    fn clear_tasks(&mut self) {
 7327        self.tasks.clear()
 7328    }
 7329
 7330    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7331        if self.tasks.insert(key, value).is_some() {
 7332            // This case should hopefully be rare, but just in case...
 7333            log::error!(
 7334                "multiple different run targets found on a single line, only the last target will be rendered"
 7335            )
 7336        }
 7337    }
 7338
 7339    /// Get all display points of breakpoints that will be rendered within editor
 7340    ///
 7341    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7342    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7343    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7344    fn active_breakpoints(
 7345        &self,
 7346        range: Range<DisplayRow>,
 7347        window: &mut Window,
 7348        cx: &mut Context<Self>,
 7349    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7350        let mut breakpoint_display_points = HashMap::default();
 7351
 7352        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7353            return breakpoint_display_points;
 7354        };
 7355
 7356        let snapshot = self.snapshot(window, cx);
 7357
 7358        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7359        let Some(project) = self.project.as_ref() else {
 7360            return breakpoint_display_points;
 7361        };
 7362
 7363        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7364            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7365
 7366        for (buffer_snapshot, range, excerpt_id) in
 7367            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7368        {
 7369            let Some(buffer) = project
 7370                .read(cx)
 7371                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7372            else {
 7373                continue;
 7374            };
 7375            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7376                &buffer,
 7377                Some(
 7378                    buffer_snapshot.anchor_before(range.start)
 7379                        ..buffer_snapshot.anchor_after(range.end),
 7380                ),
 7381                buffer_snapshot,
 7382                cx,
 7383            );
 7384            for (breakpoint, state) in breakpoints {
 7385                let multi_buffer_anchor =
 7386                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7387                let position = multi_buffer_anchor
 7388                    .to_point(&multi_buffer_snapshot)
 7389                    .to_display_point(&snapshot);
 7390
 7391                breakpoint_display_points.insert(
 7392                    position.row(),
 7393                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7394                );
 7395            }
 7396        }
 7397
 7398        breakpoint_display_points
 7399    }
 7400
 7401    fn breakpoint_context_menu(
 7402        &self,
 7403        anchor: Anchor,
 7404        window: &mut Window,
 7405        cx: &mut Context<Self>,
 7406    ) -> Entity<ui::ContextMenu> {
 7407        let weak_editor = cx.weak_entity();
 7408        let focus_handle = self.focus_handle(cx);
 7409
 7410        let row = self
 7411            .buffer
 7412            .read(cx)
 7413            .snapshot(cx)
 7414            .summary_for_anchor::<Point>(&anchor)
 7415            .row;
 7416
 7417        let breakpoint = self
 7418            .breakpoint_at_row(row, window, cx)
 7419            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7420
 7421        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7422            "Edit Log Breakpoint"
 7423        } else {
 7424            "Set Log Breakpoint"
 7425        };
 7426
 7427        let condition_breakpoint_msg = if breakpoint
 7428            .as_ref()
 7429            .is_some_and(|bp| bp.1.condition.is_some())
 7430        {
 7431            "Edit Condition Breakpoint"
 7432        } else {
 7433            "Set Condition Breakpoint"
 7434        };
 7435
 7436        let hit_condition_breakpoint_msg = if breakpoint
 7437            .as_ref()
 7438            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7439        {
 7440            "Edit Hit Condition Breakpoint"
 7441        } else {
 7442            "Set Hit Condition Breakpoint"
 7443        };
 7444
 7445        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7446            "Unset Breakpoint"
 7447        } else {
 7448            "Set Breakpoint"
 7449        };
 7450
 7451        let run_to_cursor = command_palette_hooks::CommandPaletteFilter::try_global(cx)
 7452            .map_or(false, |filter| !filter.is_hidden(&DebuggerRunToCursor));
 7453
 7454        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 7455            BreakpointState::Enabled => Some("Disable"),
 7456            BreakpointState::Disabled => Some("Enable"),
 7457        });
 7458
 7459        let (anchor, breakpoint) =
 7460            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 7461
 7462        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 7463            menu.on_blur_subscription(Subscription::new(|| {}))
 7464                .context(focus_handle)
 7465                .when(run_to_cursor, |this| {
 7466                    let weak_editor = weak_editor.clone();
 7467                    this.entry("Run to cursor", None, move |window, cx| {
 7468                        weak_editor
 7469                            .update(cx, |editor, cx| {
 7470                                editor.change_selections(None, window, cx, |s| {
 7471                                    s.select_ranges([Point::new(row, 0)..Point::new(row, 0)])
 7472                                });
 7473                            })
 7474                            .ok();
 7475
 7476                        window.dispatch_action(Box::new(DebuggerRunToCursor), cx);
 7477                    })
 7478                    .separator()
 7479                })
 7480                .when_some(toggle_state_msg, |this, msg| {
 7481                    this.entry(msg, None, {
 7482                        let weak_editor = weak_editor.clone();
 7483                        let breakpoint = breakpoint.clone();
 7484                        move |_window, cx| {
 7485                            weak_editor
 7486                                .update(cx, |this, cx| {
 7487                                    this.edit_breakpoint_at_anchor(
 7488                                        anchor,
 7489                                        breakpoint.as_ref().clone(),
 7490                                        BreakpointEditAction::InvertState,
 7491                                        cx,
 7492                                    );
 7493                                })
 7494                                .log_err();
 7495                        }
 7496                    })
 7497                })
 7498                .entry(set_breakpoint_msg, None, {
 7499                    let weak_editor = weak_editor.clone();
 7500                    let breakpoint = breakpoint.clone();
 7501                    move |_window, cx| {
 7502                        weak_editor
 7503                            .update(cx, |this, cx| {
 7504                                this.edit_breakpoint_at_anchor(
 7505                                    anchor,
 7506                                    breakpoint.as_ref().clone(),
 7507                                    BreakpointEditAction::Toggle,
 7508                                    cx,
 7509                                );
 7510                            })
 7511                            .log_err();
 7512                    }
 7513                })
 7514                .entry(log_breakpoint_msg, None, {
 7515                    let breakpoint = breakpoint.clone();
 7516                    let weak_editor = weak_editor.clone();
 7517                    move |window, cx| {
 7518                        weak_editor
 7519                            .update(cx, |this, cx| {
 7520                                this.add_edit_breakpoint_block(
 7521                                    anchor,
 7522                                    breakpoint.as_ref(),
 7523                                    BreakpointPromptEditAction::Log,
 7524                                    window,
 7525                                    cx,
 7526                                );
 7527                            })
 7528                            .log_err();
 7529                    }
 7530                })
 7531                .entry(condition_breakpoint_msg, None, {
 7532                    let breakpoint = breakpoint.clone();
 7533                    let weak_editor = weak_editor.clone();
 7534                    move |window, cx| {
 7535                        weak_editor
 7536                            .update(cx, |this, cx| {
 7537                                this.add_edit_breakpoint_block(
 7538                                    anchor,
 7539                                    breakpoint.as_ref(),
 7540                                    BreakpointPromptEditAction::Condition,
 7541                                    window,
 7542                                    cx,
 7543                                );
 7544                            })
 7545                            .log_err();
 7546                    }
 7547                })
 7548                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 7549                    weak_editor
 7550                        .update(cx, |this, cx| {
 7551                            this.add_edit_breakpoint_block(
 7552                                anchor,
 7553                                breakpoint.as_ref(),
 7554                                BreakpointPromptEditAction::HitCondition,
 7555                                window,
 7556                                cx,
 7557                            );
 7558                        })
 7559                        .log_err();
 7560                })
 7561        })
 7562    }
 7563
 7564    fn render_breakpoint(
 7565        &self,
 7566        position: Anchor,
 7567        row: DisplayRow,
 7568        breakpoint: &Breakpoint,
 7569        state: Option<BreakpointSessionState>,
 7570        cx: &mut Context<Self>,
 7571    ) -> IconButton {
 7572        let is_rejected = state.is_some_and(|s| !s.verified);
 7573        // Is it a breakpoint that shows up when hovering over gutter?
 7574        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 7575            (false, false),
 7576            |PhantomBreakpointIndicator {
 7577                 is_active,
 7578                 display_row,
 7579                 collides_with_existing_breakpoint,
 7580             }| {
 7581                (
 7582                    is_active && display_row == row,
 7583                    collides_with_existing_breakpoint,
 7584                )
 7585            },
 7586        );
 7587
 7588        let (color, icon) = {
 7589            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 7590                (false, false) => ui::IconName::DebugBreakpoint,
 7591                (true, false) => ui::IconName::DebugLogBreakpoint,
 7592                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 7593                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 7594            };
 7595
 7596            let color = if is_phantom {
 7597                Color::Hint
 7598            } else if is_rejected {
 7599                Color::Disabled
 7600            } else {
 7601                Color::Debugger
 7602            };
 7603
 7604            (color, icon)
 7605        };
 7606
 7607        let breakpoint = Arc::from(breakpoint.clone());
 7608
 7609        let alt_as_text = gpui::Keystroke {
 7610            modifiers: Modifiers::secondary_key(),
 7611            ..Default::default()
 7612        };
 7613        let primary_action_text = if breakpoint.is_disabled() {
 7614            "Enable breakpoint"
 7615        } else if is_phantom && !collides_with_existing {
 7616            "Set breakpoint"
 7617        } else {
 7618            "Unset breakpoint"
 7619        };
 7620        let focus_handle = self.focus_handle.clone();
 7621
 7622        let meta = if is_rejected {
 7623            SharedString::from("No executable code is associated with this line.")
 7624        } else if collides_with_existing && !breakpoint.is_disabled() {
 7625            SharedString::from(format!(
 7626                "{alt_as_text}-click to disable,\nright-click for more options."
 7627            ))
 7628        } else {
 7629            SharedString::from("Right-click for more options.")
 7630        };
 7631        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 7632            .icon_size(IconSize::XSmall)
 7633            .size(ui::ButtonSize::None)
 7634            .when(is_rejected, |this| {
 7635                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 7636            })
 7637            .icon_color(color)
 7638            .style(ButtonStyle::Transparent)
 7639            .on_click(cx.listener({
 7640                let breakpoint = breakpoint.clone();
 7641
 7642                move |editor, event: &ClickEvent, window, cx| {
 7643                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 7644                        BreakpointEditAction::InvertState
 7645                    } else {
 7646                        BreakpointEditAction::Toggle
 7647                    };
 7648
 7649                    window.focus(&editor.focus_handle(cx));
 7650                    editor.edit_breakpoint_at_anchor(
 7651                        position,
 7652                        breakpoint.as_ref().clone(),
 7653                        edit_action,
 7654                        cx,
 7655                    );
 7656                }
 7657            }))
 7658            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7659                editor.set_breakpoint_context_menu(
 7660                    row,
 7661                    Some(position),
 7662                    event.down.position,
 7663                    window,
 7664                    cx,
 7665                );
 7666            }))
 7667            .tooltip(move |window, cx| {
 7668                Tooltip::with_meta_in(
 7669                    primary_action_text,
 7670                    Some(&ToggleBreakpoint),
 7671                    meta.clone(),
 7672                    &focus_handle,
 7673                    window,
 7674                    cx,
 7675                )
 7676            })
 7677    }
 7678
 7679    fn build_tasks_context(
 7680        project: &Entity<Project>,
 7681        buffer: &Entity<Buffer>,
 7682        buffer_row: u32,
 7683        tasks: &Arc<RunnableTasks>,
 7684        cx: &mut Context<Self>,
 7685    ) -> Task<Option<task::TaskContext>> {
 7686        let position = Point::new(buffer_row, tasks.column);
 7687        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 7688        let location = Location {
 7689            buffer: buffer.clone(),
 7690            range: range_start..range_start,
 7691        };
 7692        // Fill in the environmental variables from the tree-sitter captures
 7693        let mut captured_task_variables = TaskVariables::default();
 7694        for (capture_name, value) in tasks.extra_variables.clone() {
 7695            captured_task_variables.insert(
 7696                task::VariableName::Custom(capture_name.into()),
 7697                value.clone(),
 7698            );
 7699        }
 7700        project.update(cx, |project, cx| {
 7701            project.task_store().update(cx, |task_store, cx| {
 7702                task_store.task_context_for_location(captured_task_variables, location, cx)
 7703            })
 7704        })
 7705    }
 7706
 7707    pub fn spawn_nearest_task(
 7708        &mut self,
 7709        action: &SpawnNearestTask,
 7710        window: &mut Window,
 7711        cx: &mut Context<Self>,
 7712    ) {
 7713        let Some((workspace, _)) = self.workspace.clone() else {
 7714            return;
 7715        };
 7716        let Some(project) = self.project.clone() else {
 7717            return;
 7718        };
 7719
 7720        // Try to find a closest, enclosing node using tree-sitter that has a
 7721        // task
 7722        let Some((buffer, buffer_row, tasks)) = self
 7723            .find_enclosing_node_task(cx)
 7724            // Or find the task that's closest in row-distance.
 7725            .or_else(|| self.find_closest_task(cx))
 7726        else {
 7727            return;
 7728        };
 7729
 7730        let reveal_strategy = action.reveal;
 7731        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 7732        cx.spawn_in(window, async move |_, cx| {
 7733            let context = task_context.await?;
 7734            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 7735
 7736            let resolved = &mut resolved_task.resolved;
 7737            resolved.reveal = reveal_strategy;
 7738
 7739            workspace
 7740                .update_in(cx, |workspace, window, cx| {
 7741                    workspace.schedule_resolved_task(
 7742                        task_source_kind,
 7743                        resolved_task,
 7744                        false,
 7745                        window,
 7746                        cx,
 7747                    );
 7748                })
 7749                .ok()
 7750        })
 7751        .detach();
 7752    }
 7753
 7754    fn find_closest_task(
 7755        &mut self,
 7756        cx: &mut Context<Self>,
 7757    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7758        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 7759
 7760        let ((buffer_id, row), tasks) = self
 7761            .tasks
 7762            .iter()
 7763            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 7764
 7765        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 7766        let tasks = Arc::new(tasks.to_owned());
 7767        Some((buffer, *row, tasks))
 7768    }
 7769
 7770    fn find_enclosing_node_task(
 7771        &mut self,
 7772        cx: &mut Context<Self>,
 7773    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 7774        let snapshot = self.buffer.read(cx).snapshot(cx);
 7775        let offset = self.selections.newest::<usize>(cx).head();
 7776        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 7777        let buffer_id = excerpt.buffer().remote_id();
 7778
 7779        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 7780        let mut cursor = layer.node().walk();
 7781
 7782        while cursor.goto_first_child_for_byte(offset).is_some() {
 7783            if cursor.node().end_byte() == offset {
 7784                cursor.goto_next_sibling();
 7785            }
 7786        }
 7787
 7788        // Ascend to the smallest ancestor that contains the range and has a task.
 7789        loop {
 7790            let node = cursor.node();
 7791            let node_range = node.byte_range();
 7792            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 7793
 7794            // Check if this node contains our offset
 7795            if node_range.start <= offset && node_range.end >= offset {
 7796                // If it contains offset, check for task
 7797                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 7798                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 7799                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 7800                }
 7801            }
 7802
 7803            if !cursor.goto_parent() {
 7804                break;
 7805            }
 7806        }
 7807        None
 7808    }
 7809
 7810    fn render_run_indicator(
 7811        &self,
 7812        _style: &EditorStyle,
 7813        is_active: bool,
 7814        row: DisplayRow,
 7815        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 7816        cx: &mut Context<Self>,
 7817    ) -> IconButton {
 7818        let color = Color::Muted;
 7819        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 7820
 7821        IconButton::new(("run_indicator", row.0 as usize), ui::IconName::Play)
 7822            .shape(ui::IconButtonShape::Square)
 7823            .icon_size(IconSize::XSmall)
 7824            .icon_color(color)
 7825            .toggle_state(is_active)
 7826            .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 7827                let quick_launch = e.down.button == MouseButton::Left;
 7828                window.focus(&editor.focus_handle(cx));
 7829                editor.toggle_code_actions(
 7830                    &ToggleCodeActions {
 7831                        deployed_from: Some(CodeActionSource::Indicator(row)),
 7832                        quick_launch,
 7833                    },
 7834                    window,
 7835                    cx,
 7836                );
 7837            }))
 7838            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 7839                editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
 7840            }))
 7841    }
 7842
 7843    pub fn context_menu_visible(&self) -> bool {
 7844        !self.edit_prediction_preview_is_active()
 7845            && self
 7846                .context_menu
 7847                .borrow()
 7848                .as_ref()
 7849                .map_or(false, |menu| menu.visible())
 7850    }
 7851
 7852    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 7853        self.context_menu
 7854            .borrow()
 7855            .as_ref()
 7856            .map(|menu| menu.origin())
 7857    }
 7858
 7859    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 7860        self.context_menu_options = Some(options);
 7861    }
 7862
 7863    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 7864    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 7865
 7866    fn render_edit_prediction_popover(
 7867        &mut self,
 7868        text_bounds: &Bounds<Pixels>,
 7869        content_origin: gpui::Point<Pixels>,
 7870        right_margin: Pixels,
 7871        editor_snapshot: &EditorSnapshot,
 7872        visible_row_range: Range<DisplayRow>,
 7873        scroll_top: f32,
 7874        scroll_bottom: f32,
 7875        line_layouts: &[LineWithInvisibles],
 7876        line_height: Pixels,
 7877        scroll_pixel_position: gpui::Point<Pixels>,
 7878        newest_selection_head: Option<DisplayPoint>,
 7879        editor_width: Pixels,
 7880        style: &EditorStyle,
 7881        window: &mut Window,
 7882        cx: &mut App,
 7883    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7884        if self.mode().is_minimap() {
 7885            return None;
 7886        }
 7887        let active_inline_completion = self.active_inline_completion.as_ref()?;
 7888
 7889        if self.edit_prediction_visible_in_cursor_popover(true) {
 7890            return None;
 7891        }
 7892
 7893        match &active_inline_completion.completion {
 7894            InlineCompletion::Move { target, .. } => {
 7895                let target_display_point = target.to_display_point(editor_snapshot);
 7896
 7897                if self.edit_prediction_requires_modifier() {
 7898                    if !self.edit_prediction_preview_is_active() {
 7899                        return None;
 7900                    }
 7901
 7902                    self.render_edit_prediction_modifier_jump_popover(
 7903                        text_bounds,
 7904                        content_origin,
 7905                        visible_row_range,
 7906                        line_layouts,
 7907                        line_height,
 7908                        scroll_pixel_position,
 7909                        newest_selection_head,
 7910                        target_display_point,
 7911                        window,
 7912                        cx,
 7913                    )
 7914                } else {
 7915                    self.render_edit_prediction_eager_jump_popover(
 7916                        text_bounds,
 7917                        content_origin,
 7918                        editor_snapshot,
 7919                        visible_row_range,
 7920                        scroll_top,
 7921                        scroll_bottom,
 7922                        line_height,
 7923                        scroll_pixel_position,
 7924                        target_display_point,
 7925                        editor_width,
 7926                        window,
 7927                        cx,
 7928                    )
 7929                }
 7930            }
 7931            InlineCompletion::Edit {
 7932                display_mode: EditDisplayMode::Inline,
 7933                ..
 7934            } => None,
 7935            InlineCompletion::Edit {
 7936                display_mode: EditDisplayMode::TabAccept,
 7937                edits,
 7938                ..
 7939            } => {
 7940                let range = &edits.first()?.0;
 7941                let target_display_point = range.end.to_display_point(editor_snapshot);
 7942
 7943                self.render_edit_prediction_end_of_line_popover(
 7944                    "Accept",
 7945                    editor_snapshot,
 7946                    visible_row_range,
 7947                    target_display_point,
 7948                    line_height,
 7949                    scroll_pixel_position,
 7950                    content_origin,
 7951                    editor_width,
 7952                    window,
 7953                    cx,
 7954                )
 7955            }
 7956            InlineCompletion::Edit {
 7957                edits,
 7958                edit_preview,
 7959                display_mode: EditDisplayMode::DiffPopover,
 7960                snapshot,
 7961            } => self.render_edit_prediction_diff_popover(
 7962                text_bounds,
 7963                content_origin,
 7964                right_margin,
 7965                editor_snapshot,
 7966                visible_row_range,
 7967                line_layouts,
 7968                line_height,
 7969                scroll_pixel_position,
 7970                newest_selection_head,
 7971                editor_width,
 7972                style,
 7973                edits,
 7974                edit_preview,
 7975                snapshot,
 7976                window,
 7977                cx,
 7978            ),
 7979        }
 7980    }
 7981
 7982    fn render_edit_prediction_modifier_jump_popover(
 7983        &mut self,
 7984        text_bounds: &Bounds<Pixels>,
 7985        content_origin: gpui::Point<Pixels>,
 7986        visible_row_range: Range<DisplayRow>,
 7987        line_layouts: &[LineWithInvisibles],
 7988        line_height: Pixels,
 7989        scroll_pixel_position: gpui::Point<Pixels>,
 7990        newest_selection_head: Option<DisplayPoint>,
 7991        target_display_point: DisplayPoint,
 7992        window: &mut Window,
 7993        cx: &mut App,
 7994    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 7995        let scrolled_content_origin =
 7996            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 7997
 7998        const SCROLL_PADDING_Y: Pixels = px(12.);
 7999
 8000        if target_display_point.row() < visible_row_range.start {
 8001            return self.render_edit_prediction_scroll_popover(
 8002                |_| SCROLL_PADDING_Y,
 8003                IconName::ArrowUp,
 8004                visible_row_range,
 8005                line_layouts,
 8006                newest_selection_head,
 8007                scrolled_content_origin,
 8008                window,
 8009                cx,
 8010            );
 8011        } else if target_display_point.row() >= visible_row_range.end {
 8012            return self.render_edit_prediction_scroll_popover(
 8013                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8014                IconName::ArrowDown,
 8015                visible_row_range,
 8016                line_layouts,
 8017                newest_selection_head,
 8018                scrolled_content_origin,
 8019                window,
 8020                cx,
 8021            );
 8022        }
 8023
 8024        const POLE_WIDTH: Pixels = px(2.);
 8025
 8026        let line_layout =
 8027            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8028        let target_column = target_display_point.column() as usize;
 8029
 8030        let target_x = line_layout.x_for_index(target_column);
 8031        let target_y =
 8032            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8033
 8034        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8035
 8036        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8037        border_color.l += 0.001;
 8038
 8039        let mut element = v_flex()
 8040            .items_end()
 8041            .when(flag_on_right, |el| el.items_start())
 8042            .child(if flag_on_right {
 8043                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8044                    .rounded_bl(px(0.))
 8045                    .rounded_tl(px(0.))
 8046                    .border_l_2()
 8047                    .border_color(border_color)
 8048            } else {
 8049                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8050                    .rounded_br(px(0.))
 8051                    .rounded_tr(px(0.))
 8052                    .border_r_2()
 8053                    .border_color(border_color)
 8054            })
 8055            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8056            .into_any();
 8057
 8058        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8059
 8060        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8061            - point(
 8062                if flag_on_right {
 8063                    POLE_WIDTH
 8064                } else {
 8065                    size.width - POLE_WIDTH
 8066                },
 8067                size.height - line_height,
 8068            );
 8069
 8070        origin.x = origin.x.max(content_origin.x);
 8071
 8072        element.prepaint_at(origin, window, cx);
 8073
 8074        Some((element, origin))
 8075    }
 8076
 8077    fn render_edit_prediction_scroll_popover(
 8078        &mut self,
 8079        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8080        scroll_icon: IconName,
 8081        visible_row_range: Range<DisplayRow>,
 8082        line_layouts: &[LineWithInvisibles],
 8083        newest_selection_head: Option<DisplayPoint>,
 8084        scrolled_content_origin: gpui::Point<Pixels>,
 8085        window: &mut Window,
 8086        cx: &mut App,
 8087    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8088        let mut element = self
 8089            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8090            .into_any();
 8091
 8092        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8093
 8094        let cursor = newest_selection_head?;
 8095        let cursor_row_layout =
 8096            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8097        let cursor_column = cursor.column() as usize;
 8098
 8099        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8100
 8101        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8102
 8103        element.prepaint_at(origin, window, cx);
 8104        Some((element, origin))
 8105    }
 8106
 8107    fn render_edit_prediction_eager_jump_popover(
 8108        &mut self,
 8109        text_bounds: &Bounds<Pixels>,
 8110        content_origin: gpui::Point<Pixels>,
 8111        editor_snapshot: &EditorSnapshot,
 8112        visible_row_range: Range<DisplayRow>,
 8113        scroll_top: f32,
 8114        scroll_bottom: f32,
 8115        line_height: Pixels,
 8116        scroll_pixel_position: gpui::Point<Pixels>,
 8117        target_display_point: DisplayPoint,
 8118        editor_width: Pixels,
 8119        window: &mut Window,
 8120        cx: &mut App,
 8121    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8122        if target_display_point.row().as_f32() < scroll_top {
 8123            let mut element = self
 8124                .render_edit_prediction_line_popover(
 8125                    "Jump to Edit",
 8126                    Some(IconName::ArrowUp),
 8127                    window,
 8128                    cx,
 8129                )?
 8130                .into_any();
 8131
 8132            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8133            let offset = point(
 8134                (text_bounds.size.width - size.width) / 2.,
 8135                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8136            );
 8137
 8138            let origin = text_bounds.origin + offset;
 8139            element.prepaint_at(origin, window, cx);
 8140            Some((element, origin))
 8141        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8142            let mut element = self
 8143                .render_edit_prediction_line_popover(
 8144                    "Jump to Edit",
 8145                    Some(IconName::ArrowDown),
 8146                    window,
 8147                    cx,
 8148                )?
 8149                .into_any();
 8150
 8151            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8152            let offset = point(
 8153                (text_bounds.size.width - size.width) / 2.,
 8154                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8155            );
 8156
 8157            let origin = text_bounds.origin + offset;
 8158            element.prepaint_at(origin, window, cx);
 8159            Some((element, origin))
 8160        } else {
 8161            self.render_edit_prediction_end_of_line_popover(
 8162                "Jump to Edit",
 8163                editor_snapshot,
 8164                visible_row_range,
 8165                target_display_point,
 8166                line_height,
 8167                scroll_pixel_position,
 8168                content_origin,
 8169                editor_width,
 8170                window,
 8171                cx,
 8172            )
 8173        }
 8174    }
 8175
 8176    fn render_edit_prediction_end_of_line_popover(
 8177        self: &mut Editor,
 8178        label: &'static str,
 8179        editor_snapshot: &EditorSnapshot,
 8180        visible_row_range: Range<DisplayRow>,
 8181        target_display_point: DisplayPoint,
 8182        line_height: Pixels,
 8183        scroll_pixel_position: gpui::Point<Pixels>,
 8184        content_origin: gpui::Point<Pixels>,
 8185        editor_width: Pixels,
 8186        window: &mut Window,
 8187        cx: &mut App,
 8188    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8189        let target_line_end = DisplayPoint::new(
 8190            target_display_point.row(),
 8191            editor_snapshot.line_len(target_display_point.row()),
 8192        );
 8193
 8194        let mut element = self
 8195            .render_edit_prediction_line_popover(label, None, window, cx)?
 8196            .into_any();
 8197
 8198        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8199
 8200        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8201
 8202        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8203        let mut origin = start_point
 8204            + line_origin
 8205            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8206        origin.x = origin.x.max(content_origin.x);
 8207
 8208        let max_x = content_origin.x + editor_width - size.width;
 8209
 8210        if origin.x > max_x {
 8211            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8212
 8213            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8214                origin.y += offset;
 8215                IconName::ArrowUp
 8216            } else {
 8217                origin.y -= offset;
 8218                IconName::ArrowDown
 8219            };
 8220
 8221            element = self
 8222                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8223                .into_any();
 8224
 8225            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8226
 8227            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8228        }
 8229
 8230        element.prepaint_at(origin, window, cx);
 8231        Some((element, origin))
 8232    }
 8233
 8234    fn render_edit_prediction_diff_popover(
 8235        self: &Editor,
 8236        text_bounds: &Bounds<Pixels>,
 8237        content_origin: gpui::Point<Pixels>,
 8238        right_margin: Pixels,
 8239        editor_snapshot: &EditorSnapshot,
 8240        visible_row_range: Range<DisplayRow>,
 8241        line_layouts: &[LineWithInvisibles],
 8242        line_height: Pixels,
 8243        scroll_pixel_position: gpui::Point<Pixels>,
 8244        newest_selection_head: Option<DisplayPoint>,
 8245        editor_width: Pixels,
 8246        style: &EditorStyle,
 8247        edits: &Vec<(Range<Anchor>, String)>,
 8248        edit_preview: &Option<language::EditPreview>,
 8249        snapshot: &language::BufferSnapshot,
 8250        window: &mut Window,
 8251        cx: &mut App,
 8252    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8253        let edit_start = edits
 8254            .first()
 8255            .unwrap()
 8256            .0
 8257            .start
 8258            .to_display_point(editor_snapshot);
 8259        let edit_end = edits
 8260            .last()
 8261            .unwrap()
 8262            .0
 8263            .end
 8264            .to_display_point(editor_snapshot);
 8265
 8266        let is_visible = visible_row_range.contains(&edit_start.row())
 8267            || visible_row_range.contains(&edit_end.row());
 8268        if !is_visible {
 8269            return None;
 8270        }
 8271
 8272        let highlighted_edits =
 8273            crate::inline_completion_edit_text(&snapshot, edits, edit_preview.as_ref()?, false, cx);
 8274
 8275        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8276        let line_count = highlighted_edits.text.lines().count();
 8277
 8278        const BORDER_WIDTH: Pixels = px(1.);
 8279
 8280        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8281        let has_keybind = keybind.is_some();
 8282
 8283        let mut element = h_flex()
 8284            .items_start()
 8285            .child(
 8286                h_flex()
 8287                    .bg(cx.theme().colors().editor_background)
 8288                    .border(BORDER_WIDTH)
 8289                    .shadow_sm()
 8290                    .border_color(cx.theme().colors().border)
 8291                    .rounded_l_lg()
 8292                    .when(line_count > 1, |el| el.rounded_br_lg())
 8293                    .pr_1()
 8294                    .child(styled_text),
 8295            )
 8296            .child(
 8297                h_flex()
 8298                    .h(line_height + BORDER_WIDTH * 2.)
 8299                    .px_1p5()
 8300                    .gap_1()
 8301                    // Workaround: For some reason, there's a gap if we don't do this
 8302                    .ml(-BORDER_WIDTH)
 8303                    .shadow(vec![gpui::BoxShadow {
 8304                        color: gpui::black().opacity(0.05),
 8305                        offset: point(px(1.), px(1.)),
 8306                        blur_radius: px(2.),
 8307                        spread_radius: px(0.),
 8308                    }])
 8309                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8310                    .border(BORDER_WIDTH)
 8311                    .border_color(cx.theme().colors().border)
 8312                    .rounded_r_lg()
 8313                    .id("edit_prediction_diff_popover_keybind")
 8314                    .when(!has_keybind, |el| {
 8315                        let status_colors = cx.theme().status();
 8316
 8317                        el.bg(status_colors.error_background)
 8318                            .border_color(status_colors.error.opacity(0.6))
 8319                            .child(Icon::new(IconName::Info).color(Color::Error))
 8320                            .cursor_default()
 8321                            .hoverable_tooltip(move |_window, cx| {
 8322                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8323                            })
 8324                    })
 8325                    .children(keybind),
 8326            )
 8327            .into_any();
 8328
 8329        let longest_row =
 8330            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8331        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8332            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8333        } else {
 8334            layout_line(
 8335                longest_row,
 8336                editor_snapshot,
 8337                style,
 8338                editor_width,
 8339                |_| false,
 8340                window,
 8341                cx,
 8342            )
 8343            .width
 8344        };
 8345
 8346        let viewport_bounds =
 8347            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8348                right: -right_margin,
 8349                ..Default::default()
 8350            });
 8351
 8352        let x_after_longest =
 8353            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8354                - scroll_pixel_position.x;
 8355
 8356        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8357
 8358        // Fully visible if it can be displayed within the window (allow overlapping other
 8359        // panes). However, this is only allowed if the popover starts within text_bounds.
 8360        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8361            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8362
 8363        let mut origin = if can_position_to_the_right {
 8364            point(
 8365                x_after_longest,
 8366                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8367                    - scroll_pixel_position.y,
 8368            )
 8369        } else {
 8370            let cursor_row = newest_selection_head.map(|head| head.row());
 8371            let above_edit = edit_start
 8372                .row()
 8373                .0
 8374                .checked_sub(line_count as u32)
 8375                .map(DisplayRow);
 8376            let below_edit = Some(edit_end.row() + 1);
 8377            let above_cursor =
 8378                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8379            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8380
 8381            // Place the edit popover adjacent to the edit if there is a location
 8382            // available that is onscreen and does not obscure the cursor. Otherwise,
 8383            // place it adjacent to the cursor.
 8384            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8385                .into_iter()
 8386                .flatten()
 8387                .find(|&start_row| {
 8388                    let end_row = start_row + line_count as u32;
 8389                    visible_row_range.contains(&start_row)
 8390                        && visible_row_range.contains(&end_row)
 8391                        && cursor_row.map_or(true, |cursor_row| {
 8392                            !((start_row..end_row).contains(&cursor_row))
 8393                        })
 8394                })?;
 8395
 8396            content_origin
 8397                + point(
 8398                    -scroll_pixel_position.x,
 8399                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8400                )
 8401        };
 8402
 8403        origin.x -= BORDER_WIDTH;
 8404
 8405        window.defer_draw(element, origin, 1);
 8406
 8407        // Do not return an element, since it will already be drawn due to defer_draw.
 8408        None
 8409    }
 8410
 8411    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8412        px(30.)
 8413    }
 8414
 8415    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8416        if self.read_only(cx) {
 8417            cx.theme().players().read_only()
 8418        } else {
 8419            self.style.as_ref().unwrap().local_player
 8420        }
 8421    }
 8422
 8423    fn render_edit_prediction_accept_keybind(
 8424        &self,
 8425        window: &mut Window,
 8426        cx: &App,
 8427    ) -> Option<AnyElement> {
 8428        let accept_binding = self.accept_edit_prediction_keybind(window, cx);
 8429        let accept_keystroke = accept_binding.keystroke()?;
 8430
 8431        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8432
 8433        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8434            Color::Accent
 8435        } else {
 8436            Color::Muted
 8437        };
 8438
 8439        h_flex()
 8440            .px_0p5()
 8441            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 8442            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8443            .text_size(TextSize::XSmall.rems(cx))
 8444            .child(h_flex().children(ui::render_modifiers(
 8445                &accept_keystroke.modifiers,
 8446                PlatformStyle::platform(),
 8447                Some(modifiers_color),
 8448                Some(IconSize::XSmall.rems().into()),
 8449                true,
 8450            )))
 8451            .when(is_platform_style_mac, |parent| {
 8452                parent.child(accept_keystroke.key.clone())
 8453            })
 8454            .when(!is_platform_style_mac, |parent| {
 8455                parent.child(
 8456                    Key::new(
 8457                        util::capitalize(&accept_keystroke.key),
 8458                        Some(Color::Default),
 8459                    )
 8460                    .size(Some(IconSize::XSmall.rems().into())),
 8461                )
 8462            })
 8463            .into_any()
 8464            .into()
 8465    }
 8466
 8467    fn render_edit_prediction_line_popover(
 8468        &self,
 8469        label: impl Into<SharedString>,
 8470        icon: Option<IconName>,
 8471        window: &mut Window,
 8472        cx: &App,
 8473    ) -> Option<Stateful<Div>> {
 8474        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 8475
 8476        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8477        let has_keybind = keybind.is_some();
 8478
 8479        let result = h_flex()
 8480            .id("ep-line-popover")
 8481            .py_0p5()
 8482            .pl_1()
 8483            .pr(padding_right)
 8484            .gap_1()
 8485            .rounded_md()
 8486            .border_1()
 8487            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8488            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 8489            .shadow_sm()
 8490            .when(!has_keybind, |el| {
 8491                let status_colors = cx.theme().status();
 8492
 8493                el.bg(status_colors.error_background)
 8494                    .border_color(status_colors.error.opacity(0.6))
 8495                    .pl_2()
 8496                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 8497                    .cursor_default()
 8498                    .hoverable_tooltip(move |_window, cx| {
 8499                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8500                    })
 8501            })
 8502            .children(keybind)
 8503            .child(
 8504                Label::new(label)
 8505                    .size(LabelSize::Small)
 8506                    .when(!has_keybind, |el| {
 8507                        el.color(cx.theme().status().error.into()).strikethrough()
 8508                    }),
 8509            )
 8510            .when(!has_keybind, |el| {
 8511                el.child(
 8512                    h_flex().ml_1().child(
 8513                        Icon::new(IconName::Info)
 8514                            .size(IconSize::Small)
 8515                            .color(cx.theme().status().error.into()),
 8516                    ),
 8517                )
 8518            })
 8519            .when_some(icon, |element, icon| {
 8520                element.child(
 8521                    div()
 8522                        .mt(px(1.5))
 8523                        .child(Icon::new(icon).size(IconSize::Small)),
 8524                )
 8525            });
 8526
 8527        Some(result)
 8528    }
 8529
 8530    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 8531        let accent_color = cx.theme().colors().text_accent;
 8532        let editor_bg_color = cx.theme().colors().editor_background;
 8533        editor_bg_color.blend(accent_color.opacity(0.1))
 8534    }
 8535
 8536    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 8537        let accent_color = cx.theme().colors().text_accent;
 8538        let editor_bg_color = cx.theme().colors().editor_background;
 8539        editor_bg_color.blend(accent_color.opacity(0.6))
 8540    }
 8541
 8542    fn render_edit_prediction_cursor_popover(
 8543        &self,
 8544        min_width: Pixels,
 8545        max_width: Pixels,
 8546        cursor_point: Point,
 8547        style: &EditorStyle,
 8548        accept_keystroke: Option<&gpui::Keystroke>,
 8549        _window: &Window,
 8550        cx: &mut Context<Editor>,
 8551    ) -> Option<AnyElement> {
 8552        let provider = self.edit_prediction_provider.as_ref()?;
 8553
 8554        if provider.provider.needs_terms_acceptance(cx) {
 8555            return Some(
 8556                h_flex()
 8557                    .min_w(min_width)
 8558                    .flex_1()
 8559                    .px_2()
 8560                    .py_1()
 8561                    .gap_3()
 8562                    .elevation_2(cx)
 8563                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 8564                    .id("accept-terms")
 8565                    .cursor_pointer()
 8566                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 8567                    .on_click(cx.listener(|this, _event, window, cx| {
 8568                        cx.stop_propagation();
 8569                        this.report_editor_event("Edit Prediction Provider ToS Clicked", None, cx);
 8570                        window.dispatch_action(
 8571                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 8572                            cx,
 8573                        );
 8574                    }))
 8575                    .child(
 8576                        h_flex()
 8577                            .flex_1()
 8578                            .gap_2()
 8579                            .child(Icon::new(IconName::ZedPredict))
 8580                            .child(Label::new("Accept Terms of Service"))
 8581                            .child(div().w_full())
 8582                            .child(
 8583                                Icon::new(IconName::ArrowUpRight)
 8584                                    .color(Color::Muted)
 8585                                    .size(IconSize::Small),
 8586                            )
 8587                            .into_any_element(),
 8588                    )
 8589                    .into_any(),
 8590            );
 8591        }
 8592
 8593        let is_refreshing = provider.provider.is_refreshing(cx);
 8594
 8595        fn pending_completion_container() -> Div {
 8596            h_flex()
 8597                .h_full()
 8598                .flex_1()
 8599                .gap_2()
 8600                .child(Icon::new(IconName::ZedPredict))
 8601        }
 8602
 8603        let completion = match &self.active_inline_completion {
 8604            Some(prediction) => {
 8605                if !self.has_visible_completions_menu() {
 8606                    const RADIUS: Pixels = px(6.);
 8607                    const BORDER_WIDTH: Pixels = px(1.);
 8608
 8609                    return Some(
 8610                        h_flex()
 8611                            .elevation_2(cx)
 8612                            .border(BORDER_WIDTH)
 8613                            .border_color(cx.theme().colors().border)
 8614                            .when(accept_keystroke.is_none(), |el| {
 8615                                el.border_color(cx.theme().status().error)
 8616                            })
 8617                            .rounded(RADIUS)
 8618                            .rounded_tl(px(0.))
 8619                            .overflow_hidden()
 8620                            .child(div().px_1p5().child(match &prediction.completion {
 8621                                InlineCompletion::Move { target, snapshot } => {
 8622                                    use text::ToPoint as _;
 8623                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 8624                                    {
 8625                                        Icon::new(IconName::ZedPredictDown)
 8626                                    } else {
 8627                                        Icon::new(IconName::ZedPredictUp)
 8628                                    }
 8629                                }
 8630                                InlineCompletion::Edit { .. } => Icon::new(IconName::ZedPredict),
 8631                            }))
 8632                            .child(
 8633                                h_flex()
 8634                                    .gap_1()
 8635                                    .py_1()
 8636                                    .px_2()
 8637                                    .rounded_r(RADIUS - BORDER_WIDTH)
 8638                                    .border_l_1()
 8639                                    .border_color(cx.theme().colors().border)
 8640                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8641                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 8642                                        el.child(
 8643                                            Label::new("Hold")
 8644                                                .size(LabelSize::Small)
 8645                                                .when(accept_keystroke.is_none(), |el| {
 8646                                                    el.strikethrough()
 8647                                                })
 8648                                                .line_height_style(LineHeightStyle::UiLabel),
 8649                                        )
 8650                                    })
 8651                                    .id("edit_prediction_cursor_popover_keybind")
 8652                                    .when(accept_keystroke.is_none(), |el| {
 8653                                        let status_colors = cx.theme().status();
 8654
 8655                                        el.bg(status_colors.error_background)
 8656                                            .border_color(status_colors.error.opacity(0.6))
 8657                                            .child(Icon::new(IconName::Info).color(Color::Error))
 8658                                            .cursor_default()
 8659                                            .hoverable_tooltip(move |_window, cx| {
 8660                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 8661                                                    .into()
 8662                                            })
 8663                                    })
 8664                                    .when_some(
 8665                                        accept_keystroke.as_ref(),
 8666                                        |el, accept_keystroke| {
 8667                                            el.child(h_flex().children(ui::render_modifiers(
 8668                                                &accept_keystroke.modifiers,
 8669                                                PlatformStyle::platform(),
 8670                                                Some(Color::Default),
 8671                                                Some(IconSize::XSmall.rems().into()),
 8672                                                false,
 8673                                            )))
 8674                                        },
 8675                                    ),
 8676                            )
 8677                            .into_any(),
 8678                    );
 8679                }
 8680
 8681                self.render_edit_prediction_cursor_popover_preview(
 8682                    prediction,
 8683                    cursor_point,
 8684                    style,
 8685                    cx,
 8686                )?
 8687            }
 8688
 8689            None if is_refreshing => match &self.stale_inline_completion_in_menu {
 8690                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 8691                    stale_completion,
 8692                    cursor_point,
 8693                    style,
 8694                    cx,
 8695                )?,
 8696
 8697                None => {
 8698                    pending_completion_container().child(Label::new("...").size(LabelSize::Small))
 8699                }
 8700            },
 8701
 8702            None => pending_completion_container().child(Label::new("No Prediction")),
 8703        };
 8704
 8705        let completion = if is_refreshing {
 8706            completion
 8707                .with_animation(
 8708                    "loading-completion",
 8709                    Animation::new(Duration::from_secs(2))
 8710                        .repeat()
 8711                        .with_easing(pulsating_between(0.4, 0.8)),
 8712                    |label, delta| label.opacity(delta),
 8713                )
 8714                .into_any_element()
 8715        } else {
 8716            completion.into_any_element()
 8717        };
 8718
 8719        let has_completion = self.active_inline_completion.is_some();
 8720
 8721        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8722        Some(
 8723            h_flex()
 8724                .min_w(min_width)
 8725                .max_w(max_width)
 8726                .flex_1()
 8727                .elevation_2(cx)
 8728                .border_color(cx.theme().colors().border)
 8729                .child(
 8730                    div()
 8731                        .flex_1()
 8732                        .py_1()
 8733                        .px_2()
 8734                        .overflow_hidden()
 8735                        .child(completion),
 8736                )
 8737                .when_some(accept_keystroke, |el, accept_keystroke| {
 8738                    if !accept_keystroke.modifiers.modified() {
 8739                        return el;
 8740                    }
 8741
 8742                    el.child(
 8743                        h_flex()
 8744                            .h_full()
 8745                            .border_l_1()
 8746                            .rounded_r_lg()
 8747                            .border_color(cx.theme().colors().border)
 8748                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 8749                            .gap_1()
 8750                            .py_1()
 8751                            .px_2()
 8752                            .child(
 8753                                h_flex()
 8754                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8755                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 8756                                    .child(h_flex().children(ui::render_modifiers(
 8757                                        &accept_keystroke.modifiers,
 8758                                        PlatformStyle::platform(),
 8759                                        Some(if !has_completion {
 8760                                            Color::Muted
 8761                                        } else {
 8762                                            Color::Default
 8763                                        }),
 8764                                        None,
 8765                                        false,
 8766                                    ))),
 8767                            )
 8768                            .child(Label::new("Preview").into_any_element())
 8769                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 8770                    )
 8771                })
 8772                .into_any(),
 8773        )
 8774    }
 8775
 8776    fn render_edit_prediction_cursor_popover_preview(
 8777        &self,
 8778        completion: &InlineCompletionState,
 8779        cursor_point: Point,
 8780        style: &EditorStyle,
 8781        cx: &mut Context<Editor>,
 8782    ) -> Option<Div> {
 8783        use text::ToPoint as _;
 8784
 8785        fn render_relative_row_jump(
 8786            prefix: impl Into<String>,
 8787            current_row: u32,
 8788            target_row: u32,
 8789        ) -> Div {
 8790            let (row_diff, arrow) = if target_row < current_row {
 8791                (current_row - target_row, IconName::ArrowUp)
 8792            } else {
 8793                (target_row - current_row, IconName::ArrowDown)
 8794            };
 8795
 8796            h_flex()
 8797                .child(
 8798                    Label::new(format!("{}{}", prefix.into(), row_diff))
 8799                        .color(Color::Muted)
 8800                        .size(LabelSize::Small),
 8801                )
 8802                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 8803        }
 8804
 8805        match &completion.completion {
 8806            InlineCompletion::Move {
 8807                target, snapshot, ..
 8808            } => Some(
 8809                h_flex()
 8810                    .px_2()
 8811                    .gap_2()
 8812                    .flex_1()
 8813                    .child(
 8814                        if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 8815                            Icon::new(IconName::ZedPredictDown)
 8816                        } else {
 8817                            Icon::new(IconName::ZedPredictUp)
 8818                        },
 8819                    )
 8820                    .child(Label::new("Jump to Edit")),
 8821            ),
 8822
 8823            InlineCompletion::Edit {
 8824                edits,
 8825                edit_preview,
 8826                snapshot,
 8827                display_mode: _,
 8828            } => {
 8829                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 8830
 8831                let (highlighted_edits, has_more_lines) = crate::inline_completion_edit_text(
 8832                    &snapshot,
 8833                    &edits,
 8834                    edit_preview.as_ref()?,
 8835                    true,
 8836                    cx,
 8837                )
 8838                .first_line_preview();
 8839
 8840                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 8841                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 8842
 8843                let preview = h_flex()
 8844                    .gap_1()
 8845                    .min_w_16()
 8846                    .child(styled_text)
 8847                    .when(has_more_lines, |parent| parent.child(""));
 8848
 8849                let left = if first_edit_row != cursor_point.row {
 8850                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 8851                        .into_any_element()
 8852                } else {
 8853                    Icon::new(IconName::ZedPredict).into_any_element()
 8854                };
 8855
 8856                Some(
 8857                    h_flex()
 8858                        .h_full()
 8859                        .flex_1()
 8860                        .gap_2()
 8861                        .pr_1()
 8862                        .overflow_x_hidden()
 8863                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 8864                        .child(left)
 8865                        .child(preview),
 8866                )
 8867            }
 8868        }
 8869    }
 8870
 8871    pub fn render_context_menu(
 8872        &self,
 8873        style: &EditorStyle,
 8874        max_height_in_lines: u32,
 8875        window: &mut Window,
 8876        cx: &mut Context<Editor>,
 8877    ) -> Option<AnyElement> {
 8878        let menu = self.context_menu.borrow();
 8879        let menu = menu.as_ref()?;
 8880        if !menu.visible() {
 8881            return None;
 8882        };
 8883        Some(menu.render(style, max_height_in_lines, window, cx))
 8884    }
 8885
 8886    fn render_context_menu_aside(
 8887        &mut self,
 8888        max_size: Size<Pixels>,
 8889        window: &mut Window,
 8890        cx: &mut Context<Editor>,
 8891    ) -> Option<AnyElement> {
 8892        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 8893            if menu.visible() {
 8894                menu.render_aside(max_size, window, cx)
 8895            } else {
 8896                None
 8897            }
 8898        })
 8899    }
 8900
 8901    fn hide_context_menu(
 8902        &mut self,
 8903        window: &mut Window,
 8904        cx: &mut Context<Self>,
 8905    ) -> Option<CodeContextMenu> {
 8906        cx.notify();
 8907        self.completion_tasks.clear();
 8908        let context_menu = self.context_menu.borrow_mut().take();
 8909        self.stale_inline_completion_in_menu.take();
 8910        self.update_visible_inline_completion(window, cx);
 8911        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 8912            if let Some(completion_provider) = &self.completion_provider {
 8913                completion_provider.selection_changed(None, window, cx);
 8914            }
 8915        }
 8916        context_menu
 8917    }
 8918
 8919    fn show_snippet_choices(
 8920        &mut self,
 8921        choices: &Vec<String>,
 8922        selection: Range<Anchor>,
 8923        cx: &mut Context<Self>,
 8924    ) {
 8925        if selection.start.buffer_id.is_none() {
 8926            return;
 8927        }
 8928        let buffer_id = selection.start.buffer_id.unwrap();
 8929        let buffer = self.buffer().read(cx).buffer(buffer_id);
 8930        let id = post_inc(&mut self.next_completion_id);
 8931        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 8932
 8933        if let Some(buffer) = buffer {
 8934            *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 8935                CompletionsMenu::new_snippet_choices(
 8936                    id,
 8937                    true,
 8938                    choices,
 8939                    selection,
 8940                    buffer,
 8941                    snippet_sort_order,
 8942                ),
 8943            ));
 8944        }
 8945    }
 8946
 8947    pub fn insert_snippet(
 8948        &mut self,
 8949        insertion_ranges: &[Range<usize>],
 8950        snippet: Snippet,
 8951        window: &mut Window,
 8952        cx: &mut Context<Self>,
 8953    ) -> Result<()> {
 8954        struct Tabstop<T> {
 8955            is_end_tabstop: bool,
 8956            ranges: Vec<Range<T>>,
 8957            choices: Option<Vec<String>>,
 8958        }
 8959
 8960        let tabstops = self.buffer.update(cx, |buffer, cx| {
 8961            let snippet_text: Arc<str> = snippet.text.clone().into();
 8962            let edits = insertion_ranges
 8963                .iter()
 8964                .cloned()
 8965                .map(|range| (range, snippet_text.clone()));
 8966            let autoindent_mode = AutoindentMode::Block {
 8967                original_indent_columns: Vec::new(),
 8968            };
 8969            buffer.edit(edits, Some(autoindent_mode), cx);
 8970
 8971            let snapshot = &*buffer.read(cx);
 8972            let snippet = &snippet;
 8973            snippet
 8974                .tabstops
 8975                .iter()
 8976                .map(|tabstop| {
 8977                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 8978                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 8979                    });
 8980                    let mut tabstop_ranges = tabstop
 8981                        .ranges
 8982                        .iter()
 8983                        .flat_map(|tabstop_range| {
 8984                            let mut delta = 0_isize;
 8985                            insertion_ranges.iter().map(move |insertion_range| {
 8986                                let insertion_start = insertion_range.start as isize + delta;
 8987                                delta +=
 8988                                    snippet.text.len() as isize - insertion_range.len() as isize;
 8989
 8990                                let start = ((insertion_start + tabstop_range.start) as usize)
 8991                                    .min(snapshot.len());
 8992                                let end = ((insertion_start + tabstop_range.end) as usize)
 8993                                    .min(snapshot.len());
 8994                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 8995                            })
 8996                        })
 8997                        .collect::<Vec<_>>();
 8998                    // Sort in reverse order so that the first range is the newest created
 8999                    // selection. Completions will use it and autoscroll will prioritize it.
 9000                    tabstop_ranges.sort_unstable_by(|a, b| b.start.cmp(&a.start, snapshot));
 9001
 9002                    Tabstop {
 9003                        is_end_tabstop,
 9004                        ranges: tabstop_ranges,
 9005                        choices: tabstop.choices.clone(),
 9006                    }
 9007                })
 9008                .collect::<Vec<_>>()
 9009        });
 9010        if let Some(tabstop) = tabstops.first() {
 9011            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9012                s.select_ranges(tabstop.ranges.iter().cloned());
 9013            });
 9014
 9015            if let Some(choices) = &tabstop.choices {
 9016                if let Some(selection) = tabstop.ranges.first() {
 9017                    self.show_snippet_choices(choices, selection.clone(), cx)
 9018                }
 9019            }
 9020
 9021            // If we're already at the last tabstop and it's at the end of the snippet,
 9022            // we're done, we don't need to keep the state around.
 9023            if !tabstop.is_end_tabstop {
 9024                let choices = tabstops
 9025                    .iter()
 9026                    .map(|tabstop| tabstop.choices.clone())
 9027                    .collect();
 9028
 9029                let ranges = tabstops
 9030                    .into_iter()
 9031                    .map(|tabstop| tabstop.ranges)
 9032                    .collect::<Vec<_>>();
 9033
 9034                self.snippet_stack.push(SnippetState {
 9035                    active_index: 0,
 9036                    ranges,
 9037                    choices,
 9038                });
 9039            }
 9040
 9041            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9042            if self.autoclose_regions.is_empty() {
 9043                let snapshot = self.buffer.read(cx).snapshot(cx);
 9044                for selection in &mut self.selections.all::<Point>(cx) {
 9045                    let selection_head = selection.head();
 9046                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9047                        continue;
 9048                    };
 9049
 9050                    let mut bracket_pair = None;
 9051                    let next_chars = snapshot.chars_at(selection_head).collect::<String>();
 9052                    let prev_chars = snapshot
 9053                        .reversed_chars_at(selection_head)
 9054                        .collect::<String>();
 9055                    for (pair, enabled) in scope.brackets() {
 9056                        if enabled
 9057                            && pair.close
 9058                            && prev_chars.starts_with(pair.start.as_str())
 9059                            && next_chars.starts_with(pair.end.as_str())
 9060                        {
 9061                            bracket_pair = Some(pair.clone());
 9062                            break;
 9063                        }
 9064                    }
 9065                    if let Some(pair) = bracket_pair {
 9066                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9067                        let autoclose_enabled =
 9068                            self.use_autoclose && snapshot_settings.use_autoclose;
 9069                        if autoclose_enabled {
 9070                            let start = snapshot.anchor_after(selection_head);
 9071                            let end = snapshot.anchor_after(selection_head);
 9072                            self.autoclose_regions.push(AutocloseRegion {
 9073                                selection_id: selection.id,
 9074                                range: start..end,
 9075                                pair,
 9076                            });
 9077                        }
 9078                    }
 9079                }
 9080            }
 9081        }
 9082        Ok(())
 9083    }
 9084
 9085    pub fn move_to_next_snippet_tabstop(
 9086        &mut self,
 9087        window: &mut Window,
 9088        cx: &mut Context<Self>,
 9089    ) -> bool {
 9090        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9091    }
 9092
 9093    pub fn move_to_prev_snippet_tabstop(
 9094        &mut self,
 9095        window: &mut Window,
 9096        cx: &mut Context<Self>,
 9097    ) -> bool {
 9098        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9099    }
 9100
 9101    pub fn move_to_snippet_tabstop(
 9102        &mut self,
 9103        bias: Bias,
 9104        window: &mut Window,
 9105        cx: &mut Context<Self>,
 9106    ) -> bool {
 9107        if let Some(mut snippet) = self.snippet_stack.pop() {
 9108            match bias {
 9109                Bias::Left => {
 9110                    if snippet.active_index > 0 {
 9111                        snippet.active_index -= 1;
 9112                    } else {
 9113                        self.snippet_stack.push(snippet);
 9114                        return false;
 9115                    }
 9116                }
 9117                Bias::Right => {
 9118                    if snippet.active_index + 1 < snippet.ranges.len() {
 9119                        snippet.active_index += 1;
 9120                    } else {
 9121                        self.snippet_stack.push(snippet);
 9122                        return false;
 9123                    }
 9124                }
 9125            }
 9126            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9127                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9128                    s.select_ranges(current_ranges.iter().cloned())
 9129                });
 9130
 9131                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9132                    if let Some(selection) = current_ranges.first() {
 9133                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9134                    }
 9135                }
 9136
 9137                // If snippet state is not at the last tabstop, push it back on the stack
 9138                if snippet.active_index + 1 < snippet.ranges.len() {
 9139                    self.snippet_stack.push(snippet);
 9140                }
 9141                return true;
 9142            }
 9143        }
 9144
 9145        false
 9146    }
 9147
 9148    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9149        self.transact(window, cx, |this, window, cx| {
 9150            this.select_all(&SelectAll, window, cx);
 9151            this.insert("", window, cx);
 9152        });
 9153    }
 9154
 9155    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9156        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9157        self.transact(window, cx, |this, window, cx| {
 9158            this.select_autoclose_pair(window, cx);
 9159            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9160            if !this.linked_edit_ranges.is_empty() {
 9161                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9162                let snapshot = this.buffer.read(cx).snapshot(cx);
 9163
 9164                for selection in selections.iter() {
 9165                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9166                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9167                    if selection_start.buffer_id != selection_end.buffer_id {
 9168                        continue;
 9169                    }
 9170                    if let Some(ranges) =
 9171                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9172                    {
 9173                        for (buffer, entries) in ranges {
 9174                            linked_ranges.entry(buffer).or_default().extend(entries);
 9175                        }
 9176                    }
 9177                }
 9178            }
 9179
 9180            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9181            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9182            for selection in &mut selections {
 9183                if selection.is_empty() {
 9184                    let old_head = selection.head();
 9185                    let mut new_head =
 9186                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9187                            .to_point(&display_map);
 9188                    if let Some((buffer, line_buffer_range)) = display_map
 9189                        .buffer_snapshot
 9190                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9191                    {
 9192                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9193                        let indent_len = match indent_size.kind {
 9194                            IndentKind::Space => {
 9195                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9196                            }
 9197                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9198                        };
 9199                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9200                            let indent_len = indent_len.get();
 9201                            new_head = cmp::min(
 9202                                new_head,
 9203                                MultiBufferPoint::new(
 9204                                    old_head.row,
 9205                                    ((old_head.column - 1) / indent_len) * indent_len,
 9206                                ),
 9207                            );
 9208                        }
 9209                    }
 9210
 9211                    selection.set_head(new_head, SelectionGoal::None);
 9212                }
 9213            }
 9214
 9215            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9216                s.select(selections)
 9217            });
 9218            this.insert("", window, cx);
 9219            let empty_str: Arc<str> = Arc::from("");
 9220            for (buffer, edits) in linked_ranges {
 9221                let snapshot = buffer.read(cx).snapshot();
 9222                use text::ToPoint as TP;
 9223
 9224                let edits = edits
 9225                    .into_iter()
 9226                    .map(|range| {
 9227                        let end_point = TP::to_point(&range.end, &snapshot);
 9228                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9229
 9230                        if end_point == start_point {
 9231                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9232                                .saturating_sub(1);
 9233                            start_point =
 9234                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9235                        };
 9236
 9237                        (start_point..end_point, empty_str.clone())
 9238                    })
 9239                    .sorted_by_key(|(range, _)| range.start)
 9240                    .collect::<Vec<_>>();
 9241                buffer.update(cx, |this, cx| {
 9242                    this.edit(edits, None, cx);
 9243                })
 9244            }
 9245            this.refresh_inline_completion(true, false, window, cx);
 9246            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9247        });
 9248    }
 9249
 9250    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9251        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9252        self.transact(window, cx, |this, window, cx| {
 9253            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9254                s.move_with(|map, selection| {
 9255                    if selection.is_empty() {
 9256                        let cursor = movement::right(map, selection.head());
 9257                        selection.end = cursor;
 9258                        selection.reversed = true;
 9259                        selection.goal = SelectionGoal::None;
 9260                    }
 9261                })
 9262            });
 9263            this.insert("", window, cx);
 9264            this.refresh_inline_completion(true, false, window, cx);
 9265        });
 9266    }
 9267
 9268    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9269        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9270        if self.move_to_prev_snippet_tabstop(window, cx) {
 9271            return;
 9272        }
 9273        self.outdent(&Outdent, window, cx);
 9274    }
 9275
 9276    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9277        if self.move_to_next_snippet_tabstop(window, cx) {
 9278            self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9279            return;
 9280        }
 9281        if self.read_only(cx) {
 9282            return;
 9283        }
 9284        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9285        let mut selections = self.selections.all_adjusted(cx);
 9286        let buffer = self.buffer.read(cx);
 9287        let snapshot = buffer.snapshot(cx);
 9288        let rows_iter = selections.iter().map(|s| s.head().row);
 9289        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9290
 9291        let has_some_cursor_in_whitespace = selections
 9292            .iter()
 9293            .filter(|selection| selection.is_empty())
 9294            .any(|selection| {
 9295                let cursor = selection.head();
 9296                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9297                cursor.column < current_indent.len
 9298            });
 9299
 9300        let mut edits = Vec::new();
 9301        let mut prev_edited_row = 0;
 9302        let mut row_delta = 0;
 9303        for selection in &mut selections {
 9304            if selection.start.row != prev_edited_row {
 9305                row_delta = 0;
 9306            }
 9307            prev_edited_row = selection.end.row;
 9308
 9309            // If the selection is non-empty, then increase the indentation of the selected lines.
 9310            if !selection.is_empty() {
 9311                row_delta =
 9312                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9313                continue;
 9314            }
 9315
 9316            let cursor = selection.head();
 9317            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9318            if let Some(suggested_indent) =
 9319                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9320            {
 9321                // Don't do anything if already at suggested indent
 9322                // and there is any other cursor which is not
 9323                if has_some_cursor_in_whitespace
 9324                    && cursor.column == current_indent.len
 9325                    && current_indent.len == suggested_indent.len
 9326                {
 9327                    continue;
 9328                }
 9329
 9330                // Adjust line and move cursor to suggested indent
 9331                // if cursor is not at suggested indent
 9332                if cursor.column < suggested_indent.len
 9333                    && cursor.column <= current_indent.len
 9334                    && current_indent.len <= suggested_indent.len
 9335                {
 9336                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9337                    selection.end = selection.start;
 9338                    if row_delta == 0 {
 9339                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9340                            cursor.row,
 9341                            current_indent,
 9342                            suggested_indent,
 9343                        ));
 9344                        row_delta = suggested_indent.len - current_indent.len;
 9345                    }
 9346                    continue;
 9347                }
 9348
 9349                // If current indent is more than suggested indent
 9350                // only move cursor to current indent and skip indent
 9351                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9352                    selection.start = Point::new(cursor.row, current_indent.len);
 9353                    selection.end = selection.start;
 9354                    continue;
 9355                }
 9356            }
 9357
 9358            // Otherwise, insert a hard or soft tab.
 9359            let settings = buffer.language_settings_at(cursor, cx);
 9360            let tab_size = if settings.hard_tabs {
 9361                IndentSize::tab()
 9362            } else {
 9363                let tab_size = settings.tab_size.get();
 9364                let indent_remainder = snapshot
 9365                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9366                    .flat_map(str::chars)
 9367                    .fold(row_delta % tab_size, |counter: u32, c| {
 9368                        if c == '\t' {
 9369                            0
 9370                        } else {
 9371                            (counter + 1) % tab_size
 9372                        }
 9373                    });
 9374
 9375                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9376                IndentSize::spaces(chars_to_next_tab_stop)
 9377            };
 9378            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9379            selection.end = selection.start;
 9380            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9381            row_delta += tab_size.len;
 9382        }
 9383
 9384        self.transact(window, cx, |this, window, cx| {
 9385            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9386            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9387                s.select(selections)
 9388            });
 9389            this.refresh_inline_completion(true, false, window, cx);
 9390        });
 9391    }
 9392
 9393    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
 9394        if self.read_only(cx) {
 9395            return;
 9396        }
 9397        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9398        let mut selections = self.selections.all::<Point>(cx);
 9399        let mut prev_edited_row = 0;
 9400        let mut row_delta = 0;
 9401        let mut edits = Vec::new();
 9402        let buffer = self.buffer.read(cx);
 9403        let snapshot = buffer.snapshot(cx);
 9404        for selection in &mut selections {
 9405            if selection.start.row != prev_edited_row {
 9406                row_delta = 0;
 9407            }
 9408            prev_edited_row = selection.end.row;
 9409
 9410            row_delta =
 9411                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9412        }
 9413
 9414        self.transact(window, cx, |this, window, cx| {
 9415            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
 9416            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9417                s.select(selections)
 9418            });
 9419        });
 9420    }
 9421
 9422    fn indent_selection(
 9423        buffer: &MultiBuffer,
 9424        snapshot: &MultiBufferSnapshot,
 9425        selection: &mut Selection<Point>,
 9426        edits: &mut Vec<(Range<Point>, String)>,
 9427        delta_for_start_row: u32,
 9428        cx: &App,
 9429    ) -> u32 {
 9430        let settings = buffer.language_settings_at(selection.start, cx);
 9431        let tab_size = settings.tab_size.get();
 9432        let indent_kind = if settings.hard_tabs {
 9433            IndentKind::Tab
 9434        } else {
 9435            IndentKind::Space
 9436        };
 9437        let mut start_row = selection.start.row;
 9438        let mut end_row = selection.end.row + 1;
 9439
 9440        // If a selection ends at the beginning of a line, don't indent
 9441        // that last line.
 9442        if selection.end.column == 0 && selection.end.row > selection.start.row {
 9443            end_row -= 1;
 9444        }
 9445
 9446        // Avoid re-indenting a row that has already been indented by a
 9447        // previous selection, but still update this selection's column
 9448        // to reflect that indentation.
 9449        if delta_for_start_row > 0 {
 9450            start_row += 1;
 9451            selection.start.column += delta_for_start_row;
 9452            if selection.end.row == selection.start.row {
 9453                selection.end.column += delta_for_start_row;
 9454            }
 9455        }
 9456
 9457        let mut delta_for_end_row = 0;
 9458        let has_multiple_rows = start_row + 1 != end_row;
 9459        for row in start_row..end_row {
 9460            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
 9461            let indent_delta = match (current_indent.kind, indent_kind) {
 9462                (IndentKind::Space, IndentKind::Space) => {
 9463                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
 9464                    IndentSize::spaces(columns_to_next_tab_stop)
 9465                }
 9466                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
 9467                (_, IndentKind::Tab) => IndentSize::tab(),
 9468            };
 9469
 9470            let start = if has_multiple_rows || current_indent.len < selection.start.column {
 9471                0
 9472            } else {
 9473                selection.start.column
 9474            };
 9475            let row_start = Point::new(row, start);
 9476            edits.push((
 9477                row_start..row_start,
 9478                indent_delta.chars().collect::<String>(),
 9479            ));
 9480
 9481            // Update this selection's endpoints to reflect the indentation.
 9482            if row == selection.start.row {
 9483                selection.start.column += indent_delta.len;
 9484            }
 9485            if row == selection.end.row {
 9486                selection.end.column += indent_delta.len;
 9487                delta_for_end_row = indent_delta.len;
 9488            }
 9489        }
 9490
 9491        if selection.start.row == selection.end.row {
 9492            delta_for_start_row + delta_for_end_row
 9493        } else {
 9494            delta_for_end_row
 9495        }
 9496    }
 9497
 9498    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
 9499        if self.read_only(cx) {
 9500            return;
 9501        }
 9502        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9503        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9504        let selections = self.selections.all::<Point>(cx);
 9505        let mut deletion_ranges = Vec::new();
 9506        let mut last_outdent = None;
 9507        {
 9508            let buffer = self.buffer.read(cx);
 9509            let snapshot = buffer.snapshot(cx);
 9510            for selection in &selections {
 9511                let settings = buffer.language_settings_at(selection.start, cx);
 9512                let tab_size = settings.tab_size.get();
 9513                let mut rows = selection.spanned_rows(false, &display_map);
 9514
 9515                // Avoid re-outdenting a row that has already been outdented by a
 9516                // previous selection.
 9517                if let Some(last_row) = last_outdent {
 9518                    if last_row == rows.start {
 9519                        rows.start = rows.start.next_row();
 9520                    }
 9521                }
 9522                let has_multiple_rows = rows.len() > 1;
 9523                for row in rows.iter_rows() {
 9524                    let indent_size = snapshot.indent_size_for_line(row);
 9525                    if indent_size.len > 0 {
 9526                        let deletion_len = match indent_size.kind {
 9527                            IndentKind::Space => {
 9528                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
 9529                                if columns_to_prev_tab_stop == 0 {
 9530                                    tab_size
 9531                                } else {
 9532                                    columns_to_prev_tab_stop
 9533                                }
 9534                            }
 9535                            IndentKind::Tab => 1,
 9536                        };
 9537                        let start = if has_multiple_rows
 9538                            || deletion_len > selection.start.column
 9539                            || indent_size.len < selection.start.column
 9540                        {
 9541                            0
 9542                        } else {
 9543                            selection.start.column - deletion_len
 9544                        };
 9545                        deletion_ranges.push(
 9546                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
 9547                        );
 9548                        last_outdent = Some(row);
 9549                    }
 9550                }
 9551            }
 9552        }
 9553
 9554        self.transact(window, cx, |this, window, cx| {
 9555            this.buffer.update(cx, |buffer, cx| {
 9556                let empty_str: Arc<str> = Arc::default();
 9557                buffer.edit(
 9558                    deletion_ranges
 9559                        .into_iter()
 9560                        .map(|range| (range, empty_str.clone())),
 9561                    None,
 9562                    cx,
 9563                );
 9564            });
 9565            let selections = this.selections.all::<usize>(cx);
 9566            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9567                s.select(selections)
 9568            });
 9569        });
 9570    }
 9571
 9572    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
 9573        if self.read_only(cx) {
 9574            return;
 9575        }
 9576        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9577        let selections = self
 9578            .selections
 9579            .all::<usize>(cx)
 9580            .into_iter()
 9581            .map(|s| s.range());
 9582
 9583        self.transact(window, cx, |this, window, cx| {
 9584            this.buffer.update(cx, |buffer, cx| {
 9585                buffer.autoindent_ranges(selections, cx);
 9586            });
 9587            let selections = this.selections.all::<usize>(cx);
 9588            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9589                s.select(selections)
 9590            });
 9591        });
 9592    }
 9593
 9594    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
 9595        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9596        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 9597        let selections = self.selections.all::<Point>(cx);
 9598
 9599        let mut new_cursors = Vec::new();
 9600        let mut edit_ranges = Vec::new();
 9601        let mut selections = selections.iter().peekable();
 9602        while let Some(selection) = selections.next() {
 9603            let mut rows = selection.spanned_rows(false, &display_map);
 9604            let goal_display_column = selection.head().to_display_point(&display_map).column();
 9605
 9606            // Accumulate contiguous regions of rows that we want to delete.
 9607            while let Some(next_selection) = selections.peek() {
 9608                let next_rows = next_selection.spanned_rows(false, &display_map);
 9609                if next_rows.start <= rows.end {
 9610                    rows.end = next_rows.end;
 9611                    selections.next().unwrap();
 9612                } else {
 9613                    break;
 9614                }
 9615            }
 9616
 9617            let buffer = &display_map.buffer_snapshot;
 9618            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
 9619            let edit_end;
 9620            let cursor_buffer_row;
 9621            if buffer.max_point().row >= rows.end.0 {
 9622                // If there's a line after the range, delete the \n from the end of the row range
 9623                // and position the cursor on the next line.
 9624                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
 9625                cursor_buffer_row = rows.end;
 9626            } else {
 9627                // If there isn't a line after the range, delete the \n from the line before the
 9628                // start of the row range and position the cursor there.
 9629                edit_start = edit_start.saturating_sub(1);
 9630                edit_end = buffer.len();
 9631                cursor_buffer_row = rows.start.previous_row();
 9632            }
 9633
 9634            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
 9635            *cursor.column_mut() =
 9636                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
 9637
 9638            new_cursors.push((
 9639                selection.id,
 9640                buffer.anchor_after(cursor.to_point(&display_map)),
 9641            ));
 9642            edit_ranges.push(edit_start..edit_end);
 9643        }
 9644
 9645        self.transact(window, cx, |this, window, cx| {
 9646            let buffer = this.buffer.update(cx, |buffer, cx| {
 9647                let empty_str: Arc<str> = Arc::default();
 9648                buffer.edit(
 9649                    edit_ranges
 9650                        .into_iter()
 9651                        .map(|range| (range, empty_str.clone())),
 9652                    None,
 9653                    cx,
 9654                );
 9655                buffer.snapshot(cx)
 9656            });
 9657            let new_selections = new_cursors
 9658                .into_iter()
 9659                .map(|(id, cursor)| {
 9660                    let cursor = cursor.to_point(&buffer);
 9661                    Selection {
 9662                        id,
 9663                        start: cursor,
 9664                        end: cursor,
 9665                        reversed: false,
 9666                        goal: SelectionGoal::None,
 9667                    }
 9668                })
 9669                .collect();
 9670
 9671            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9672                s.select(new_selections);
 9673            });
 9674        });
 9675    }
 9676
 9677    pub fn join_lines_impl(
 9678        &mut self,
 9679        insert_whitespace: bool,
 9680        window: &mut Window,
 9681        cx: &mut Context<Self>,
 9682    ) {
 9683        if self.read_only(cx) {
 9684            return;
 9685        }
 9686        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
 9687        for selection in self.selections.all::<Point>(cx) {
 9688            let start = MultiBufferRow(selection.start.row);
 9689            // Treat single line selections as if they include the next line. Otherwise this action
 9690            // would do nothing for single line selections individual cursors.
 9691            let end = if selection.start.row == selection.end.row {
 9692                MultiBufferRow(selection.start.row + 1)
 9693            } else {
 9694                MultiBufferRow(selection.end.row)
 9695            };
 9696
 9697            if let Some(last_row_range) = row_ranges.last_mut() {
 9698                if start <= last_row_range.end {
 9699                    last_row_range.end = end;
 9700                    continue;
 9701                }
 9702            }
 9703            row_ranges.push(start..end);
 9704        }
 9705
 9706        let snapshot = self.buffer.read(cx).snapshot(cx);
 9707        let mut cursor_positions = Vec::new();
 9708        for row_range in &row_ranges {
 9709            let anchor = snapshot.anchor_before(Point::new(
 9710                row_range.end.previous_row().0,
 9711                snapshot.line_len(row_range.end.previous_row()),
 9712            ));
 9713            cursor_positions.push(anchor..anchor);
 9714        }
 9715
 9716        self.transact(window, cx, |this, window, cx| {
 9717            for row_range in row_ranges.into_iter().rev() {
 9718                for row in row_range.iter_rows().rev() {
 9719                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
 9720                    let next_line_row = row.next_row();
 9721                    let indent = snapshot.indent_size_for_line(next_line_row);
 9722                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
 9723
 9724                    let replace =
 9725                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
 9726                            " "
 9727                        } else {
 9728                            ""
 9729                        };
 9730
 9731                    this.buffer.update(cx, |buffer, cx| {
 9732                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
 9733                    });
 9734                }
 9735            }
 9736
 9737            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
 9738                s.select_anchor_ranges(cursor_positions)
 9739            });
 9740        });
 9741    }
 9742
 9743    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
 9744        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9745        self.join_lines_impl(true, window, cx);
 9746    }
 9747
 9748    pub fn sort_lines_case_sensitive(
 9749        &mut self,
 9750        _: &SortLinesCaseSensitive,
 9751        window: &mut Window,
 9752        cx: &mut Context<Self>,
 9753    ) {
 9754        self.manipulate_lines(window, cx, |lines| lines.sort())
 9755    }
 9756
 9757    pub fn sort_lines_case_insensitive(
 9758        &mut self,
 9759        _: &SortLinesCaseInsensitive,
 9760        window: &mut Window,
 9761        cx: &mut Context<Self>,
 9762    ) {
 9763        self.manipulate_lines(window, cx, |lines| {
 9764            lines.sort_by_key(|line| line.to_lowercase())
 9765        })
 9766    }
 9767
 9768    pub fn unique_lines_case_insensitive(
 9769        &mut self,
 9770        _: &UniqueLinesCaseInsensitive,
 9771        window: &mut Window,
 9772        cx: &mut Context<Self>,
 9773    ) {
 9774        self.manipulate_lines(window, cx, |lines| {
 9775            let mut seen = HashSet::default();
 9776            lines.retain(|line| seen.insert(line.to_lowercase()));
 9777        })
 9778    }
 9779
 9780    pub fn unique_lines_case_sensitive(
 9781        &mut self,
 9782        _: &UniqueLinesCaseSensitive,
 9783        window: &mut Window,
 9784        cx: &mut Context<Self>,
 9785    ) {
 9786        self.manipulate_lines(window, cx, |lines| {
 9787            let mut seen = HashSet::default();
 9788            lines.retain(|line| seen.insert(*line));
 9789        })
 9790    }
 9791
 9792    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
 9793        let Some(project) = self.project.clone() else {
 9794            return;
 9795        };
 9796        self.reload(project, window, cx)
 9797            .detach_and_notify_err(window, cx);
 9798    }
 9799
 9800    pub fn restore_file(
 9801        &mut self,
 9802        _: &::git::RestoreFile,
 9803        window: &mut Window,
 9804        cx: &mut Context<Self>,
 9805    ) {
 9806        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9807        let mut buffer_ids = HashSet::default();
 9808        let snapshot = self.buffer().read(cx).snapshot(cx);
 9809        for selection in self.selections.all::<usize>(cx) {
 9810            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
 9811        }
 9812
 9813        let buffer = self.buffer().read(cx);
 9814        let ranges = buffer_ids
 9815            .into_iter()
 9816            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
 9817            .collect::<Vec<_>>();
 9818
 9819        self.restore_hunks_in_ranges(ranges, window, cx);
 9820    }
 9821
 9822    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
 9823        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
 9824        let selections = self
 9825            .selections
 9826            .all(cx)
 9827            .into_iter()
 9828            .map(|s| s.range())
 9829            .collect();
 9830        self.restore_hunks_in_ranges(selections, window, cx);
 9831    }
 9832
 9833    pub fn restore_hunks_in_ranges(
 9834        &mut self,
 9835        ranges: Vec<Range<Point>>,
 9836        window: &mut Window,
 9837        cx: &mut Context<Editor>,
 9838    ) {
 9839        let mut revert_changes = HashMap::default();
 9840        let chunk_by = self
 9841            .snapshot(window, cx)
 9842            .hunks_for_ranges(ranges)
 9843            .into_iter()
 9844            .chunk_by(|hunk| hunk.buffer_id);
 9845        for (buffer_id, hunks) in &chunk_by {
 9846            let hunks = hunks.collect::<Vec<_>>();
 9847            for hunk in &hunks {
 9848                self.prepare_restore_change(&mut revert_changes, hunk, cx);
 9849            }
 9850            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
 9851        }
 9852        drop(chunk_by);
 9853        if !revert_changes.is_empty() {
 9854            self.transact(window, cx, |editor, window, cx| {
 9855                editor.restore(revert_changes, window, cx);
 9856            });
 9857        }
 9858    }
 9859
 9860    pub fn open_active_item_in_terminal(
 9861        &mut self,
 9862        _: &OpenInTerminal,
 9863        window: &mut Window,
 9864        cx: &mut Context<Self>,
 9865    ) {
 9866        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
 9867            let project_path = buffer.read(cx).project_path(cx)?;
 9868            let project = self.project.as_ref()?.read(cx);
 9869            let entry = project.entry_for_path(&project_path, cx)?;
 9870            let parent = match &entry.canonical_path {
 9871                Some(canonical_path) => canonical_path.to_path_buf(),
 9872                None => project.absolute_path(&project_path, cx)?,
 9873            }
 9874            .parent()?
 9875            .to_path_buf();
 9876            Some(parent)
 9877        }) {
 9878            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
 9879        }
 9880    }
 9881
 9882    fn set_breakpoint_context_menu(
 9883        &mut self,
 9884        display_row: DisplayRow,
 9885        position: Option<Anchor>,
 9886        clicked_point: gpui::Point<Pixels>,
 9887        window: &mut Window,
 9888        cx: &mut Context<Self>,
 9889    ) {
 9890        if !cx.has_flag::<DebuggerFeatureFlag>() {
 9891            return;
 9892        }
 9893        let source = self
 9894            .buffer
 9895            .read(cx)
 9896            .snapshot(cx)
 9897            .anchor_before(Point::new(display_row.0, 0u32));
 9898
 9899        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
 9900
 9901        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
 9902            self,
 9903            source,
 9904            clicked_point,
 9905            context_menu,
 9906            window,
 9907            cx,
 9908        );
 9909    }
 9910
 9911    fn add_edit_breakpoint_block(
 9912        &mut self,
 9913        anchor: Anchor,
 9914        breakpoint: &Breakpoint,
 9915        edit_action: BreakpointPromptEditAction,
 9916        window: &mut Window,
 9917        cx: &mut Context<Self>,
 9918    ) {
 9919        let weak_editor = cx.weak_entity();
 9920        let bp_prompt = cx.new(|cx| {
 9921            BreakpointPromptEditor::new(
 9922                weak_editor,
 9923                anchor,
 9924                breakpoint.clone(),
 9925                edit_action,
 9926                window,
 9927                cx,
 9928            )
 9929        });
 9930
 9931        let height = bp_prompt.update(cx, |this, cx| {
 9932            this.prompt
 9933                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
 9934        });
 9935        let cloned_prompt = bp_prompt.clone();
 9936        let blocks = vec![BlockProperties {
 9937            style: BlockStyle::Sticky,
 9938            placement: BlockPlacement::Above(anchor),
 9939            height: Some(height),
 9940            render: Arc::new(move |cx| {
 9941                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
 9942                cloned_prompt.clone().into_any_element()
 9943            }),
 9944            priority: 0,
 9945            render_in_minimap: true,
 9946        }];
 9947
 9948        let focus_handle = bp_prompt.focus_handle(cx);
 9949        window.focus(&focus_handle);
 9950
 9951        let block_ids = self.insert_blocks(blocks, None, cx);
 9952        bp_prompt.update(cx, |prompt, _| {
 9953            prompt.add_block_ids(block_ids);
 9954        });
 9955    }
 9956
 9957    pub(crate) fn breakpoint_at_row(
 9958        &self,
 9959        row: u32,
 9960        window: &mut Window,
 9961        cx: &mut Context<Self>,
 9962    ) -> Option<(Anchor, Breakpoint)> {
 9963        let snapshot = self.snapshot(window, cx);
 9964        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
 9965
 9966        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
 9967    }
 9968
 9969    pub(crate) fn breakpoint_at_anchor(
 9970        &self,
 9971        breakpoint_position: Anchor,
 9972        snapshot: &EditorSnapshot,
 9973        cx: &mut Context<Self>,
 9974    ) -> Option<(Anchor, Breakpoint)> {
 9975        let project = self.project.clone()?;
 9976
 9977        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
 9978            snapshot
 9979                .buffer_snapshot
 9980                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
 9981        })?;
 9982
 9983        let enclosing_excerpt = breakpoint_position.excerpt_id;
 9984        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
 9985        let buffer_snapshot = buffer.read(cx).snapshot();
 9986
 9987        let row = buffer_snapshot
 9988            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
 9989            .row;
 9990
 9991        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
 9992        let anchor_end = snapshot
 9993            .buffer_snapshot
 9994            .anchor_after(Point::new(row, line_len));
 9995
 9996        let bp = self
 9997            .breakpoint_store
 9998            .as_ref()?
 9999            .read_with(cx, |breakpoint_store, cx| {
10000                breakpoint_store
10001                    .breakpoints(
10002                        &buffer,
10003                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10004                        &buffer_snapshot,
10005                        cx,
10006                    )
10007                    .next()
10008                    .and_then(|(bp, _)| {
10009                        let breakpoint_row = buffer_snapshot
10010                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10011                            .row;
10012
10013                        if breakpoint_row == row {
10014                            snapshot
10015                                .buffer_snapshot
10016                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10017                                .map(|position| (position, bp.bp.clone()))
10018                        } else {
10019                            None
10020                        }
10021                    })
10022            });
10023        bp
10024    }
10025
10026    pub fn edit_log_breakpoint(
10027        &mut self,
10028        _: &EditLogBreakpoint,
10029        window: &mut Window,
10030        cx: &mut Context<Self>,
10031    ) {
10032        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10033            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10034                message: None,
10035                state: BreakpointState::Enabled,
10036                condition: None,
10037                hit_condition: None,
10038            });
10039
10040            self.add_edit_breakpoint_block(
10041                anchor,
10042                &breakpoint,
10043                BreakpointPromptEditAction::Log,
10044                window,
10045                cx,
10046            );
10047        }
10048    }
10049
10050    fn breakpoints_at_cursors(
10051        &self,
10052        window: &mut Window,
10053        cx: &mut Context<Self>,
10054    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10055        let snapshot = self.snapshot(window, cx);
10056        let cursors = self
10057            .selections
10058            .disjoint_anchors()
10059            .into_iter()
10060            .map(|selection| {
10061                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10062
10063                let breakpoint_position = self
10064                    .breakpoint_at_row(cursor_position.row, window, cx)
10065                    .map(|bp| bp.0)
10066                    .unwrap_or_else(|| {
10067                        snapshot
10068                            .display_snapshot
10069                            .buffer_snapshot
10070                            .anchor_after(Point::new(cursor_position.row, 0))
10071                    });
10072
10073                let breakpoint = self
10074                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10075                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10076
10077                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10078            })
10079            // 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.
10080            .collect::<HashMap<Anchor, _>>();
10081
10082        cursors.into_iter().collect()
10083    }
10084
10085    pub fn enable_breakpoint(
10086        &mut self,
10087        _: &crate::actions::EnableBreakpoint,
10088        window: &mut Window,
10089        cx: &mut Context<Self>,
10090    ) {
10091        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10092            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10093                continue;
10094            };
10095            self.edit_breakpoint_at_anchor(
10096                anchor,
10097                breakpoint,
10098                BreakpointEditAction::InvertState,
10099                cx,
10100            );
10101        }
10102    }
10103
10104    pub fn disable_breakpoint(
10105        &mut self,
10106        _: &crate::actions::DisableBreakpoint,
10107        window: &mut Window,
10108        cx: &mut Context<Self>,
10109    ) {
10110        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10111            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10112                continue;
10113            };
10114            self.edit_breakpoint_at_anchor(
10115                anchor,
10116                breakpoint,
10117                BreakpointEditAction::InvertState,
10118                cx,
10119            );
10120        }
10121    }
10122
10123    pub fn toggle_breakpoint(
10124        &mut self,
10125        _: &crate::actions::ToggleBreakpoint,
10126        window: &mut Window,
10127        cx: &mut Context<Self>,
10128    ) {
10129        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10130            if let Some(breakpoint) = breakpoint {
10131                self.edit_breakpoint_at_anchor(
10132                    anchor,
10133                    breakpoint,
10134                    BreakpointEditAction::Toggle,
10135                    cx,
10136                );
10137            } else {
10138                self.edit_breakpoint_at_anchor(
10139                    anchor,
10140                    Breakpoint::new_standard(),
10141                    BreakpointEditAction::Toggle,
10142                    cx,
10143                );
10144            }
10145        }
10146    }
10147
10148    pub fn edit_breakpoint_at_anchor(
10149        &mut self,
10150        breakpoint_position: Anchor,
10151        breakpoint: Breakpoint,
10152        edit_action: BreakpointEditAction,
10153        cx: &mut Context<Self>,
10154    ) {
10155        let Some(breakpoint_store) = &self.breakpoint_store else {
10156            return;
10157        };
10158
10159        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10160            if breakpoint_position == Anchor::min() {
10161                self.buffer()
10162                    .read(cx)
10163                    .excerpt_buffer_ids()
10164                    .into_iter()
10165                    .next()
10166            } else {
10167                None
10168            }
10169        }) else {
10170            return;
10171        };
10172
10173        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10174            return;
10175        };
10176
10177        breakpoint_store.update(cx, |breakpoint_store, cx| {
10178            breakpoint_store.toggle_breakpoint(
10179                buffer,
10180                BreakpointWithPosition {
10181                    position: breakpoint_position.text_anchor,
10182                    bp: breakpoint,
10183                },
10184                edit_action,
10185                cx,
10186            );
10187        });
10188
10189        cx.notify();
10190    }
10191
10192    #[cfg(any(test, feature = "test-support"))]
10193    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10194        self.breakpoint_store.clone()
10195    }
10196
10197    pub fn prepare_restore_change(
10198        &self,
10199        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10200        hunk: &MultiBufferDiffHunk,
10201        cx: &mut App,
10202    ) -> Option<()> {
10203        if hunk.is_created_file() {
10204            return None;
10205        }
10206        let buffer = self.buffer.read(cx);
10207        let diff = buffer.diff_for(hunk.buffer_id)?;
10208        let buffer = buffer.buffer(hunk.buffer_id)?;
10209        let buffer = buffer.read(cx);
10210        let original_text = diff
10211            .read(cx)
10212            .base_text()
10213            .as_rope()
10214            .slice(hunk.diff_base_byte_range.clone());
10215        let buffer_snapshot = buffer.snapshot();
10216        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10217        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10218            probe
10219                .0
10220                .start
10221                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10222                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10223        }) {
10224            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10225            Some(())
10226        } else {
10227            None
10228        }
10229    }
10230
10231    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10232        self.manipulate_lines(window, cx, |lines| lines.reverse())
10233    }
10234
10235    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10236        self.manipulate_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10237    }
10238
10239    fn manipulate_lines<Fn>(
10240        &mut self,
10241        window: &mut Window,
10242        cx: &mut Context<Self>,
10243        mut callback: Fn,
10244    ) where
10245        Fn: FnMut(&mut Vec<&str>),
10246    {
10247        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10248
10249        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10250        let buffer = self.buffer.read(cx).snapshot(cx);
10251
10252        let mut edits = Vec::new();
10253
10254        let selections = self.selections.all::<Point>(cx);
10255        let mut selections = selections.iter().peekable();
10256        let mut contiguous_row_selections = Vec::new();
10257        let mut new_selections = Vec::new();
10258        let mut added_lines = 0;
10259        let mut removed_lines = 0;
10260
10261        while let Some(selection) = selections.next() {
10262            let (start_row, end_row) = consume_contiguous_rows(
10263                &mut contiguous_row_selections,
10264                selection,
10265                &display_map,
10266                &mut selections,
10267            );
10268
10269            let start_point = Point::new(start_row.0, 0);
10270            let end_point = Point::new(
10271                end_row.previous_row().0,
10272                buffer.line_len(end_row.previous_row()),
10273            );
10274            let text = buffer
10275                .text_for_range(start_point..end_point)
10276                .collect::<String>();
10277
10278            let mut lines = text.split('\n').collect_vec();
10279
10280            let lines_before = lines.len();
10281            callback(&mut lines);
10282            let lines_after = lines.len();
10283
10284            edits.push((start_point..end_point, lines.join("\n")));
10285
10286            // Selections must change based on added and removed line count
10287            let start_row =
10288                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10289            let end_row = MultiBufferRow(start_row.0 + lines_after.saturating_sub(1) as u32);
10290            new_selections.push(Selection {
10291                id: selection.id,
10292                start: start_row,
10293                end: end_row,
10294                goal: SelectionGoal::None,
10295                reversed: selection.reversed,
10296            });
10297
10298            if lines_after > lines_before {
10299                added_lines += lines_after - lines_before;
10300            } else if lines_before > lines_after {
10301                removed_lines += lines_before - lines_after;
10302            }
10303        }
10304
10305        self.transact(window, cx, |this, window, cx| {
10306            let buffer = this.buffer.update(cx, |buffer, cx| {
10307                buffer.edit(edits, None, cx);
10308                buffer.snapshot(cx)
10309            });
10310
10311            // Recalculate offsets on newly edited buffer
10312            let new_selections = new_selections
10313                .iter()
10314                .map(|s| {
10315                    let start_point = Point::new(s.start.0, 0);
10316                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10317                    Selection {
10318                        id: s.id,
10319                        start: buffer.point_to_offset(start_point),
10320                        end: buffer.point_to_offset(end_point),
10321                        goal: s.goal,
10322                        reversed: s.reversed,
10323                    }
10324                })
10325                .collect();
10326
10327            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10328                s.select(new_selections);
10329            });
10330
10331            this.request_autoscroll(Autoscroll::fit(), cx);
10332        });
10333    }
10334
10335    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
10336        self.manipulate_text(window, cx, |text| {
10337            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
10338            if has_upper_case_characters {
10339                text.to_lowercase()
10340            } else {
10341                text.to_uppercase()
10342            }
10343        })
10344    }
10345
10346    pub fn convert_to_upper_case(
10347        &mut self,
10348        _: &ConvertToUpperCase,
10349        window: &mut Window,
10350        cx: &mut Context<Self>,
10351    ) {
10352        self.manipulate_text(window, cx, |text| text.to_uppercase())
10353    }
10354
10355    pub fn convert_to_lower_case(
10356        &mut self,
10357        _: &ConvertToLowerCase,
10358        window: &mut Window,
10359        cx: &mut Context<Self>,
10360    ) {
10361        self.manipulate_text(window, cx, |text| text.to_lowercase())
10362    }
10363
10364    pub fn convert_to_title_case(
10365        &mut self,
10366        _: &ConvertToTitleCase,
10367        window: &mut Window,
10368        cx: &mut Context<Self>,
10369    ) {
10370        self.manipulate_text(window, cx, |text| {
10371            text.split('\n')
10372                .map(|line| line.to_case(Case::Title))
10373                .join("\n")
10374        })
10375    }
10376
10377    pub fn convert_to_snake_case(
10378        &mut self,
10379        _: &ConvertToSnakeCase,
10380        window: &mut Window,
10381        cx: &mut Context<Self>,
10382    ) {
10383        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
10384    }
10385
10386    pub fn convert_to_kebab_case(
10387        &mut self,
10388        _: &ConvertToKebabCase,
10389        window: &mut Window,
10390        cx: &mut Context<Self>,
10391    ) {
10392        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
10393    }
10394
10395    pub fn convert_to_upper_camel_case(
10396        &mut self,
10397        _: &ConvertToUpperCamelCase,
10398        window: &mut Window,
10399        cx: &mut Context<Self>,
10400    ) {
10401        self.manipulate_text(window, cx, |text| {
10402            text.split('\n')
10403                .map(|line| line.to_case(Case::UpperCamel))
10404                .join("\n")
10405        })
10406    }
10407
10408    pub fn convert_to_lower_camel_case(
10409        &mut self,
10410        _: &ConvertToLowerCamelCase,
10411        window: &mut Window,
10412        cx: &mut Context<Self>,
10413    ) {
10414        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
10415    }
10416
10417    pub fn convert_to_opposite_case(
10418        &mut self,
10419        _: &ConvertToOppositeCase,
10420        window: &mut Window,
10421        cx: &mut Context<Self>,
10422    ) {
10423        self.manipulate_text(window, cx, |text| {
10424            text.chars()
10425                .fold(String::with_capacity(text.len()), |mut t, c| {
10426                    if c.is_uppercase() {
10427                        t.extend(c.to_lowercase());
10428                    } else {
10429                        t.extend(c.to_uppercase());
10430                    }
10431                    t
10432                })
10433        })
10434    }
10435
10436    pub fn convert_to_rot13(
10437        &mut self,
10438        _: &ConvertToRot13,
10439        window: &mut Window,
10440        cx: &mut Context<Self>,
10441    ) {
10442        self.manipulate_text(window, cx, |text| {
10443            text.chars()
10444                .map(|c| match c {
10445                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
10446                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
10447                    _ => c,
10448                })
10449                .collect()
10450        })
10451    }
10452
10453    pub fn convert_to_rot47(
10454        &mut self,
10455        _: &ConvertToRot47,
10456        window: &mut Window,
10457        cx: &mut Context<Self>,
10458    ) {
10459        self.manipulate_text(window, cx, |text| {
10460            text.chars()
10461                .map(|c| {
10462                    let code_point = c as u32;
10463                    if code_point >= 33 && code_point <= 126 {
10464                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
10465                    }
10466                    c
10467                })
10468                .collect()
10469        })
10470    }
10471
10472    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
10473    where
10474        Fn: FnMut(&str) -> String,
10475    {
10476        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10477        let buffer = self.buffer.read(cx).snapshot(cx);
10478
10479        let mut new_selections = Vec::new();
10480        let mut edits = Vec::new();
10481        let mut selection_adjustment = 0i32;
10482
10483        for selection in self.selections.all::<usize>(cx) {
10484            let selection_is_empty = selection.is_empty();
10485
10486            let (start, end) = if selection_is_empty {
10487                let word_range = movement::surrounding_word(
10488                    &display_map,
10489                    selection.start.to_display_point(&display_map),
10490                );
10491                let start = word_range.start.to_offset(&display_map, Bias::Left);
10492                let end = word_range.end.to_offset(&display_map, Bias::Left);
10493                (start, end)
10494            } else {
10495                (selection.start, selection.end)
10496            };
10497
10498            let text = buffer.text_for_range(start..end).collect::<String>();
10499            let old_length = text.len() as i32;
10500            let text = callback(&text);
10501
10502            new_selections.push(Selection {
10503                start: (start as i32 - selection_adjustment) as usize,
10504                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
10505                goal: SelectionGoal::None,
10506                ..selection
10507            });
10508
10509            selection_adjustment += old_length - text.len() as i32;
10510
10511            edits.push((start..end, text));
10512        }
10513
10514        self.transact(window, cx, |this, window, cx| {
10515            this.buffer.update(cx, |buffer, cx| {
10516                buffer.edit(edits, None, cx);
10517            });
10518
10519            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10520                s.select(new_selections);
10521            });
10522
10523            this.request_autoscroll(Autoscroll::fit(), cx);
10524        });
10525    }
10526
10527    pub fn duplicate(
10528        &mut self,
10529        upwards: bool,
10530        whole_lines: bool,
10531        window: &mut Window,
10532        cx: &mut Context<Self>,
10533    ) {
10534        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10535
10536        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10537        let buffer = &display_map.buffer_snapshot;
10538        let selections = self.selections.all::<Point>(cx);
10539
10540        let mut edits = Vec::new();
10541        let mut selections_iter = selections.iter().peekable();
10542        while let Some(selection) = selections_iter.next() {
10543            let mut rows = selection.spanned_rows(false, &display_map);
10544            // duplicate line-wise
10545            if whole_lines || selection.start == selection.end {
10546                // Avoid duplicating the same lines twice.
10547                while let Some(next_selection) = selections_iter.peek() {
10548                    let next_rows = next_selection.spanned_rows(false, &display_map);
10549                    if next_rows.start < rows.end {
10550                        rows.end = next_rows.end;
10551                        selections_iter.next().unwrap();
10552                    } else {
10553                        break;
10554                    }
10555                }
10556
10557                // Copy the text from the selected row region and splice it either at the start
10558                // or end of the region.
10559                let start = Point::new(rows.start.0, 0);
10560                let end = Point::new(
10561                    rows.end.previous_row().0,
10562                    buffer.line_len(rows.end.previous_row()),
10563                );
10564                let text = buffer
10565                    .text_for_range(start..end)
10566                    .chain(Some("\n"))
10567                    .collect::<String>();
10568                let insert_location = if upwards {
10569                    Point::new(rows.end.0, 0)
10570                } else {
10571                    start
10572                };
10573                edits.push((insert_location..insert_location, text));
10574            } else {
10575                // duplicate character-wise
10576                let start = selection.start;
10577                let end = selection.end;
10578                let text = buffer.text_for_range(start..end).collect::<String>();
10579                edits.push((selection.end..selection.end, text));
10580            }
10581        }
10582
10583        self.transact(window, cx, |this, _, cx| {
10584            this.buffer.update(cx, |buffer, cx| {
10585                buffer.edit(edits, None, cx);
10586            });
10587
10588            this.request_autoscroll(Autoscroll::fit(), cx);
10589        });
10590    }
10591
10592    pub fn duplicate_line_up(
10593        &mut self,
10594        _: &DuplicateLineUp,
10595        window: &mut Window,
10596        cx: &mut Context<Self>,
10597    ) {
10598        self.duplicate(true, true, window, cx);
10599    }
10600
10601    pub fn duplicate_line_down(
10602        &mut self,
10603        _: &DuplicateLineDown,
10604        window: &mut Window,
10605        cx: &mut Context<Self>,
10606    ) {
10607        self.duplicate(false, true, window, cx);
10608    }
10609
10610    pub fn duplicate_selection(
10611        &mut self,
10612        _: &DuplicateSelection,
10613        window: &mut Window,
10614        cx: &mut Context<Self>,
10615    ) {
10616        self.duplicate(false, false, window, cx);
10617    }
10618
10619    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
10620        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10621
10622        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10623        let buffer = self.buffer.read(cx).snapshot(cx);
10624
10625        let mut edits = Vec::new();
10626        let mut unfold_ranges = Vec::new();
10627        let mut refold_creases = Vec::new();
10628
10629        let selections = self.selections.all::<Point>(cx);
10630        let mut selections = selections.iter().peekable();
10631        let mut contiguous_row_selections = Vec::new();
10632        let mut new_selections = Vec::new();
10633
10634        while let Some(selection) = selections.next() {
10635            // Find all the selections that span a contiguous row range
10636            let (start_row, end_row) = consume_contiguous_rows(
10637                &mut contiguous_row_selections,
10638                selection,
10639                &display_map,
10640                &mut selections,
10641            );
10642
10643            // Move the text spanned by the row range to be before the line preceding the row range
10644            if start_row.0 > 0 {
10645                let range_to_move = Point::new(
10646                    start_row.previous_row().0,
10647                    buffer.line_len(start_row.previous_row()),
10648                )
10649                    ..Point::new(
10650                        end_row.previous_row().0,
10651                        buffer.line_len(end_row.previous_row()),
10652                    );
10653                let insertion_point = display_map
10654                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
10655                    .0;
10656
10657                // Don't move lines across excerpts
10658                if buffer
10659                    .excerpt_containing(insertion_point..range_to_move.end)
10660                    .is_some()
10661                {
10662                    let text = buffer
10663                        .text_for_range(range_to_move.clone())
10664                        .flat_map(|s| s.chars())
10665                        .skip(1)
10666                        .chain(['\n'])
10667                        .collect::<String>();
10668
10669                    edits.push((
10670                        buffer.anchor_after(range_to_move.start)
10671                            ..buffer.anchor_before(range_to_move.end),
10672                        String::new(),
10673                    ));
10674                    let insertion_anchor = buffer.anchor_after(insertion_point);
10675                    edits.push((insertion_anchor..insertion_anchor, text));
10676
10677                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
10678
10679                    // Move selections up
10680                    new_selections.extend(contiguous_row_selections.drain(..).map(
10681                        |mut selection| {
10682                            selection.start.row -= row_delta;
10683                            selection.end.row -= row_delta;
10684                            selection
10685                        },
10686                    ));
10687
10688                    // Move folds up
10689                    unfold_ranges.push(range_to_move.clone());
10690                    for fold in display_map.folds_in_range(
10691                        buffer.anchor_before(range_to_move.start)
10692                            ..buffer.anchor_after(range_to_move.end),
10693                    ) {
10694                        let mut start = fold.range.start.to_point(&buffer);
10695                        let mut end = fold.range.end.to_point(&buffer);
10696                        start.row -= row_delta;
10697                        end.row -= row_delta;
10698                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10699                    }
10700                }
10701            }
10702
10703            // If we didn't move line(s), preserve the existing selections
10704            new_selections.append(&mut contiguous_row_selections);
10705        }
10706
10707        self.transact(window, cx, |this, window, cx| {
10708            this.unfold_ranges(&unfold_ranges, true, true, cx);
10709            this.buffer.update(cx, |buffer, cx| {
10710                for (range, text) in edits {
10711                    buffer.edit([(range, text)], None, cx);
10712                }
10713            });
10714            this.fold_creases(refold_creases, true, window, cx);
10715            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10716                s.select(new_selections);
10717            })
10718        });
10719    }
10720
10721    pub fn move_line_down(
10722        &mut self,
10723        _: &MoveLineDown,
10724        window: &mut Window,
10725        cx: &mut Context<Self>,
10726    ) {
10727        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10728
10729        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10730        let buffer = self.buffer.read(cx).snapshot(cx);
10731
10732        let mut edits = Vec::new();
10733        let mut unfold_ranges = Vec::new();
10734        let mut refold_creases = Vec::new();
10735
10736        let selections = self.selections.all::<Point>(cx);
10737        let mut selections = selections.iter().peekable();
10738        let mut contiguous_row_selections = Vec::new();
10739        let mut new_selections = Vec::new();
10740
10741        while let Some(selection) = selections.next() {
10742            // Find all the selections that span a contiguous row range
10743            let (start_row, end_row) = consume_contiguous_rows(
10744                &mut contiguous_row_selections,
10745                selection,
10746                &display_map,
10747                &mut selections,
10748            );
10749
10750            // Move the text spanned by the row range to be after the last line of the row range
10751            if end_row.0 <= buffer.max_point().row {
10752                let range_to_move =
10753                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
10754                let insertion_point = display_map
10755                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
10756                    .0;
10757
10758                // Don't move lines across excerpt boundaries
10759                if buffer
10760                    .excerpt_containing(range_to_move.start..insertion_point)
10761                    .is_some()
10762                {
10763                    let mut text = String::from("\n");
10764                    text.extend(buffer.text_for_range(range_to_move.clone()));
10765                    text.pop(); // Drop trailing newline
10766                    edits.push((
10767                        buffer.anchor_after(range_to_move.start)
10768                            ..buffer.anchor_before(range_to_move.end),
10769                        String::new(),
10770                    ));
10771                    let insertion_anchor = buffer.anchor_after(insertion_point);
10772                    edits.push((insertion_anchor..insertion_anchor, text));
10773
10774                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
10775
10776                    // Move selections down
10777                    new_selections.extend(contiguous_row_selections.drain(..).map(
10778                        |mut selection| {
10779                            selection.start.row += row_delta;
10780                            selection.end.row += row_delta;
10781                            selection
10782                        },
10783                    ));
10784
10785                    // Move folds down
10786                    unfold_ranges.push(range_to_move.clone());
10787                    for fold in display_map.folds_in_range(
10788                        buffer.anchor_before(range_to_move.start)
10789                            ..buffer.anchor_after(range_to_move.end),
10790                    ) {
10791                        let mut start = fold.range.start.to_point(&buffer);
10792                        let mut end = fold.range.end.to_point(&buffer);
10793                        start.row += row_delta;
10794                        end.row += row_delta;
10795                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
10796                    }
10797                }
10798            }
10799
10800            // If we didn't move line(s), preserve the existing selections
10801            new_selections.append(&mut contiguous_row_selections);
10802        }
10803
10804        self.transact(window, cx, |this, window, cx| {
10805            this.unfold_ranges(&unfold_ranges, true, true, cx);
10806            this.buffer.update(cx, |buffer, cx| {
10807                for (range, text) in edits {
10808                    buffer.edit([(range, text)], None, cx);
10809                }
10810            });
10811            this.fold_creases(refold_creases, true, window, cx);
10812            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10813                s.select(new_selections)
10814            });
10815        });
10816    }
10817
10818    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
10819        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10820        let text_layout_details = &self.text_layout_details(window);
10821        self.transact(window, cx, |this, window, cx| {
10822            let edits = this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10823                let mut edits: Vec<(Range<usize>, String)> = Default::default();
10824                s.move_with(|display_map, selection| {
10825                    if !selection.is_empty() {
10826                        return;
10827                    }
10828
10829                    let mut head = selection.head();
10830                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
10831                    if head.column() == display_map.line_len(head.row()) {
10832                        transpose_offset = display_map
10833                            .buffer_snapshot
10834                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10835                    }
10836
10837                    if transpose_offset == 0 {
10838                        return;
10839                    }
10840
10841                    *head.column_mut() += 1;
10842                    head = display_map.clip_point(head, Bias::Right);
10843                    let goal = SelectionGoal::HorizontalPosition(
10844                        display_map
10845                            .x_for_display_point(head, text_layout_details)
10846                            .into(),
10847                    );
10848                    selection.collapse_to(head, goal);
10849
10850                    let transpose_start = display_map
10851                        .buffer_snapshot
10852                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
10853                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
10854                        let transpose_end = display_map
10855                            .buffer_snapshot
10856                            .clip_offset(transpose_offset + 1, Bias::Right);
10857                        if let Some(ch) =
10858                            display_map.buffer_snapshot.chars_at(transpose_start).next()
10859                        {
10860                            edits.push((transpose_start..transpose_offset, String::new()));
10861                            edits.push((transpose_end..transpose_end, ch.to_string()));
10862                        }
10863                    }
10864                });
10865                edits
10866            });
10867            this.buffer
10868                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
10869            let selections = this.selections.all::<usize>(cx);
10870            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
10871                s.select(selections);
10872            });
10873        });
10874    }
10875
10876    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
10877        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
10878        self.rewrap_impl(RewrapOptions::default(), cx)
10879    }
10880
10881    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
10882        let buffer = self.buffer.read(cx).snapshot(cx);
10883        let selections = self.selections.all::<Point>(cx);
10884        let mut selections = selections.iter().peekable();
10885
10886        let mut edits = Vec::new();
10887        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
10888
10889        while let Some(selection) = selections.next() {
10890            let mut start_row = selection.start.row;
10891            let mut end_row = selection.end.row;
10892
10893            // Skip selections that overlap with a range that has already been rewrapped.
10894            let selection_range = start_row..end_row;
10895            if rewrapped_row_ranges
10896                .iter()
10897                .any(|range| range.overlaps(&selection_range))
10898            {
10899                continue;
10900            }
10901
10902            let tab_size = buffer.language_settings_at(selection.head(), cx).tab_size;
10903
10904            // Since not all lines in the selection may be at the same indent
10905            // level, choose the indent size that is the most common between all
10906            // of the lines.
10907            //
10908            // If there is a tie, we use the deepest indent.
10909            let (indent_size, indent_end) = {
10910                let mut indent_size_occurrences = HashMap::default();
10911                let mut rows_by_indent_size = HashMap::<IndentSize, Vec<u32>>::default();
10912
10913                for row in start_row..=end_row {
10914                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
10915                    rows_by_indent_size.entry(indent).or_default().push(row);
10916                    *indent_size_occurrences.entry(indent).or_insert(0) += 1;
10917                }
10918
10919                let indent_size = indent_size_occurrences
10920                    .into_iter()
10921                    .max_by_key(|(indent, count)| (*count, indent.len_with_expanded_tabs(tab_size)))
10922                    .map(|(indent, _)| indent)
10923                    .unwrap_or_default();
10924                let row = rows_by_indent_size[&indent_size][0];
10925                let indent_end = Point::new(row, indent_size.len);
10926
10927                (indent_size, indent_end)
10928            };
10929
10930            let mut line_prefix = indent_size.chars().collect::<String>();
10931
10932            let mut inside_comment = false;
10933            if let Some(comment_prefix) =
10934                buffer
10935                    .language_scope_at(selection.head())
10936                    .and_then(|language| {
10937                        language
10938                            .line_comment_prefixes()
10939                            .iter()
10940                            .find(|prefix| buffer.contains_str_at(indent_end, prefix))
10941                            .cloned()
10942                    })
10943            {
10944                line_prefix.push_str(&comment_prefix);
10945                inside_comment = true;
10946            }
10947
10948            let language_settings = buffer.language_settings_at(selection.head(), cx);
10949            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
10950                RewrapBehavior::InComments => inside_comment,
10951                RewrapBehavior::InSelections => !selection.is_empty(),
10952                RewrapBehavior::Anywhere => true,
10953            };
10954
10955            let should_rewrap = options.override_language_settings
10956                || allow_rewrap_based_on_language
10957                || self.hard_wrap.is_some();
10958            if !should_rewrap {
10959                continue;
10960            }
10961
10962            if selection.is_empty() {
10963                'expand_upwards: while start_row > 0 {
10964                    let prev_row = start_row - 1;
10965                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
10966                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
10967                    {
10968                        start_row = prev_row;
10969                    } else {
10970                        break 'expand_upwards;
10971                    }
10972                }
10973
10974                'expand_downwards: while end_row < buffer.max_point().row {
10975                    let next_row = end_row + 1;
10976                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
10977                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
10978                    {
10979                        end_row = next_row;
10980                    } else {
10981                        break 'expand_downwards;
10982                    }
10983                }
10984            }
10985
10986            let start = Point::new(start_row, 0);
10987            let start_offset = start.to_offset(&buffer);
10988            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
10989            let selection_text = buffer.text_for_range(start..end).collect::<String>();
10990            let Some(lines_without_prefixes) = selection_text
10991                .lines()
10992                .map(|line| {
10993                    line.strip_prefix(&line_prefix)
10994                        .or_else(|| line.trim_start().strip_prefix(&line_prefix.trim_start()))
10995                        .with_context(|| {
10996                            format!("line did not start with prefix {line_prefix:?}: {line:?}")
10997                        })
10998                })
10999                .collect::<Result<Vec<_>, _>>()
11000                .log_err()
11001            else {
11002                continue;
11003            };
11004
11005            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11006                buffer
11007                    .language_settings_at(Point::new(start_row, 0), cx)
11008                    .preferred_line_length as usize
11009            });
11010            let wrapped_text = wrap_with_prefix(
11011                line_prefix,
11012                lines_without_prefixes.join("\n"),
11013                wrap_column,
11014                tab_size,
11015                options.preserve_existing_whitespace,
11016            );
11017
11018            // TODO: should always use char-based diff while still supporting cursor behavior that
11019            // matches vim.
11020            let mut diff_options = DiffOptions::default();
11021            if options.override_language_settings {
11022                diff_options.max_word_diff_len = 0;
11023                diff_options.max_word_diff_line_count = 0;
11024            } else {
11025                diff_options.max_word_diff_len = usize::MAX;
11026                diff_options.max_word_diff_line_count = usize::MAX;
11027            }
11028
11029            for (old_range, new_text) in
11030                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11031            {
11032                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11033                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11034                edits.push((edit_start..edit_end, new_text));
11035            }
11036
11037            rewrapped_row_ranges.push(start_row..=end_row);
11038        }
11039
11040        self.buffer
11041            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11042    }
11043
11044    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11045        let mut text = String::new();
11046        let buffer = self.buffer.read(cx).snapshot(cx);
11047        let mut selections = self.selections.all::<Point>(cx);
11048        let mut clipboard_selections = Vec::with_capacity(selections.len());
11049        {
11050            let max_point = buffer.max_point();
11051            let mut is_first = true;
11052            for selection in &mut selections {
11053                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11054                if is_entire_line {
11055                    selection.start = Point::new(selection.start.row, 0);
11056                    if !selection.is_empty() && selection.end.column == 0 {
11057                        selection.end = cmp::min(max_point, selection.end);
11058                    } else {
11059                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
11060                    }
11061                    selection.goal = SelectionGoal::None;
11062                }
11063                if is_first {
11064                    is_first = false;
11065                } else {
11066                    text += "\n";
11067                }
11068                let mut len = 0;
11069                for chunk in buffer.text_for_range(selection.start..selection.end) {
11070                    text.push_str(chunk);
11071                    len += chunk.len();
11072                }
11073                clipboard_selections.push(ClipboardSelection {
11074                    len,
11075                    is_entire_line,
11076                    first_line_indent: buffer
11077                        .indent_size_for_line(MultiBufferRow(selection.start.row))
11078                        .len,
11079                });
11080            }
11081        }
11082
11083        self.transact(window, cx, |this, window, cx| {
11084            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11085                s.select(selections);
11086            });
11087            this.insert("", window, cx);
11088        });
11089        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
11090    }
11091
11092    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
11093        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11094        let item = self.cut_common(window, cx);
11095        cx.write_to_clipboard(item);
11096    }
11097
11098    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
11099        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11100        self.change_selections(None, window, cx, |s| {
11101            s.move_with(|snapshot, sel| {
11102                if sel.is_empty() {
11103                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
11104                }
11105            });
11106        });
11107        let item = self.cut_common(window, cx);
11108        cx.set_global(KillRing(item))
11109    }
11110
11111    pub fn kill_ring_yank(
11112        &mut self,
11113        _: &KillRingYank,
11114        window: &mut Window,
11115        cx: &mut Context<Self>,
11116    ) {
11117        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11118        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
11119            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
11120                (kill_ring.text().to_string(), kill_ring.metadata_json())
11121            } else {
11122                return;
11123            }
11124        } else {
11125            return;
11126        };
11127        self.do_paste(&text, metadata, false, window, cx);
11128    }
11129
11130    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
11131        self.do_copy(true, cx);
11132    }
11133
11134    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
11135        self.do_copy(false, cx);
11136    }
11137
11138    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
11139        let selections = self.selections.all::<Point>(cx);
11140        let buffer = self.buffer.read(cx).read(cx);
11141        let mut text = String::new();
11142
11143        let mut clipboard_selections = Vec::with_capacity(selections.len());
11144        {
11145            let max_point = buffer.max_point();
11146            let mut is_first = true;
11147            for selection in &selections {
11148                let mut start = selection.start;
11149                let mut end = selection.end;
11150                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11151                if is_entire_line {
11152                    start = Point::new(start.row, 0);
11153                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
11154                }
11155
11156                let mut trimmed_selections = Vec::new();
11157                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
11158                    let row = MultiBufferRow(start.row);
11159                    let first_indent = buffer.indent_size_for_line(row);
11160                    if first_indent.len == 0 || start.column > first_indent.len {
11161                        trimmed_selections.push(start..end);
11162                    } else {
11163                        trimmed_selections.push(
11164                            Point::new(row.0, first_indent.len)
11165                                ..Point::new(row.0, buffer.line_len(row)),
11166                        );
11167                        for row in start.row + 1..=end.row {
11168                            let mut line_len = buffer.line_len(MultiBufferRow(row));
11169                            if row == end.row {
11170                                line_len = end.column;
11171                            }
11172                            if line_len == 0 {
11173                                trimmed_selections
11174                                    .push(Point::new(row, 0)..Point::new(row, line_len));
11175                                continue;
11176                            }
11177                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
11178                            if row_indent_size.len >= first_indent.len {
11179                                trimmed_selections.push(
11180                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
11181                                );
11182                            } else {
11183                                trimmed_selections.clear();
11184                                trimmed_selections.push(start..end);
11185                                break;
11186                            }
11187                        }
11188                    }
11189                } else {
11190                    trimmed_selections.push(start..end);
11191                }
11192
11193                for trimmed_range in trimmed_selections {
11194                    if is_first {
11195                        is_first = false;
11196                    } else {
11197                        text += "\n";
11198                    }
11199                    let mut len = 0;
11200                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
11201                        text.push_str(chunk);
11202                        len += chunk.len();
11203                    }
11204                    clipboard_selections.push(ClipboardSelection {
11205                        len,
11206                        is_entire_line,
11207                        first_line_indent: buffer
11208                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
11209                            .len,
11210                    });
11211                }
11212            }
11213        }
11214
11215        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
11216            text,
11217            clipboard_selections,
11218        ));
11219    }
11220
11221    pub fn do_paste(
11222        &mut self,
11223        text: &String,
11224        clipboard_selections: Option<Vec<ClipboardSelection>>,
11225        handle_entire_lines: bool,
11226        window: &mut Window,
11227        cx: &mut Context<Self>,
11228    ) {
11229        if self.read_only(cx) {
11230            return;
11231        }
11232
11233        let clipboard_text = Cow::Borrowed(text);
11234
11235        self.transact(window, cx, |this, window, cx| {
11236            if let Some(mut clipboard_selections) = clipboard_selections {
11237                let old_selections = this.selections.all::<usize>(cx);
11238                let all_selections_were_entire_line =
11239                    clipboard_selections.iter().all(|s| s.is_entire_line);
11240                let first_selection_indent_column =
11241                    clipboard_selections.first().map(|s| s.first_line_indent);
11242                if clipboard_selections.len() != old_selections.len() {
11243                    clipboard_selections.drain(..);
11244                }
11245                let cursor_offset = this.selections.last::<usize>(cx).head();
11246                let mut auto_indent_on_paste = true;
11247
11248                this.buffer.update(cx, |buffer, cx| {
11249                    let snapshot = buffer.read(cx);
11250                    auto_indent_on_paste = snapshot
11251                        .language_settings_at(cursor_offset, cx)
11252                        .auto_indent_on_paste;
11253
11254                    let mut start_offset = 0;
11255                    let mut edits = Vec::new();
11256                    let mut original_indent_columns = Vec::new();
11257                    for (ix, selection) in old_selections.iter().enumerate() {
11258                        let to_insert;
11259                        let entire_line;
11260                        let original_indent_column;
11261                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
11262                            let end_offset = start_offset + clipboard_selection.len;
11263                            to_insert = &clipboard_text[start_offset..end_offset];
11264                            entire_line = clipboard_selection.is_entire_line;
11265                            start_offset = end_offset + 1;
11266                            original_indent_column = Some(clipboard_selection.first_line_indent);
11267                        } else {
11268                            to_insert = clipboard_text.as_str();
11269                            entire_line = all_selections_were_entire_line;
11270                            original_indent_column = first_selection_indent_column
11271                        }
11272
11273                        // If the corresponding selection was empty when this slice of the
11274                        // clipboard text was written, then the entire line containing the
11275                        // selection was copied. If this selection is also currently empty,
11276                        // then paste the line before the current line of the buffer.
11277                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
11278                            let column = selection.start.to_point(&snapshot).column as usize;
11279                            let line_start = selection.start - column;
11280                            line_start..line_start
11281                        } else {
11282                            selection.range()
11283                        };
11284
11285                        edits.push((range, to_insert));
11286                        original_indent_columns.push(original_indent_column);
11287                    }
11288                    drop(snapshot);
11289
11290                    buffer.edit(
11291                        edits,
11292                        if auto_indent_on_paste {
11293                            Some(AutoindentMode::Block {
11294                                original_indent_columns,
11295                            })
11296                        } else {
11297                            None
11298                        },
11299                        cx,
11300                    );
11301                });
11302
11303                let selections = this.selections.all::<usize>(cx);
11304                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11305                    s.select(selections)
11306                });
11307            } else {
11308                this.insert(&clipboard_text, window, cx);
11309            }
11310        });
11311    }
11312
11313    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
11314        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11315        if let Some(item) = cx.read_from_clipboard() {
11316            let entries = item.entries();
11317
11318            match entries.first() {
11319                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
11320                // of all the pasted entries.
11321                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
11322                    .do_paste(
11323                        clipboard_string.text(),
11324                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
11325                        true,
11326                        window,
11327                        cx,
11328                    ),
11329                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
11330            }
11331        }
11332    }
11333
11334    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
11335        if self.read_only(cx) {
11336            return;
11337        }
11338
11339        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11340
11341        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
11342            if let Some((selections, _)) =
11343                self.selection_history.transaction(transaction_id).cloned()
11344            {
11345                self.change_selections(None, window, cx, |s| {
11346                    s.select_anchors(selections.to_vec());
11347                });
11348            } else {
11349                log::error!(
11350                    "No entry in selection_history found for undo. \
11351                     This may correspond to a bug where undo does not update the selection. \
11352                     If this is occurring, please add details to \
11353                     https://github.com/zed-industries/zed/issues/22692"
11354                );
11355            }
11356            self.request_autoscroll(Autoscroll::fit(), cx);
11357            self.unmark_text(window, cx);
11358            self.refresh_inline_completion(true, false, window, cx);
11359            cx.emit(EditorEvent::Edited { transaction_id });
11360            cx.emit(EditorEvent::TransactionUndone { transaction_id });
11361        }
11362    }
11363
11364    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
11365        if self.read_only(cx) {
11366            return;
11367        }
11368
11369        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11370
11371        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
11372            if let Some((_, Some(selections))) =
11373                self.selection_history.transaction(transaction_id).cloned()
11374            {
11375                self.change_selections(None, window, cx, |s| {
11376                    s.select_anchors(selections.to_vec());
11377                });
11378            } else {
11379                log::error!(
11380                    "No entry in selection_history found for redo. \
11381                     This may correspond to a bug where undo does not update the selection. \
11382                     If this is occurring, please add details to \
11383                     https://github.com/zed-industries/zed/issues/22692"
11384                );
11385            }
11386            self.request_autoscroll(Autoscroll::fit(), cx);
11387            self.unmark_text(window, cx);
11388            self.refresh_inline_completion(true, false, window, cx);
11389            cx.emit(EditorEvent::Edited { transaction_id });
11390        }
11391    }
11392
11393    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
11394        self.buffer
11395            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
11396    }
11397
11398    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
11399        self.buffer
11400            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
11401    }
11402
11403    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
11404        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11405        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11406            s.move_with(|map, selection| {
11407                let cursor = if selection.is_empty() {
11408                    movement::left(map, selection.start)
11409                } else {
11410                    selection.start
11411                };
11412                selection.collapse_to(cursor, SelectionGoal::None);
11413            });
11414        })
11415    }
11416
11417    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
11418        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11419        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11420            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
11421        })
11422    }
11423
11424    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
11425        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11426        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11427            s.move_with(|map, selection| {
11428                let cursor = if selection.is_empty() {
11429                    movement::right(map, selection.end)
11430                } else {
11431                    selection.end
11432                };
11433                selection.collapse_to(cursor, SelectionGoal::None)
11434            });
11435        })
11436    }
11437
11438    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
11439        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11440        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11441            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
11442        })
11443    }
11444
11445    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
11446        if self.take_rename(true, window, cx).is_some() {
11447            return;
11448        }
11449
11450        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11451            cx.propagate();
11452            return;
11453        }
11454
11455        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11456
11457        let text_layout_details = &self.text_layout_details(window);
11458        let selection_count = self.selections.count();
11459        let first_selection = self.selections.first_anchor();
11460
11461        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11462            s.move_with(|map, selection| {
11463                if !selection.is_empty() {
11464                    selection.goal = SelectionGoal::None;
11465                }
11466                let (cursor, goal) = movement::up(
11467                    map,
11468                    selection.start,
11469                    selection.goal,
11470                    false,
11471                    text_layout_details,
11472                );
11473                selection.collapse_to(cursor, goal);
11474            });
11475        });
11476
11477        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11478        {
11479            cx.propagate();
11480        }
11481    }
11482
11483    pub fn move_up_by_lines(
11484        &mut self,
11485        action: &MoveUpByLines,
11486        window: &mut Window,
11487        cx: &mut Context<Self>,
11488    ) {
11489        if self.take_rename(true, window, cx).is_some() {
11490            return;
11491        }
11492
11493        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11494            cx.propagate();
11495            return;
11496        }
11497
11498        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11499
11500        let text_layout_details = &self.text_layout_details(window);
11501
11502        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11503            s.move_with(|map, selection| {
11504                if !selection.is_empty() {
11505                    selection.goal = SelectionGoal::None;
11506                }
11507                let (cursor, goal) = movement::up_by_rows(
11508                    map,
11509                    selection.start,
11510                    action.lines,
11511                    selection.goal,
11512                    false,
11513                    text_layout_details,
11514                );
11515                selection.collapse_to(cursor, goal);
11516            });
11517        })
11518    }
11519
11520    pub fn move_down_by_lines(
11521        &mut self,
11522        action: &MoveDownByLines,
11523        window: &mut Window,
11524        cx: &mut Context<Self>,
11525    ) {
11526        if self.take_rename(true, window, cx).is_some() {
11527            return;
11528        }
11529
11530        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11531            cx.propagate();
11532            return;
11533        }
11534
11535        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11536
11537        let text_layout_details = &self.text_layout_details(window);
11538
11539        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11540            s.move_with(|map, selection| {
11541                if !selection.is_empty() {
11542                    selection.goal = SelectionGoal::None;
11543                }
11544                let (cursor, goal) = movement::down_by_rows(
11545                    map,
11546                    selection.start,
11547                    action.lines,
11548                    selection.goal,
11549                    false,
11550                    text_layout_details,
11551                );
11552                selection.collapse_to(cursor, goal);
11553            });
11554        })
11555    }
11556
11557    pub fn select_down_by_lines(
11558        &mut self,
11559        action: &SelectDownByLines,
11560        window: &mut Window,
11561        cx: &mut Context<Self>,
11562    ) {
11563        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11564        let text_layout_details = &self.text_layout_details(window);
11565        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11566            s.move_heads_with(|map, head, goal| {
11567                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
11568            })
11569        })
11570    }
11571
11572    pub fn select_up_by_lines(
11573        &mut self,
11574        action: &SelectUpByLines,
11575        window: &mut Window,
11576        cx: &mut Context<Self>,
11577    ) {
11578        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11579        let text_layout_details = &self.text_layout_details(window);
11580        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11581            s.move_heads_with(|map, head, goal| {
11582                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
11583            })
11584        })
11585    }
11586
11587    pub fn select_page_up(
11588        &mut self,
11589        _: &SelectPageUp,
11590        window: &mut Window,
11591        cx: &mut Context<Self>,
11592    ) {
11593        let Some(row_count) = self.visible_row_count() else {
11594            return;
11595        };
11596
11597        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11598
11599        let text_layout_details = &self.text_layout_details(window);
11600
11601        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11602            s.move_heads_with(|map, head, goal| {
11603                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
11604            })
11605        })
11606    }
11607
11608    pub fn move_page_up(
11609        &mut self,
11610        action: &MovePageUp,
11611        window: &mut Window,
11612        cx: &mut Context<Self>,
11613    ) {
11614        if self.take_rename(true, window, cx).is_some() {
11615            return;
11616        }
11617
11618        if self
11619            .context_menu
11620            .borrow_mut()
11621            .as_mut()
11622            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
11623            .unwrap_or(false)
11624        {
11625            return;
11626        }
11627
11628        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11629            cx.propagate();
11630            return;
11631        }
11632
11633        let Some(row_count) = self.visible_row_count() else {
11634            return;
11635        };
11636
11637        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11638
11639        let autoscroll = if action.center_cursor {
11640            Autoscroll::center()
11641        } else {
11642            Autoscroll::fit()
11643        };
11644
11645        let text_layout_details = &self.text_layout_details(window);
11646
11647        self.change_selections(Some(autoscroll), window, cx, |s| {
11648            s.move_with(|map, selection| {
11649                if !selection.is_empty() {
11650                    selection.goal = SelectionGoal::None;
11651                }
11652                let (cursor, goal) = movement::up_by_rows(
11653                    map,
11654                    selection.end,
11655                    row_count,
11656                    selection.goal,
11657                    false,
11658                    text_layout_details,
11659                );
11660                selection.collapse_to(cursor, goal);
11661            });
11662        });
11663    }
11664
11665    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
11666        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11667        let text_layout_details = &self.text_layout_details(window);
11668        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11669            s.move_heads_with(|map, head, goal| {
11670                movement::up(map, head, goal, false, text_layout_details)
11671            })
11672        })
11673    }
11674
11675    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
11676        self.take_rename(true, window, cx);
11677
11678        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11679            cx.propagate();
11680            return;
11681        }
11682
11683        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11684
11685        let text_layout_details = &self.text_layout_details(window);
11686        let selection_count = self.selections.count();
11687        let first_selection = self.selections.first_anchor();
11688
11689        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11690            s.move_with(|map, selection| {
11691                if !selection.is_empty() {
11692                    selection.goal = SelectionGoal::None;
11693                }
11694                let (cursor, goal) = movement::down(
11695                    map,
11696                    selection.end,
11697                    selection.goal,
11698                    false,
11699                    text_layout_details,
11700                );
11701                selection.collapse_to(cursor, goal);
11702            });
11703        });
11704
11705        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
11706        {
11707            cx.propagate();
11708        }
11709    }
11710
11711    pub fn select_page_down(
11712        &mut self,
11713        _: &SelectPageDown,
11714        window: &mut Window,
11715        cx: &mut Context<Self>,
11716    ) {
11717        let Some(row_count) = self.visible_row_count() else {
11718            return;
11719        };
11720
11721        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11722
11723        let text_layout_details = &self.text_layout_details(window);
11724
11725        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11726            s.move_heads_with(|map, head, goal| {
11727                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
11728            })
11729        })
11730    }
11731
11732    pub fn move_page_down(
11733        &mut self,
11734        action: &MovePageDown,
11735        window: &mut Window,
11736        cx: &mut Context<Self>,
11737    ) {
11738        if self.take_rename(true, window, cx).is_some() {
11739            return;
11740        }
11741
11742        if self
11743            .context_menu
11744            .borrow_mut()
11745            .as_mut()
11746            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
11747            .unwrap_or(false)
11748        {
11749            return;
11750        }
11751
11752        if matches!(self.mode, EditorMode::SingleLine { .. }) {
11753            cx.propagate();
11754            return;
11755        }
11756
11757        let Some(row_count) = self.visible_row_count() else {
11758            return;
11759        };
11760
11761        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11762
11763        let autoscroll = if action.center_cursor {
11764            Autoscroll::center()
11765        } else {
11766            Autoscroll::fit()
11767        };
11768
11769        let text_layout_details = &self.text_layout_details(window);
11770        self.change_selections(Some(autoscroll), window, cx, |s| {
11771            s.move_with(|map, selection| {
11772                if !selection.is_empty() {
11773                    selection.goal = SelectionGoal::None;
11774                }
11775                let (cursor, goal) = movement::down_by_rows(
11776                    map,
11777                    selection.end,
11778                    row_count,
11779                    selection.goal,
11780                    false,
11781                    text_layout_details,
11782                );
11783                selection.collapse_to(cursor, goal);
11784            });
11785        });
11786    }
11787
11788    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
11789        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11790        let text_layout_details = &self.text_layout_details(window);
11791        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11792            s.move_heads_with(|map, head, goal| {
11793                movement::down(map, head, goal, false, text_layout_details)
11794            })
11795        });
11796    }
11797
11798    pub fn context_menu_first(
11799        &mut self,
11800        _: &ContextMenuFirst,
11801        window: &mut Window,
11802        cx: &mut Context<Self>,
11803    ) {
11804        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11805            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
11806        }
11807    }
11808
11809    pub fn context_menu_prev(
11810        &mut self,
11811        _: &ContextMenuPrevious,
11812        window: &mut Window,
11813        cx: &mut Context<Self>,
11814    ) {
11815        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11816            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
11817        }
11818    }
11819
11820    pub fn context_menu_next(
11821        &mut self,
11822        _: &ContextMenuNext,
11823        window: &mut Window,
11824        cx: &mut Context<Self>,
11825    ) {
11826        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11827            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
11828        }
11829    }
11830
11831    pub fn context_menu_last(
11832        &mut self,
11833        _: &ContextMenuLast,
11834        window: &mut Window,
11835        cx: &mut Context<Self>,
11836    ) {
11837        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
11838            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
11839        }
11840    }
11841
11842    pub fn move_to_previous_word_start(
11843        &mut self,
11844        _: &MoveToPreviousWordStart,
11845        window: &mut Window,
11846        cx: &mut Context<Self>,
11847    ) {
11848        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11849        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11850            s.move_cursors_with(|map, head, _| {
11851                (
11852                    movement::previous_word_start(map, head),
11853                    SelectionGoal::None,
11854                )
11855            });
11856        })
11857    }
11858
11859    pub fn move_to_previous_subword_start(
11860        &mut self,
11861        _: &MoveToPreviousSubwordStart,
11862        window: &mut Window,
11863        cx: &mut Context<Self>,
11864    ) {
11865        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11866        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11867            s.move_cursors_with(|map, head, _| {
11868                (
11869                    movement::previous_subword_start(map, head),
11870                    SelectionGoal::None,
11871                )
11872            });
11873        })
11874    }
11875
11876    pub fn select_to_previous_word_start(
11877        &mut self,
11878        _: &SelectToPreviousWordStart,
11879        window: &mut Window,
11880        cx: &mut Context<Self>,
11881    ) {
11882        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11883        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11884            s.move_heads_with(|map, head, _| {
11885                (
11886                    movement::previous_word_start(map, head),
11887                    SelectionGoal::None,
11888                )
11889            });
11890        })
11891    }
11892
11893    pub fn select_to_previous_subword_start(
11894        &mut self,
11895        _: &SelectToPreviousSubwordStart,
11896        window: &mut Window,
11897        cx: &mut Context<Self>,
11898    ) {
11899        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11900        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11901            s.move_heads_with(|map, head, _| {
11902                (
11903                    movement::previous_subword_start(map, head),
11904                    SelectionGoal::None,
11905                )
11906            });
11907        })
11908    }
11909
11910    pub fn delete_to_previous_word_start(
11911        &mut self,
11912        action: &DeleteToPreviousWordStart,
11913        window: &mut Window,
11914        cx: &mut Context<Self>,
11915    ) {
11916        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11917        self.transact(window, cx, |this, window, cx| {
11918            this.select_autoclose_pair(window, cx);
11919            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11920                s.move_with(|map, selection| {
11921                    if selection.is_empty() {
11922                        let cursor = if action.ignore_newlines {
11923                            movement::previous_word_start(map, selection.head())
11924                        } else {
11925                            movement::previous_word_start_or_newline(map, selection.head())
11926                        };
11927                        selection.set_head(cursor, SelectionGoal::None);
11928                    }
11929                });
11930            });
11931            this.insert("", window, cx);
11932        });
11933    }
11934
11935    pub fn delete_to_previous_subword_start(
11936        &mut self,
11937        _: &DeleteToPreviousSubwordStart,
11938        window: &mut Window,
11939        cx: &mut Context<Self>,
11940    ) {
11941        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
11942        self.transact(window, cx, |this, window, cx| {
11943            this.select_autoclose_pair(window, cx);
11944            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11945                s.move_with(|map, selection| {
11946                    if selection.is_empty() {
11947                        let cursor = movement::previous_subword_start(map, selection.head());
11948                        selection.set_head(cursor, SelectionGoal::None);
11949                    }
11950                });
11951            });
11952            this.insert("", window, cx);
11953        });
11954    }
11955
11956    pub fn move_to_next_word_end(
11957        &mut self,
11958        _: &MoveToNextWordEnd,
11959        window: &mut Window,
11960        cx: &mut Context<Self>,
11961    ) {
11962        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11963        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11964            s.move_cursors_with(|map, head, _| {
11965                (movement::next_word_end(map, head), SelectionGoal::None)
11966            });
11967        })
11968    }
11969
11970    pub fn move_to_next_subword_end(
11971        &mut self,
11972        _: &MoveToNextSubwordEnd,
11973        window: &mut Window,
11974        cx: &mut Context<Self>,
11975    ) {
11976        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11977        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11978            s.move_cursors_with(|map, head, _| {
11979                (movement::next_subword_end(map, head), SelectionGoal::None)
11980            });
11981        })
11982    }
11983
11984    pub fn select_to_next_word_end(
11985        &mut self,
11986        _: &SelectToNextWordEnd,
11987        window: &mut Window,
11988        cx: &mut Context<Self>,
11989    ) {
11990        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
11991        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
11992            s.move_heads_with(|map, head, _| {
11993                (movement::next_word_end(map, head), SelectionGoal::None)
11994            });
11995        })
11996    }
11997
11998    pub fn select_to_next_subword_end(
11999        &mut self,
12000        _: &SelectToNextSubwordEnd,
12001        window: &mut Window,
12002        cx: &mut Context<Self>,
12003    ) {
12004        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12005        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12006            s.move_heads_with(|map, head, _| {
12007                (movement::next_subword_end(map, head), SelectionGoal::None)
12008            });
12009        })
12010    }
12011
12012    pub fn delete_to_next_word_end(
12013        &mut self,
12014        action: &DeleteToNextWordEnd,
12015        window: &mut Window,
12016        cx: &mut Context<Self>,
12017    ) {
12018        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12019        self.transact(window, cx, |this, window, cx| {
12020            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12021                s.move_with(|map, selection| {
12022                    if selection.is_empty() {
12023                        let cursor = if action.ignore_newlines {
12024                            movement::next_word_end(map, selection.head())
12025                        } else {
12026                            movement::next_word_end_or_newline(map, selection.head())
12027                        };
12028                        selection.set_head(cursor, SelectionGoal::None);
12029                    }
12030                });
12031            });
12032            this.insert("", window, cx);
12033        });
12034    }
12035
12036    pub fn delete_to_next_subword_end(
12037        &mut self,
12038        _: &DeleteToNextSubwordEnd,
12039        window: &mut Window,
12040        cx: &mut Context<Self>,
12041    ) {
12042        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12043        self.transact(window, cx, |this, window, cx| {
12044            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12045                s.move_with(|map, selection| {
12046                    if selection.is_empty() {
12047                        let cursor = movement::next_subword_end(map, selection.head());
12048                        selection.set_head(cursor, SelectionGoal::None);
12049                    }
12050                });
12051            });
12052            this.insert("", window, cx);
12053        });
12054    }
12055
12056    pub fn move_to_beginning_of_line(
12057        &mut self,
12058        action: &MoveToBeginningOfLine,
12059        window: &mut Window,
12060        cx: &mut Context<Self>,
12061    ) {
12062        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12063        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12064            s.move_cursors_with(|map, head, _| {
12065                (
12066                    movement::indented_line_beginning(
12067                        map,
12068                        head,
12069                        action.stop_at_soft_wraps,
12070                        action.stop_at_indent,
12071                    ),
12072                    SelectionGoal::None,
12073                )
12074            });
12075        })
12076    }
12077
12078    pub fn select_to_beginning_of_line(
12079        &mut self,
12080        action: &SelectToBeginningOfLine,
12081        window: &mut Window,
12082        cx: &mut Context<Self>,
12083    ) {
12084        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12085        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12086            s.move_heads_with(|map, head, _| {
12087                (
12088                    movement::indented_line_beginning(
12089                        map,
12090                        head,
12091                        action.stop_at_soft_wraps,
12092                        action.stop_at_indent,
12093                    ),
12094                    SelectionGoal::None,
12095                )
12096            });
12097        });
12098    }
12099
12100    pub fn delete_to_beginning_of_line(
12101        &mut self,
12102        action: &DeleteToBeginningOfLine,
12103        window: &mut Window,
12104        cx: &mut Context<Self>,
12105    ) {
12106        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12107        self.transact(window, cx, |this, window, cx| {
12108            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12109                s.move_with(|_, selection| {
12110                    selection.reversed = true;
12111                });
12112            });
12113
12114            this.select_to_beginning_of_line(
12115                &SelectToBeginningOfLine {
12116                    stop_at_soft_wraps: false,
12117                    stop_at_indent: action.stop_at_indent,
12118                },
12119                window,
12120                cx,
12121            );
12122            this.backspace(&Backspace, window, cx);
12123        });
12124    }
12125
12126    pub fn move_to_end_of_line(
12127        &mut self,
12128        action: &MoveToEndOfLine,
12129        window: &mut Window,
12130        cx: &mut Context<Self>,
12131    ) {
12132        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12133        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12134            s.move_cursors_with(|map, head, _| {
12135                (
12136                    movement::line_end(map, head, action.stop_at_soft_wraps),
12137                    SelectionGoal::None,
12138                )
12139            });
12140        })
12141    }
12142
12143    pub fn select_to_end_of_line(
12144        &mut self,
12145        action: &SelectToEndOfLine,
12146        window: &mut Window,
12147        cx: &mut Context<Self>,
12148    ) {
12149        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12150        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12151            s.move_heads_with(|map, head, _| {
12152                (
12153                    movement::line_end(map, head, action.stop_at_soft_wraps),
12154                    SelectionGoal::None,
12155                )
12156            });
12157        })
12158    }
12159
12160    pub fn delete_to_end_of_line(
12161        &mut self,
12162        _: &DeleteToEndOfLine,
12163        window: &mut Window,
12164        cx: &mut Context<Self>,
12165    ) {
12166        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12167        self.transact(window, cx, |this, window, cx| {
12168            this.select_to_end_of_line(
12169                &SelectToEndOfLine {
12170                    stop_at_soft_wraps: false,
12171                },
12172                window,
12173                cx,
12174            );
12175            this.delete(&Delete, window, cx);
12176        });
12177    }
12178
12179    pub fn cut_to_end_of_line(
12180        &mut self,
12181        _: &CutToEndOfLine,
12182        window: &mut Window,
12183        cx: &mut Context<Self>,
12184    ) {
12185        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
12186        self.transact(window, cx, |this, window, cx| {
12187            this.select_to_end_of_line(
12188                &SelectToEndOfLine {
12189                    stop_at_soft_wraps: false,
12190                },
12191                window,
12192                cx,
12193            );
12194            this.cut(&Cut, window, cx);
12195        });
12196    }
12197
12198    pub fn move_to_start_of_paragraph(
12199        &mut self,
12200        _: &MoveToStartOfParagraph,
12201        window: &mut Window,
12202        cx: &mut Context<Self>,
12203    ) {
12204        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12205            cx.propagate();
12206            return;
12207        }
12208        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12209        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12210            s.move_with(|map, selection| {
12211                selection.collapse_to(
12212                    movement::start_of_paragraph(map, selection.head(), 1),
12213                    SelectionGoal::None,
12214                )
12215            });
12216        })
12217    }
12218
12219    pub fn move_to_end_of_paragraph(
12220        &mut self,
12221        _: &MoveToEndOfParagraph,
12222        window: &mut Window,
12223        cx: &mut Context<Self>,
12224    ) {
12225        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12226            cx.propagate();
12227            return;
12228        }
12229        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12230        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12231            s.move_with(|map, selection| {
12232                selection.collapse_to(
12233                    movement::end_of_paragraph(map, selection.head(), 1),
12234                    SelectionGoal::None,
12235                )
12236            });
12237        })
12238    }
12239
12240    pub fn select_to_start_of_paragraph(
12241        &mut self,
12242        _: &SelectToStartOfParagraph,
12243        window: &mut Window,
12244        cx: &mut Context<Self>,
12245    ) {
12246        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12247            cx.propagate();
12248            return;
12249        }
12250        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12251        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12252            s.move_heads_with(|map, head, _| {
12253                (
12254                    movement::start_of_paragraph(map, head, 1),
12255                    SelectionGoal::None,
12256                )
12257            });
12258        })
12259    }
12260
12261    pub fn select_to_end_of_paragraph(
12262        &mut self,
12263        _: &SelectToEndOfParagraph,
12264        window: &mut Window,
12265        cx: &mut Context<Self>,
12266    ) {
12267        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12268            cx.propagate();
12269            return;
12270        }
12271        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12272        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12273            s.move_heads_with(|map, head, _| {
12274                (
12275                    movement::end_of_paragraph(map, head, 1),
12276                    SelectionGoal::None,
12277                )
12278            });
12279        })
12280    }
12281
12282    pub fn move_to_start_of_excerpt(
12283        &mut self,
12284        _: &MoveToStartOfExcerpt,
12285        window: &mut Window,
12286        cx: &mut Context<Self>,
12287    ) {
12288        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12289            cx.propagate();
12290            return;
12291        }
12292        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12293        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12294            s.move_with(|map, selection| {
12295                selection.collapse_to(
12296                    movement::start_of_excerpt(
12297                        map,
12298                        selection.head(),
12299                        workspace::searchable::Direction::Prev,
12300                    ),
12301                    SelectionGoal::None,
12302                )
12303            });
12304        })
12305    }
12306
12307    pub fn move_to_start_of_next_excerpt(
12308        &mut self,
12309        _: &MoveToStartOfNextExcerpt,
12310        window: &mut Window,
12311        cx: &mut Context<Self>,
12312    ) {
12313        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12314            cx.propagate();
12315            return;
12316        }
12317
12318        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12319            s.move_with(|map, selection| {
12320                selection.collapse_to(
12321                    movement::start_of_excerpt(
12322                        map,
12323                        selection.head(),
12324                        workspace::searchable::Direction::Next,
12325                    ),
12326                    SelectionGoal::None,
12327                )
12328            });
12329        })
12330    }
12331
12332    pub fn move_to_end_of_excerpt(
12333        &mut self,
12334        _: &MoveToEndOfExcerpt,
12335        window: &mut Window,
12336        cx: &mut Context<Self>,
12337    ) {
12338        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12339            cx.propagate();
12340            return;
12341        }
12342        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12343        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12344            s.move_with(|map, selection| {
12345                selection.collapse_to(
12346                    movement::end_of_excerpt(
12347                        map,
12348                        selection.head(),
12349                        workspace::searchable::Direction::Next,
12350                    ),
12351                    SelectionGoal::None,
12352                )
12353            });
12354        })
12355    }
12356
12357    pub fn move_to_end_of_previous_excerpt(
12358        &mut self,
12359        _: &MoveToEndOfPreviousExcerpt,
12360        window: &mut Window,
12361        cx: &mut Context<Self>,
12362    ) {
12363        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12364            cx.propagate();
12365            return;
12366        }
12367        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12368        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12369            s.move_with(|map, selection| {
12370                selection.collapse_to(
12371                    movement::end_of_excerpt(
12372                        map,
12373                        selection.head(),
12374                        workspace::searchable::Direction::Prev,
12375                    ),
12376                    SelectionGoal::None,
12377                )
12378            });
12379        })
12380    }
12381
12382    pub fn select_to_start_of_excerpt(
12383        &mut self,
12384        _: &SelectToStartOfExcerpt,
12385        window: &mut Window,
12386        cx: &mut Context<Self>,
12387    ) {
12388        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12389            cx.propagate();
12390            return;
12391        }
12392        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12393        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12394            s.move_heads_with(|map, head, _| {
12395                (
12396                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12397                    SelectionGoal::None,
12398                )
12399            });
12400        })
12401    }
12402
12403    pub fn select_to_start_of_next_excerpt(
12404        &mut self,
12405        _: &SelectToStartOfNextExcerpt,
12406        window: &mut Window,
12407        cx: &mut Context<Self>,
12408    ) {
12409        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12410            cx.propagate();
12411            return;
12412        }
12413        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12414        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12415            s.move_heads_with(|map, head, _| {
12416                (
12417                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
12418                    SelectionGoal::None,
12419                )
12420            });
12421        })
12422    }
12423
12424    pub fn select_to_end_of_excerpt(
12425        &mut self,
12426        _: &SelectToEndOfExcerpt,
12427        window: &mut Window,
12428        cx: &mut Context<Self>,
12429    ) {
12430        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12431            cx.propagate();
12432            return;
12433        }
12434        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12435        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12436            s.move_heads_with(|map, head, _| {
12437                (
12438                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
12439                    SelectionGoal::None,
12440                )
12441            });
12442        })
12443    }
12444
12445    pub fn select_to_end_of_previous_excerpt(
12446        &mut self,
12447        _: &SelectToEndOfPreviousExcerpt,
12448        window: &mut Window,
12449        cx: &mut Context<Self>,
12450    ) {
12451        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12452            cx.propagate();
12453            return;
12454        }
12455        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12456        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12457            s.move_heads_with(|map, head, _| {
12458                (
12459                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
12460                    SelectionGoal::None,
12461                )
12462            });
12463        })
12464    }
12465
12466    pub fn move_to_beginning(
12467        &mut self,
12468        _: &MoveToBeginning,
12469        window: &mut Window,
12470        cx: &mut Context<Self>,
12471    ) {
12472        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12473            cx.propagate();
12474            return;
12475        }
12476        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12477        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12478            s.select_ranges(vec![0..0]);
12479        });
12480    }
12481
12482    pub fn select_to_beginning(
12483        &mut self,
12484        _: &SelectToBeginning,
12485        window: &mut Window,
12486        cx: &mut Context<Self>,
12487    ) {
12488        let mut selection = self.selections.last::<Point>(cx);
12489        selection.set_head(Point::zero(), SelectionGoal::None);
12490        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12491        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12492            s.select(vec![selection]);
12493        });
12494    }
12495
12496    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
12497        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12498            cx.propagate();
12499            return;
12500        }
12501        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12502        let cursor = self.buffer.read(cx).read(cx).len();
12503        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12504            s.select_ranges(vec![cursor..cursor])
12505        });
12506    }
12507
12508    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
12509        self.nav_history = nav_history;
12510    }
12511
12512    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
12513        self.nav_history.as_ref()
12514    }
12515
12516    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
12517        self.push_to_nav_history(self.selections.newest_anchor().head(), None, false, cx);
12518    }
12519
12520    fn push_to_nav_history(
12521        &mut self,
12522        cursor_anchor: Anchor,
12523        new_position: Option<Point>,
12524        is_deactivate: bool,
12525        cx: &mut Context<Self>,
12526    ) {
12527        if let Some(nav_history) = self.nav_history.as_mut() {
12528            let buffer = self.buffer.read(cx).read(cx);
12529            let cursor_position = cursor_anchor.to_point(&buffer);
12530            let scroll_state = self.scroll_manager.anchor();
12531            let scroll_top_row = scroll_state.top_row(&buffer);
12532            drop(buffer);
12533
12534            if let Some(new_position) = new_position {
12535                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
12536                if row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA {
12537                    return;
12538                }
12539            }
12540
12541            nav_history.push(
12542                Some(NavigationData {
12543                    cursor_anchor,
12544                    cursor_position,
12545                    scroll_anchor: scroll_state,
12546                    scroll_top_row,
12547                }),
12548                cx,
12549            );
12550            cx.emit(EditorEvent::PushedToNavHistory {
12551                anchor: cursor_anchor,
12552                is_deactivate,
12553            })
12554        }
12555    }
12556
12557    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
12558        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12559        let buffer = self.buffer.read(cx).snapshot(cx);
12560        let mut selection = self.selections.first::<usize>(cx);
12561        selection.set_head(buffer.len(), SelectionGoal::None);
12562        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12563            s.select(vec![selection]);
12564        });
12565    }
12566
12567    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
12568        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12569        let end = self.buffer.read(cx).read(cx).len();
12570        self.change_selections(None, window, cx, |s| {
12571            s.select_ranges(vec![0..end]);
12572        });
12573    }
12574
12575    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
12576        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12577        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12578        let mut selections = self.selections.all::<Point>(cx);
12579        let max_point = display_map.buffer_snapshot.max_point();
12580        for selection in &mut selections {
12581            let rows = selection.spanned_rows(true, &display_map);
12582            selection.start = Point::new(rows.start.0, 0);
12583            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
12584            selection.reversed = false;
12585        }
12586        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12587            s.select(selections);
12588        });
12589    }
12590
12591    pub fn split_selection_into_lines(
12592        &mut self,
12593        _: &SplitSelectionIntoLines,
12594        window: &mut Window,
12595        cx: &mut Context<Self>,
12596    ) {
12597        let selections = self
12598            .selections
12599            .all::<Point>(cx)
12600            .into_iter()
12601            .map(|selection| selection.start..selection.end)
12602            .collect::<Vec<_>>();
12603        self.unfold_ranges(&selections, true, true, cx);
12604
12605        let mut new_selection_ranges = Vec::new();
12606        {
12607            let buffer = self.buffer.read(cx).read(cx);
12608            for selection in selections {
12609                for row in selection.start.row..selection.end.row {
12610                    let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12611                    new_selection_ranges.push(cursor..cursor);
12612                }
12613
12614                let is_multiline_selection = selection.start.row != selection.end.row;
12615                // Don't insert last one if it's a multi-line selection ending at the start of a line,
12616                // so this action feels more ergonomic when paired with other selection operations
12617                let should_skip_last = is_multiline_selection && selection.end.column == 0;
12618                if !should_skip_last {
12619                    new_selection_ranges.push(selection.end..selection.end);
12620                }
12621            }
12622        }
12623        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12624            s.select_ranges(new_selection_ranges);
12625        });
12626    }
12627
12628    pub fn add_selection_above(
12629        &mut self,
12630        _: &AddSelectionAbove,
12631        window: &mut Window,
12632        cx: &mut Context<Self>,
12633    ) {
12634        self.add_selection(true, window, cx);
12635    }
12636
12637    pub fn add_selection_below(
12638        &mut self,
12639        _: &AddSelectionBelow,
12640        window: &mut Window,
12641        cx: &mut Context<Self>,
12642    ) {
12643        self.add_selection(false, window, cx);
12644    }
12645
12646    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
12647        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12648
12649        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12650        let mut selections = self.selections.all::<Point>(cx);
12651        let text_layout_details = self.text_layout_details(window);
12652        let mut state = self.add_selections_state.take().unwrap_or_else(|| {
12653            let oldest_selection = selections.iter().min_by_key(|s| s.id).unwrap().clone();
12654            let range = oldest_selection.display_range(&display_map).sorted();
12655
12656            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
12657            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
12658            let positions = start_x.min(end_x)..start_x.max(end_x);
12659
12660            selections.clear();
12661            let mut stack = Vec::new();
12662            for row in range.start.row().0..=range.end.row().0 {
12663                if let Some(selection) = self.selections.build_columnar_selection(
12664                    &display_map,
12665                    DisplayRow(row),
12666                    &positions,
12667                    oldest_selection.reversed,
12668                    &text_layout_details,
12669                ) {
12670                    stack.push(selection.id);
12671                    selections.push(selection);
12672                }
12673            }
12674
12675            if above {
12676                stack.reverse();
12677            }
12678
12679            AddSelectionsState { above, stack }
12680        });
12681
12682        let last_added_selection = *state.stack.last().unwrap();
12683        let mut new_selections = Vec::new();
12684        if above == state.above {
12685            let end_row = if above {
12686                DisplayRow(0)
12687            } else {
12688                display_map.max_point().row()
12689            };
12690
12691            'outer: for selection in selections {
12692                if selection.id == last_added_selection {
12693                    let range = selection.display_range(&display_map).sorted();
12694                    debug_assert_eq!(range.start.row(), range.end.row());
12695                    let mut row = range.start.row();
12696                    let positions =
12697                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
12698                            px(start)..px(end)
12699                        } else {
12700                            let start_x =
12701                                display_map.x_for_display_point(range.start, &text_layout_details);
12702                            let end_x =
12703                                display_map.x_for_display_point(range.end, &text_layout_details);
12704                            start_x.min(end_x)..start_x.max(end_x)
12705                        };
12706
12707                    while row != end_row {
12708                        if above {
12709                            row.0 -= 1;
12710                        } else {
12711                            row.0 += 1;
12712                        }
12713
12714                        if let Some(new_selection) = self.selections.build_columnar_selection(
12715                            &display_map,
12716                            row,
12717                            &positions,
12718                            selection.reversed,
12719                            &text_layout_details,
12720                        ) {
12721                            state.stack.push(new_selection.id);
12722                            if above {
12723                                new_selections.push(new_selection);
12724                                new_selections.push(selection);
12725                            } else {
12726                                new_selections.push(selection);
12727                                new_selections.push(new_selection);
12728                            }
12729
12730                            continue 'outer;
12731                        }
12732                    }
12733                }
12734
12735                new_selections.push(selection);
12736            }
12737        } else {
12738            new_selections = selections;
12739            new_selections.retain(|s| s.id != last_added_selection);
12740            state.stack.pop();
12741        }
12742
12743        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
12744            s.select(new_selections);
12745        });
12746        if state.stack.len() > 1 {
12747            self.add_selections_state = Some(state);
12748        }
12749    }
12750
12751    fn select_match_ranges(
12752        &mut self,
12753        range: Range<usize>,
12754        reversed: bool,
12755        replace_newest: bool,
12756        auto_scroll: Option<Autoscroll>,
12757        window: &mut Window,
12758        cx: &mut Context<Editor>,
12759    ) {
12760        self.unfold_ranges(&[range.clone()], false, auto_scroll.is_some(), cx);
12761        self.change_selections(auto_scroll, window, cx, |s| {
12762            if replace_newest {
12763                s.delete(s.newest_anchor().id);
12764            }
12765            if reversed {
12766                s.insert_range(range.end..range.start);
12767            } else {
12768                s.insert_range(range);
12769            }
12770        });
12771    }
12772
12773    pub fn select_next_match_internal(
12774        &mut self,
12775        display_map: &DisplaySnapshot,
12776        replace_newest: bool,
12777        autoscroll: Option<Autoscroll>,
12778        window: &mut Window,
12779        cx: &mut Context<Self>,
12780    ) -> Result<()> {
12781        let buffer = &display_map.buffer_snapshot;
12782        let mut selections = self.selections.all::<usize>(cx);
12783        if let Some(mut select_next_state) = self.select_next_state.take() {
12784            let query = &select_next_state.query;
12785            if !select_next_state.done {
12786                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
12787                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
12788                let mut next_selected_range = None;
12789
12790                let bytes_after_last_selection =
12791                    buffer.bytes_in_range(last_selection.end..buffer.len());
12792                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
12793                let query_matches = query
12794                    .stream_find_iter(bytes_after_last_selection)
12795                    .map(|result| (last_selection.end, result))
12796                    .chain(
12797                        query
12798                            .stream_find_iter(bytes_before_first_selection)
12799                            .map(|result| (0, result)),
12800                    );
12801
12802                for (start_offset, query_match) in query_matches {
12803                    let query_match = query_match.unwrap(); // can only fail due to I/O
12804                    let offset_range =
12805                        start_offset + query_match.start()..start_offset + query_match.end();
12806                    let display_range = offset_range.start.to_display_point(display_map)
12807                        ..offset_range.end.to_display_point(display_map);
12808
12809                    if !select_next_state.wordwise
12810                        || (!movement::is_inside_word(display_map, display_range.start)
12811                            && !movement::is_inside_word(display_map, display_range.end))
12812                    {
12813                        // TODO: This is n^2, because we might check all the selections
12814                        if !selections
12815                            .iter()
12816                            .any(|selection| selection.range().overlaps(&offset_range))
12817                        {
12818                            next_selected_range = Some(offset_range);
12819                            break;
12820                        }
12821                    }
12822                }
12823
12824                if let Some(next_selected_range) = next_selected_range {
12825                    self.select_match_ranges(
12826                        next_selected_range,
12827                        last_selection.reversed,
12828                        replace_newest,
12829                        autoscroll,
12830                        window,
12831                        cx,
12832                    );
12833                } else {
12834                    select_next_state.done = true;
12835                }
12836            }
12837
12838            self.select_next_state = Some(select_next_state);
12839        } else {
12840            let mut only_carets = true;
12841            let mut same_text_selected = true;
12842            let mut selected_text = None;
12843
12844            let mut selections_iter = selections.iter().peekable();
12845            while let Some(selection) = selections_iter.next() {
12846                if selection.start != selection.end {
12847                    only_carets = false;
12848                }
12849
12850                if same_text_selected {
12851                    if selected_text.is_none() {
12852                        selected_text =
12853                            Some(buffer.text_for_range(selection.range()).collect::<String>());
12854                    }
12855
12856                    if let Some(next_selection) = selections_iter.peek() {
12857                        if next_selection.range().len() == selection.range().len() {
12858                            let next_selected_text = buffer
12859                                .text_for_range(next_selection.range())
12860                                .collect::<String>();
12861                            if Some(next_selected_text) != selected_text {
12862                                same_text_selected = false;
12863                                selected_text = None;
12864                            }
12865                        } else {
12866                            same_text_selected = false;
12867                            selected_text = None;
12868                        }
12869                    }
12870                }
12871            }
12872
12873            if only_carets {
12874                for selection in &mut selections {
12875                    let word_range = movement::surrounding_word(
12876                        display_map,
12877                        selection.start.to_display_point(display_map),
12878                    );
12879                    selection.start = word_range.start.to_offset(display_map, Bias::Left);
12880                    selection.end = word_range.end.to_offset(display_map, Bias::Left);
12881                    selection.goal = SelectionGoal::None;
12882                    selection.reversed = false;
12883                    self.select_match_ranges(
12884                        selection.start..selection.end,
12885                        selection.reversed,
12886                        replace_newest,
12887                        autoscroll,
12888                        window,
12889                        cx,
12890                    );
12891                }
12892
12893                if selections.len() == 1 {
12894                    let selection = selections
12895                        .last()
12896                        .expect("ensured that there's only one selection");
12897                    let query = buffer
12898                        .text_for_range(selection.start..selection.end)
12899                        .collect::<String>();
12900                    let is_empty = query.is_empty();
12901                    let select_state = SelectNextState {
12902                        query: AhoCorasick::new(&[query])?,
12903                        wordwise: true,
12904                        done: is_empty,
12905                    };
12906                    self.select_next_state = Some(select_state);
12907                } else {
12908                    self.select_next_state = None;
12909                }
12910            } else if let Some(selected_text) = selected_text {
12911                self.select_next_state = Some(SelectNextState {
12912                    query: AhoCorasick::new(&[selected_text])?,
12913                    wordwise: false,
12914                    done: false,
12915                });
12916                self.select_next_match_internal(
12917                    display_map,
12918                    replace_newest,
12919                    autoscroll,
12920                    window,
12921                    cx,
12922                )?;
12923            }
12924        }
12925        Ok(())
12926    }
12927
12928    pub fn select_all_matches(
12929        &mut self,
12930        _action: &SelectAllMatches,
12931        window: &mut Window,
12932        cx: &mut Context<Self>,
12933    ) -> Result<()> {
12934        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12935
12936        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12937
12938        self.select_next_match_internal(&display_map, false, None, window, cx)?;
12939        let Some(select_next_state) = self.select_next_state.as_mut() else {
12940            return Ok(());
12941        };
12942        if select_next_state.done {
12943            return Ok(());
12944        }
12945
12946        let mut new_selections = Vec::new();
12947
12948        let reversed = self.selections.oldest::<usize>(cx).reversed;
12949        let buffer = &display_map.buffer_snapshot;
12950        let query_matches = select_next_state
12951            .query
12952            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
12953
12954        for query_match in query_matches.into_iter() {
12955            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
12956            let offset_range = if reversed {
12957                query_match.end()..query_match.start()
12958            } else {
12959                query_match.start()..query_match.end()
12960            };
12961            let display_range = offset_range.start.to_display_point(&display_map)
12962                ..offset_range.end.to_display_point(&display_map);
12963
12964            if !select_next_state.wordwise
12965                || (!movement::is_inside_word(&display_map, display_range.start)
12966                    && !movement::is_inside_word(&display_map, display_range.end))
12967            {
12968                new_selections.push(offset_range.start..offset_range.end);
12969            }
12970        }
12971
12972        select_next_state.done = true;
12973        self.unfold_ranges(&new_selections.clone(), false, false, cx);
12974        self.change_selections(None, window, cx, |selections| {
12975            selections.select_ranges(new_selections)
12976        });
12977
12978        Ok(())
12979    }
12980
12981    pub fn select_next(
12982        &mut self,
12983        action: &SelectNext,
12984        window: &mut Window,
12985        cx: &mut Context<Self>,
12986    ) -> Result<()> {
12987        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
12988        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12989        self.select_next_match_internal(
12990            &display_map,
12991            action.replace_newest,
12992            Some(Autoscroll::newest()),
12993            window,
12994            cx,
12995        )?;
12996        Ok(())
12997    }
12998
12999    pub fn select_previous(
13000        &mut self,
13001        action: &SelectPrevious,
13002        window: &mut Window,
13003        cx: &mut Context<Self>,
13004    ) -> Result<()> {
13005        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13006        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13007        let buffer = &display_map.buffer_snapshot;
13008        let mut selections = self.selections.all::<usize>(cx);
13009        if let Some(mut select_prev_state) = self.select_prev_state.take() {
13010            let query = &select_prev_state.query;
13011            if !select_prev_state.done {
13012                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13013                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13014                let mut next_selected_range = None;
13015                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
13016                let bytes_before_last_selection =
13017                    buffer.reversed_bytes_in_range(0..last_selection.start);
13018                let bytes_after_first_selection =
13019                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
13020                let query_matches = query
13021                    .stream_find_iter(bytes_before_last_selection)
13022                    .map(|result| (last_selection.start, result))
13023                    .chain(
13024                        query
13025                            .stream_find_iter(bytes_after_first_selection)
13026                            .map(|result| (buffer.len(), result)),
13027                    );
13028                for (end_offset, query_match) in query_matches {
13029                    let query_match = query_match.unwrap(); // can only fail due to I/O
13030                    let offset_range =
13031                        end_offset - query_match.end()..end_offset - query_match.start();
13032                    let display_range = offset_range.start.to_display_point(&display_map)
13033                        ..offset_range.end.to_display_point(&display_map);
13034
13035                    if !select_prev_state.wordwise
13036                        || (!movement::is_inside_word(&display_map, display_range.start)
13037                            && !movement::is_inside_word(&display_map, display_range.end))
13038                    {
13039                        next_selected_range = Some(offset_range);
13040                        break;
13041                    }
13042                }
13043
13044                if let Some(next_selected_range) = next_selected_range {
13045                    self.select_match_ranges(
13046                        next_selected_range,
13047                        last_selection.reversed,
13048                        action.replace_newest,
13049                        Some(Autoscroll::newest()),
13050                        window,
13051                        cx,
13052                    );
13053                } else {
13054                    select_prev_state.done = true;
13055                }
13056            }
13057
13058            self.select_prev_state = Some(select_prev_state);
13059        } else {
13060            let mut only_carets = true;
13061            let mut same_text_selected = true;
13062            let mut selected_text = None;
13063
13064            let mut selections_iter = selections.iter().peekable();
13065            while let Some(selection) = selections_iter.next() {
13066                if selection.start != selection.end {
13067                    only_carets = false;
13068                }
13069
13070                if same_text_selected {
13071                    if selected_text.is_none() {
13072                        selected_text =
13073                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13074                    }
13075
13076                    if let Some(next_selection) = selections_iter.peek() {
13077                        if next_selection.range().len() == selection.range().len() {
13078                            let next_selected_text = buffer
13079                                .text_for_range(next_selection.range())
13080                                .collect::<String>();
13081                            if Some(next_selected_text) != selected_text {
13082                                same_text_selected = false;
13083                                selected_text = None;
13084                            }
13085                        } else {
13086                            same_text_selected = false;
13087                            selected_text = None;
13088                        }
13089                    }
13090                }
13091            }
13092
13093            if only_carets {
13094                for selection in &mut selections {
13095                    let word_range = movement::surrounding_word(
13096                        &display_map,
13097                        selection.start.to_display_point(&display_map),
13098                    );
13099                    selection.start = word_range.start.to_offset(&display_map, Bias::Left);
13100                    selection.end = word_range.end.to_offset(&display_map, Bias::Left);
13101                    selection.goal = SelectionGoal::None;
13102                    selection.reversed = false;
13103                    self.select_match_ranges(
13104                        selection.start..selection.end,
13105                        selection.reversed,
13106                        action.replace_newest,
13107                        Some(Autoscroll::newest()),
13108                        window,
13109                        cx,
13110                    );
13111                }
13112                if selections.len() == 1 {
13113                    let selection = selections
13114                        .last()
13115                        .expect("ensured that there's only one selection");
13116                    let query = buffer
13117                        .text_for_range(selection.start..selection.end)
13118                        .collect::<String>();
13119                    let is_empty = query.is_empty();
13120                    let select_state = SelectNextState {
13121                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
13122                        wordwise: true,
13123                        done: is_empty,
13124                    };
13125                    self.select_prev_state = Some(select_state);
13126                } else {
13127                    self.select_prev_state = None;
13128                }
13129            } else if let Some(selected_text) = selected_text {
13130                self.select_prev_state = Some(SelectNextState {
13131                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
13132                    wordwise: false,
13133                    done: false,
13134                });
13135                self.select_previous(action, window, cx)?;
13136            }
13137        }
13138        Ok(())
13139    }
13140
13141    pub fn find_next_match(
13142        &mut self,
13143        _: &FindNextMatch,
13144        window: &mut Window,
13145        cx: &mut Context<Self>,
13146    ) -> Result<()> {
13147        let selections = self.selections.disjoint_anchors();
13148        match selections.first() {
13149            Some(first) if selections.len() >= 2 => {
13150                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13151                    s.select_ranges([first.range()]);
13152                });
13153            }
13154            _ => self.select_next(
13155                &SelectNext {
13156                    replace_newest: true,
13157                },
13158                window,
13159                cx,
13160            )?,
13161        }
13162        Ok(())
13163    }
13164
13165    pub fn find_previous_match(
13166        &mut self,
13167        _: &FindPreviousMatch,
13168        window: &mut Window,
13169        cx: &mut Context<Self>,
13170    ) -> Result<()> {
13171        let selections = self.selections.disjoint_anchors();
13172        match selections.last() {
13173            Some(last) if selections.len() >= 2 => {
13174                self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13175                    s.select_ranges([last.range()]);
13176                });
13177            }
13178            _ => self.select_previous(
13179                &SelectPrevious {
13180                    replace_newest: true,
13181                },
13182                window,
13183                cx,
13184            )?,
13185        }
13186        Ok(())
13187    }
13188
13189    pub fn toggle_comments(
13190        &mut self,
13191        action: &ToggleComments,
13192        window: &mut Window,
13193        cx: &mut Context<Self>,
13194    ) {
13195        if self.read_only(cx) {
13196            return;
13197        }
13198        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
13199        let text_layout_details = &self.text_layout_details(window);
13200        self.transact(window, cx, |this, window, cx| {
13201            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
13202            let mut edits = Vec::new();
13203            let mut selection_edit_ranges = Vec::new();
13204            let mut last_toggled_row = None;
13205            let snapshot = this.buffer.read(cx).read(cx);
13206            let empty_str: Arc<str> = Arc::default();
13207            let mut suffixes_inserted = Vec::new();
13208            let ignore_indent = action.ignore_indent;
13209
13210            fn comment_prefix_range(
13211                snapshot: &MultiBufferSnapshot,
13212                row: MultiBufferRow,
13213                comment_prefix: &str,
13214                comment_prefix_whitespace: &str,
13215                ignore_indent: bool,
13216            ) -> Range<Point> {
13217                let indent_size = if ignore_indent {
13218                    0
13219                } else {
13220                    snapshot.indent_size_for_line(row).len
13221                };
13222
13223                let start = Point::new(row.0, indent_size);
13224
13225                let mut line_bytes = snapshot
13226                    .bytes_in_range(start..snapshot.max_point())
13227                    .flatten()
13228                    .copied();
13229
13230                // If this line currently begins with the line comment prefix, then record
13231                // the range containing the prefix.
13232                if line_bytes
13233                    .by_ref()
13234                    .take(comment_prefix.len())
13235                    .eq(comment_prefix.bytes())
13236                {
13237                    // Include any whitespace that matches the comment prefix.
13238                    let matching_whitespace_len = line_bytes
13239                        .zip(comment_prefix_whitespace.bytes())
13240                        .take_while(|(a, b)| a == b)
13241                        .count() as u32;
13242                    let end = Point::new(
13243                        start.row,
13244                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
13245                    );
13246                    start..end
13247                } else {
13248                    start..start
13249                }
13250            }
13251
13252            fn comment_suffix_range(
13253                snapshot: &MultiBufferSnapshot,
13254                row: MultiBufferRow,
13255                comment_suffix: &str,
13256                comment_suffix_has_leading_space: bool,
13257            ) -> Range<Point> {
13258                let end = Point::new(row.0, snapshot.line_len(row));
13259                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
13260
13261                let mut line_end_bytes = snapshot
13262                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
13263                    .flatten()
13264                    .copied();
13265
13266                let leading_space_len = if suffix_start_column > 0
13267                    && line_end_bytes.next() == Some(b' ')
13268                    && comment_suffix_has_leading_space
13269                {
13270                    1
13271                } else {
13272                    0
13273                };
13274
13275                // If this line currently begins with the line comment prefix, then record
13276                // the range containing the prefix.
13277                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
13278                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
13279                    start..end
13280                } else {
13281                    end..end
13282                }
13283            }
13284
13285            // TODO: Handle selections that cross excerpts
13286            for selection in &mut selections {
13287                let start_column = snapshot
13288                    .indent_size_for_line(MultiBufferRow(selection.start.row))
13289                    .len;
13290                let language = if let Some(language) =
13291                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
13292                {
13293                    language
13294                } else {
13295                    continue;
13296                };
13297
13298                selection_edit_ranges.clear();
13299
13300                // If multiple selections contain a given row, avoid processing that
13301                // row more than once.
13302                let mut start_row = MultiBufferRow(selection.start.row);
13303                if last_toggled_row == Some(start_row) {
13304                    start_row = start_row.next_row();
13305                }
13306                let end_row =
13307                    if selection.end.row > selection.start.row && selection.end.column == 0 {
13308                        MultiBufferRow(selection.end.row - 1)
13309                    } else {
13310                        MultiBufferRow(selection.end.row)
13311                    };
13312                last_toggled_row = Some(end_row);
13313
13314                if start_row > end_row {
13315                    continue;
13316                }
13317
13318                // If the language has line comments, toggle those.
13319                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
13320
13321                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
13322                if ignore_indent {
13323                    full_comment_prefixes = full_comment_prefixes
13324                        .into_iter()
13325                        .map(|s| Arc::from(s.trim_end()))
13326                        .collect();
13327                }
13328
13329                if !full_comment_prefixes.is_empty() {
13330                    let first_prefix = full_comment_prefixes
13331                        .first()
13332                        .expect("prefixes is non-empty");
13333                    let prefix_trimmed_lengths = full_comment_prefixes
13334                        .iter()
13335                        .map(|p| p.trim_end_matches(' ').len())
13336                        .collect::<SmallVec<[usize; 4]>>();
13337
13338                    let mut all_selection_lines_are_comments = true;
13339
13340                    for row in start_row.0..=end_row.0 {
13341                        let row = MultiBufferRow(row);
13342                        if start_row < end_row && snapshot.is_line_blank(row) {
13343                            continue;
13344                        }
13345
13346                        let prefix_range = full_comment_prefixes
13347                            .iter()
13348                            .zip(prefix_trimmed_lengths.iter().copied())
13349                            .map(|(prefix, trimmed_prefix_len)| {
13350                                comment_prefix_range(
13351                                    snapshot.deref(),
13352                                    row,
13353                                    &prefix[..trimmed_prefix_len],
13354                                    &prefix[trimmed_prefix_len..],
13355                                    ignore_indent,
13356                                )
13357                            })
13358                            .max_by_key(|range| range.end.column - range.start.column)
13359                            .expect("prefixes is non-empty");
13360
13361                        if prefix_range.is_empty() {
13362                            all_selection_lines_are_comments = false;
13363                        }
13364
13365                        selection_edit_ranges.push(prefix_range);
13366                    }
13367
13368                    if all_selection_lines_are_comments {
13369                        edits.extend(
13370                            selection_edit_ranges
13371                                .iter()
13372                                .cloned()
13373                                .map(|range| (range, empty_str.clone())),
13374                        );
13375                    } else {
13376                        let min_column = selection_edit_ranges
13377                            .iter()
13378                            .map(|range| range.start.column)
13379                            .min()
13380                            .unwrap_or(0);
13381                        edits.extend(selection_edit_ranges.iter().map(|range| {
13382                            let position = Point::new(range.start.row, min_column);
13383                            (position..position, first_prefix.clone())
13384                        }));
13385                    }
13386                } else if let Some((full_comment_prefix, comment_suffix)) =
13387                    language.block_comment_delimiters()
13388                {
13389                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
13390                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
13391                    let prefix_range = comment_prefix_range(
13392                        snapshot.deref(),
13393                        start_row,
13394                        comment_prefix,
13395                        comment_prefix_whitespace,
13396                        ignore_indent,
13397                    );
13398                    let suffix_range = comment_suffix_range(
13399                        snapshot.deref(),
13400                        end_row,
13401                        comment_suffix.trim_start_matches(' '),
13402                        comment_suffix.starts_with(' '),
13403                    );
13404
13405                    if prefix_range.is_empty() || suffix_range.is_empty() {
13406                        edits.push((
13407                            prefix_range.start..prefix_range.start,
13408                            full_comment_prefix.clone(),
13409                        ));
13410                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
13411                        suffixes_inserted.push((end_row, comment_suffix.len()));
13412                    } else {
13413                        edits.push((prefix_range, empty_str.clone()));
13414                        edits.push((suffix_range, empty_str.clone()));
13415                    }
13416                } else {
13417                    continue;
13418                }
13419            }
13420
13421            drop(snapshot);
13422            this.buffer.update(cx, |buffer, cx| {
13423                buffer.edit(edits, None, cx);
13424            });
13425
13426            // Adjust selections so that they end before any comment suffixes that
13427            // were inserted.
13428            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
13429            let mut selections = this.selections.all::<Point>(cx);
13430            let snapshot = this.buffer.read(cx).read(cx);
13431            for selection in &mut selections {
13432                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
13433                    match row.cmp(&MultiBufferRow(selection.end.row)) {
13434                        Ordering::Less => {
13435                            suffixes_inserted.next();
13436                            continue;
13437                        }
13438                        Ordering::Greater => break,
13439                        Ordering::Equal => {
13440                            if selection.end.column == snapshot.line_len(row) {
13441                                if selection.is_empty() {
13442                                    selection.start.column -= suffix_len as u32;
13443                                }
13444                                selection.end.column -= suffix_len as u32;
13445                            }
13446                            break;
13447                        }
13448                    }
13449                }
13450            }
13451
13452            drop(snapshot);
13453            this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13454                s.select(selections)
13455            });
13456
13457            let selections = this.selections.all::<Point>(cx);
13458            let selections_on_single_row = selections.windows(2).all(|selections| {
13459                selections[0].start.row == selections[1].start.row
13460                    && selections[0].end.row == selections[1].end.row
13461                    && selections[0].start.row == selections[0].end.row
13462            });
13463            let selections_selecting = selections
13464                .iter()
13465                .any(|selection| selection.start != selection.end);
13466            let advance_downwards = action.advance_downwards
13467                && selections_on_single_row
13468                && !selections_selecting
13469                && !matches!(this.mode, EditorMode::SingleLine { .. });
13470
13471            if advance_downwards {
13472                let snapshot = this.buffer.read(cx).snapshot(cx);
13473
13474                this.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13475                    s.move_cursors_with(|display_snapshot, display_point, _| {
13476                        let mut point = display_point.to_point(display_snapshot);
13477                        point.row += 1;
13478                        point = snapshot.clip_point(point, Bias::Left);
13479                        let display_point = point.to_display_point(display_snapshot);
13480                        let goal = SelectionGoal::HorizontalPosition(
13481                            display_snapshot
13482                                .x_for_display_point(display_point, text_layout_details)
13483                                .into(),
13484                        );
13485                        (display_point, goal)
13486                    })
13487                });
13488            }
13489        });
13490    }
13491
13492    pub fn select_enclosing_symbol(
13493        &mut self,
13494        _: &SelectEnclosingSymbol,
13495        window: &mut Window,
13496        cx: &mut Context<Self>,
13497    ) {
13498        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13499
13500        let buffer = self.buffer.read(cx).snapshot(cx);
13501        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
13502
13503        fn update_selection(
13504            selection: &Selection<usize>,
13505            buffer_snap: &MultiBufferSnapshot,
13506        ) -> Option<Selection<usize>> {
13507            let cursor = selection.head();
13508            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
13509            for symbol in symbols.iter().rev() {
13510                let start = symbol.range.start.to_offset(buffer_snap);
13511                let end = symbol.range.end.to_offset(buffer_snap);
13512                let new_range = start..end;
13513                if start < selection.start || end > selection.end {
13514                    return Some(Selection {
13515                        id: selection.id,
13516                        start: new_range.start,
13517                        end: new_range.end,
13518                        goal: SelectionGoal::None,
13519                        reversed: selection.reversed,
13520                    });
13521                }
13522            }
13523            None
13524        }
13525
13526        let mut selected_larger_symbol = false;
13527        let new_selections = old_selections
13528            .iter()
13529            .map(|selection| match update_selection(selection, &buffer) {
13530                Some(new_selection) => {
13531                    if new_selection.range() != selection.range() {
13532                        selected_larger_symbol = true;
13533                    }
13534                    new_selection
13535                }
13536                None => selection.clone(),
13537            })
13538            .collect::<Vec<_>>();
13539
13540        if selected_larger_symbol {
13541            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13542                s.select(new_selections);
13543            });
13544        }
13545    }
13546
13547    pub fn select_larger_syntax_node(
13548        &mut self,
13549        _: &SelectLargerSyntaxNode,
13550        window: &mut Window,
13551        cx: &mut Context<Self>,
13552    ) {
13553        let Some(visible_row_count) = self.visible_row_count() else {
13554            return;
13555        };
13556        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
13557        if old_selections.is_empty() {
13558            return;
13559        }
13560
13561        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13562
13563        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13564        let buffer = self.buffer.read(cx).snapshot(cx);
13565
13566        let mut selected_larger_node = false;
13567        let mut new_selections = old_selections
13568            .iter()
13569            .map(|selection| {
13570                let old_range = selection.start..selection.end;
13571
13572                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
13573                    // manually select word at selection
13574                    if ["string_content", "inline"].contains(&node.kind()) {
13575                        let word_range = {
13576                            let display_point = buffer
13577                                .offset_to_point(old_range.start)
13578                                .to_display_point(&display_map);
13579                            let Range { start, end } =
13580                                movement::surrounding_word(&display_map, display_point);
13581                            start.to_point(&display_map).to_offset(&buffer)
13582                                ..end.to_point(&display_map).to_offset(&buffer)
13583                        };
13584                        // ignore if word is already selected
13585                        if !word_range.is_empty() && old_range != word_range {
13586                            let last_word_range = {
13587                                let display_point = buffer
13588                                    .offset_to_point(old_range.end)
13589                                    .to_display_point(&display_map);
13590                                let Range { start, end } =
13591                                    movement::surrounding_word(&display_map, display_point);
13592                                start.to_point(&display_map).to_offset(&buffer)
13593                                    ..end.to_point(&display_map).to_offset(&buffer)
13594                            };
13595                            // only select word if start and end point belongs to same word
13596                            if word_range == last_word_range {
13597                                selected_larger_node = true;
13598                                return Selection {
13599                                    id: selection.id,
13600                                    start: word_range.start,
13601                                    end: word_range.end,
13602                                    goal: SelectionGoal::None,
13603                                    reversed: selection.reversed,
13604                                };
13605                            }
13606                        }
13607                    }
13608                }
13609
13610                let mut new_range = old_range.clone();
13611                while let Some((_node, containing_range)) =
13612                    buffer.syntax_ancestor(new_range.clone())
13613                {
13614                    new_range = match containing_range {
13615                        MultiOrSingleBufferOffsetRange::Single(_) => break,
13616                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
13617                    };
13618                    if !display_map.intersects_fold(new_range.start)
13619                        && !display_map.intersects_fold(new_range.end)
13620                    {
13621                        break;
13622                    }
13623                }
13624
13625                selected_larger_node |= new_range != old_range;
13626                Selection {
13627                    id: selection.id,
13628                    start: new_range.start,
13629                    end: new_range.end,
13630                    goal: SelectionGoal::None,
13631                    reversed: selection.reversed,
13632                }
13633            })
13634            .collect::<Vec<_>>();
13635
13636        if !selected_larger_node {
13637            return; // don't put this call in the history
13638        }
13639
13640        // scroll based on transformation done to the last selection created by the user
13641        let (last_old, last_new) = old_selections
13642            .last()
13643            .zip(new_selections.last().cloned())
13644            .expect("old_selections isn't empty");
13645
13646        // revert selection
13647        let is_selection_reversed = {
13648            let should_newest_selection_be_reversed = last_old.start != last_new.start;
13649            new_selections.last_mut().expect("checked above").reversed =
13650                should_newest_selection_be_reversed;
13651            should_newest_selection_be_reversed
13652        };
13653
13654        if selected_larger_node {
13655            self.select_syntax_node_history.disable_clearing = true;
13656            self.change_selections(None, window, cx, |s| {
13657                s.select(new_selections.clone());
13658            });
13659            self.select_syntax_node_history.disable_clearing = false;
13660        }
13661
13662        let start_row = last_new.start.to_display_point(&display_map).row().0;
13663        let end_row = last_new.end.to_display_point(&display_map).row().0;
13664        let selection_height = end_row - start_row + 1;
13665        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
13666
13667        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
13668        let scroll_behavior = if fits_on_the_screen {
13669            self.request_autoscroll(Autoscroll::fit(), cx);
13670            SelectSyntaxNodeScrollBehavior::FitSelection
13671        } else if is_selection_reversed {
13672            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13673            SelectSyntaxNodeScrollBehavior::CursorTop
13674        } else {
13675            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13676            SelectSyntaxNodeScrollBehavior::CursorBottom
13677        };
13678
13679        self.select_syntax_node_history.push((
13680            old_selections,
13681            scroll_behavior,
13682            is_selection_reversed,
13683        ));
13684    }
13685
13686    pub fn select_smaller_syntax_node(
13687        &mut self,
13688        _: &SelectSmallerSyntaxNode,
13689        window: &mut Window,
13690        cx: &mut Context<Self>,
13691    ) {
13692        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13693
13694        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
13695            self.select_syntax_node_history.pop()
13696        {
13697            if let Some(selection) = selections.last_mut() {
13698                selection.reversed = is_selection_reversed;
13699            }
13700
13701            self.select_syntax_node_history.disable_clearing = true;
13702            self.change_selections(None, window, cx, |s| {
13703                s.select(selections.to_vec());
13704            });
13705            self.select_syntax_node_history.disable_clearing = false;
13706
13707            match scroll_behavior {
13708                SelectSyntaxNodeScrollBehavior::CursorTop => {
13709                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
13710                }
13711                SelectSyntaxNodeScrollBehavior::FitSelection => {
13712                    self.request_autoscroll(Autoscroll::fit(), cx);
13713                }
13714                SelectSyntaxNodeScrollBehavior::CursorBottom => {
13715                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
13716                }
13717            }
13718        }
13719    }
13720
13721    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
13722        if !EditorSettings::get_global(cx).gutter.runnables {
13723            self.clear_tasks();
13724            return Task::ready(());
13725        }
13726        let project = self.project.as_ref().map(Entity::downgrade);
13727        let task_sources = self.lsp_task_sources(cx);
13728        let multi_buffer = self.buffer.downgrade();
13729        cx.spawn_in(window, async move |editor, cx| {
13730            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
13731            let Some(project) = project.and_then(|p| p.upgrade()) else {
13732                return;
13733            };
13734            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
13735                this.display_map.update(cx, |map, cx| map.snapshot(cx))
13736            }) else {
13737                return;
13738            };
13739
13740            let hide_runnables = project
13741                .update(cx, |project, cx| {
13742                    // Do not display any test indicators in non-dev server remote projects.
13743                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
13744                })
13745                .unwrap_or(true);
13746            if hide_runnables {
13747                return;
13748            }
13749            let new_rows =
13750                cx.background_spawn({
13751                    let snapshot = display_snapshot.clone();
13752                    async move {
13753                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
13754                    }
13755                })
13756                    .await;
13757            let Ok(lsp_tasks) =
13758                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
13759            else {
13760                return;
13761            };
13762            let lsp_tasks = lsp_tasks.await;
13763
13764            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
13765                lsp_tasks
13766                    .into_iter()
13767                    .flat_map(|(kind, tasks)| {
13768                        tasks.into_iter().filter_map(move |(location, task)| {
13769                            Some((kind.clone(), location?, task))
13770                        })
13771                    })
13772                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
13773                        let buffer = location.target.buffer;
13774                        let buffer_snapshot = buffer.read(cx).snapshot();
13775                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
13776                            |(excerpt_id, snapshot, _)| {
13777                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
13778                                    display_snapshot
13779                                        .buffer_snapshot
13780                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
13781                                } else {
13782                                    None
13783                                }
13784                            },
13785                        );
13786                        if let Some(offset) = offset {
13787                            let task_buffer_range =
13788                                location.target.range.to_point(&buffer_snapshot);
13789                            let context_buffer_range =
13790                                task_buffer_range.to_offset(&buffer_snapshot);
13791                            let context_range = BufferOffset(context_buffer_range.start)
13792                                ..BufferOffset(context_buffer_range.end);
13793
13794                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
13795                                .or_insert_with(|| RunnableTasks {
13796                                    templates: Vec::new(),
13797                                    offset,
13798                                    column: task_buffer_range.start.column,
13799                                    extra_variables: HashMap::default(),
13800                                    context_range,
13801                                })
13802                                .templates
13803                                .push((kind, task.original_task().clone()));
13804                        }
13805
13806                        acc
13807                    })
13808            }) else {
13809                return;
13810            };
13811
13812            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
13813                buffer.language_settings(cx).tasks.prefer_lsp
13814            }) else {
13815                return;
13816            };
13817
13818            let rows = Self::runnable_rows(
13819                project,
13820                display_snapshot,
13821                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
13822                new_rows,
13823                cx.clone(),
13824            );
13825            editor
13826                .update(cx, |editor, _| {
13827                    editor.clear_tasks();
13828                    for (key, mut value) in rows {
13829                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
13830                            value.templates.extend(lsp_tasks.templates);
13831                        }
13832
13833                        editor.insert_tasks(key, value);
13834                    }
13835                    for (key, value) in lsp_tasks_by_rows {
13836                        editor.insert_tasks(key, value);
13837                    }
13838                })
13839                .ok();
13840        })
13841    }
13842    fn fetch_runnable_ranges(
13843        snapshot: &DisplaySnapshot,
13844        range: Range<Anchor>,
13845    ) -> Vec<language::RunnableRange> {
13846        snapshot.buffer_snapshot.runnable_ranges(range).collect()
13847    }
13848
13849    fn runnable_rows(
13850        project: Entity<Project>,
13851        snapshot: DisplaySnapshot,
13852        prefer_lsp: bool,
13853        runnable_ranges: Vec<RunnableRange>,
13854        mut cx: AsyncWindowContext,
13855    ) -> Vec<((BufferId, BufferRow), RunnableTasks)> {
13856        runnable_ranges
13857            .into_iter()
13858            .filter_map(|mut runnable| {
13859                let mut tasks = cx
13860                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
13861                    .ok()?;
13862                if prefer_lsp {
13863                    tasks.retain(|(task_kind, _)| {
13864                        !matches!(task_kind, TaskSourceKind::Language { .. })
13865                    });
13866                }
13867                if tasks.is_empty() {
13868                    return None;
13869                }
13870
13871                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
13872
13873                let row = snapshot
13874                    .buffer_snapshot
13875                    .buffer_line_for_row(MultiBufferRow(point.row))?
13876                    .1
13877                    .start
13878                    .row;
13879
13880                let context_range =
13881                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
13882                Some((
13883                    (runnable.buffer_id, row),
13884                    RunnableTasks {
13885                        templates: tasks,
13886                        offset: snapshot
13887                            .buffer_snapshot
13888                            .anchor_before(runnable.run_range.start),
13889                        context_range,
13890                        column: point.column,
13891                        extra_variables: runnable.extra_captures,
13892                    },
13893                ))
13894            })
13895            .collect()
13896    }
13897
13898    fn templates_with_tags(
13899        project: &Entity<Project>,
13900        runnable: &mut Runnable,
13901        cx: &mut App,
13902    ) -> Vec<(TaskSourceKind, TaskTemplate)> {
13903        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
13904            let (worktree_id, file) = project
13905                .buffer_for_id(runnable.buffer, cx)
13906                .and_then(|buffer| buffer.read(cx).file())
13907                .map(|file| (file.worktree_id(cx), file.clone()))
13908                .unzip();
13909
13910            (
13911                project.task_store().read(cx).task_inventory().cloned(),
13912                worktree_id,
13913                file,
13914            )
13915        });
13916
13917        let mut templates_with_tags = mem::take(&mut runnable.tags)
13918            .into_iter()
13919            .flat_map(|RunnableTag(tag)| {
13920                inventory
13921                    .as_ref()
13922                    .into_iter()
13923                    .flat_map(|inventory| {
13924                        inventory.read(cx).list_tasks(
13925                            file.clone(),
13926                            Some(runnable.language.clone()),
13927                            worktree_id,
13928                            cx,
13929                        )
13930                    })
13931                    .filter(move |(_, template)| {
13932                        template.tags.iter().any(|source_tag| source_tag == &tag)
13933                    })
13934            })
13935            .sorted_by_key(|(kind, _)| kind.to_owned())
13936            .collect::<Vec<_>>();
13937        if let Some((leading_tag_source, _)) = templates_with_tags.first() {
13938            // Strongest source wins; if we have worktree tag binding, prefer that to
13939            // global and language bindings;
13940            // if we have a global binding, prefer that to language binding.
13941            let first_mismatch = templates_with_tags
13942                .iter()
13943                .position(|(tag_source, _)| tag_source != leading_tag_source);
13944            if let Some(index) = first_mismatch {
13945                templates_with_tags.truncate(index);
13946            }
13947        }
13948
13949        templates_with_tags
13950    }
13951
13952    pub fn move_to_enclosing_bracket(
13953        &mut self,
13954        _: &MoveToEnclosingBracket,
13955        window: &mut Window,
13956        cx: &mut Context<Self>,
13957    ) {
13958        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
13959        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
13960            s.move_offsets_with(|snapshot, selection| {
13961                let Some(enclosing_bracket_ranges) =
13962                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
13963                else {
13964                    return;
13965                };
13966
13967                let mut best_length = usize::MAX;
13968                let mut best_inside = false;
13969                let mut best_in_bracket_range = false;
13970                let mut best_destination = None;
13971                for (open, close) in enclosing_bracket_ranges {
13972                    let close = close.to_inclusive();
13973                    let length = close.end() - open.start;
13974                    let inside = selection.start >= open.end && selection.end <= *close.start();
13975                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
13976                        || close.contains(&selection.head());
13977
13978                    // If best is next to a bracket and current isn't, skip
13979                    if !in_bracket_range && best_in_bracket_range {
13980                        continue;
13981                    }
13982
13983                    // Prefer smaller lengths unless best is inside and current isn't
13984                    if length > best_length && (best_inside || !inside) {
13985                        continue;
13986                    }
13987
13988                    best_length = length;
13989                    best_inside = inside;
13990                    best_in_bracket_range = in_bracket_range;
13991                    best_destination = Some(
13992                        if close.contains(&selection.start) && close.contains(&selection.end) {
13993                            if inside { open.end } else { open.start }
13994                        } else if inside {
13995                            *close.start()
13996                        } else {
13997                            *close.end()
13998                        },
13999                    );
14000                }
14001
14002                if let Some(destination) = best_destination {
14003                    selection.collapse_to(destination, SelectionGoal::None);
14004                }
14005            })
14006        });
14007    }
14008
14009    pub fn undo_selection(
14010        &mut self,
14011        _: &UndoSelection,
14012        window: &mut Window,
14013        cx: &mut Context<Self>,
14014    ) {
14015        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14016        self.end_selection(window, cx);
14017        self.selection_history.mode = SelectionHistoryMode::Undoing;
14018        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
14019            self.change_selections(None, window, cx, |s| {
14020                s.select_anchors(entry.selections.to_vec())
14021            });
14022            self.select_next_state = entry.select_next_state;
14023            self.select_prev_state = entry.select_prev_state;
14024            self.add_selections_state = entry.add_selections_state;
14025            self.request_autoscroll(Autoscroll::newest(), cx);
14026        }
14027        self.selection_history.mode = SelectionHistoryMode::Normal;
14028    }
14029
14030    pub fn redo_selection(
14031        &mut self,
14032        _: &RedoSelection,
14033        window: &mut Window,
14034        cx: &mut Context<Self>,
14035    ) {
14036        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14037        self.end_selection(window, cx);
14038        self.selection_history.mode = SelectionHistoryMode::Redoing;
14039        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
14040            self.change_selections(None, window, cx, |s| {
14041                s.select_anchors(entry.selections.to_vec())
14042            });
14043            self.select_next_state = entry.select_next_state;
14044            self.select_prev_state = entry.select_prev_state;
14045            self.add_selections_state = entry.add_selections_state;
14046            self.request_autoscroll(Autoscroll::newest(), cx);
14047        }
14048        self.selection_history.mode = SelectionHistoryMode::Normal;
14049    }
14050
14051    pub fn expand_excerpts(
14052        &mut self,
14053        action: &ExpandExcerpts,
14054        _: &mut Window,
14055        cx: &mut Context<Self>,
14056    ) {
14057        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
14058    }
14059
14060    pub fn expand_excerpts_down(
14061        &mut self,
14062        action: &ExpandExcerptsDown,
14063        _: &mut Window,
14064        cx: &mut Context<Self>,
14065    ) {
14066        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
14067    }
14068
14069    pub fn expand_excerpts_up(
14070        &mut self,
14071        action: &ExpandExcerptsUp,
14072        _: &mut Window,
14073        cx: &mut Context<Self>,
14074    ) {
14075        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
14076    }
14077
14078    pub fn expand_excerpts_for_direction(
14079        &mut self,
14080        lines: u32,
14081        direction: ExpandExcerptDirection,
14082
14083        cx: &mut Context<Self>,
14084    ) {
14085        let selections = self.selections.disjoint_anchors();
14086
14087        let lines = if lines == 0 {
14088            EditorSettings::get_global(cx).expand_excerpt_lines
14089        } else {
14090            lines
14091        };
14092
14093        self.buffer.update(cx, |buffer, cx| {
14094            let snapshot = buffer.snapshot(cx);
14095            let mut excerpt_ids = selections
14096                .iter()
14097                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
14098                .collect::<Vec<_>>();
14099            excerpt_ids.sort();
14100            excerpt_ids.dedup();
14101            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
14102        })
14103    }
14104
14105    pub fn expand_excerpt(
14106        &mut self,
14107        excerpt: ExcerptId,
14108        direction: ExpandExcerptDirection,
14109        window: &mut Window,
14110        cx: &mut Context<Self>,
14111    ) {
14112        let current_scroll_position = self.scroll_position(cx);
14113        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
14114        let mut should_scroll_up = false;
14115
14116        if direction == ExpandExcerptDirection::Down {
14117            let multi_buffer = self.buffer.read(cx);
14118            let snapshot = multi_buffer.snapshot(cx);
14119            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
14120                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
14121                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
14122                        let buffer_snapshot = buffer.read(cx).snapshot();
14123                        let excerpt_end_row =
14124                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
14125                        let last_row = buffer_snapshot.max_point().row;
14126                        let lines_below = last_row.saturating_sub(excerpt_end_row);
14127                        should_scroll_up = lines_below >= lines_to_expand;
14128                    }
14129                }
14130            }
14131        }
14132
14133        self.buffer.update(cx, |buffer, cx| {
14134            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
14135        });
14136
14137        if should_scroll_up {
14138            let new_scroll_position =
14139                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
14140            self.set_scroll_position(new_scroll_position, window, cx);
14141        }
14142    }
14143
14144    pub fn go_to_singleton_buffer_point(
14145        &mut self,
14146        point: Point,
14147        window: &mut Window,
14148        cx: &mut Context<Self>,
14149    ) {
14150        self.go_to_singleton_buffer_range(point..point, window, cx);
14151    }
14152
14153    pub fn go_to_singleton_buffer_range(
14154        &mut self,
14155        range: Range<Point>,
14156        window: &mut Window,
14157        cx: &mut Context<Self>,
14158    ) {
14159        let multibuffer = self.buffer().read(cx);
14160        let Some(buffer) = multibuffer.as_singleton() else {
14161            return;
14162        };
14163        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
14164            return;
14165        };
14166        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
14167            return;
14168        };
14169        self.change_selections(Some(Autoscroll::center()), window, cx, |s| {
14170            s.select_anchor_ranges([start..end])
14171        });
14172    }
14173
14174    pub fn go_to_diagnostic(
14175        &mut self,
14176        _: &GoToDiagnostic,
14177        window: &mut Window,
14178        cx: &mut Context<Self>,
14179    ) {
14180        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14181        self.go_to_diagnostic_impl(Direction::Next, window, cx)
14182    }
14183
14184    pub fn go_to_prev_diagnostic(
14185        &mut self,
14186        _: &GoToPreviousDiagnostic,
14187        window: &mut Window,
14188        cx: &mut Context<Self>,
14189    ) {
14190        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14191        self.go_to_diagnostic_impl(Direction::Prev, window, cx)
14192    }
14193
14194    pub fn go_to_diagnostic_impl(
14195        &mut self,
14196        direction: Direction,
14197        window: &mut Window,
14198        cx: &mut Context<Self>,
14199    ) {
14200        let buffer = self.buffer.read(cx).snapshot(cx);
14201        let selection = self.selections.newest::<usize>(cx);
14202
14203        let mut active_group_id = None;
14204        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
14205            if active_group.active_range.start.to_offset(&buffer) == selection.start {
14206                active_group_id = Some(active_group.group_id);
14207            }
14208        }
14209
14210        fn filtered(
14211            snapshot: EditorSnapshot,
14212            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
14213        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
14214            diagnostics
14215                .filter(|entry| entry.range.start != entry.range.end)
14216                .filter(|entry| !entry.diagnostic.is_unnecessary)
14217                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
14218        }
14219
14220        let snapshot = self.snapshot(window, cx);
14221        let before = filtered(
14222            snapshot.clone(),
14223            buffer
14224                .diagnostics_in_range(0..selection.start)
14225                .filter(|entry| entry.range.start <= selection.start),
14226        );
14227        let after = filtered(
14228            snapshot,
14229            buffer
14230                .diagnostics_in_range(selection.start..buffer.len())
14231                .filter(|entry| entry.range.start >= selection.start),
14232        );
14233
14234        let mut found: Option<DiagnosticEntry<usize>> = None;
14235        if direction == Direction::Prev {
14236            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
14237            {
14238                for diagnostic in prev_diagnostics.into_iter().rev() {
14239                    if diagnostic.range.start != selection.start
14240                        || active_group_id
14241                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
14242                    {
14243                        found = Some(diagnostic);
14244                        break 'outer;
14245                    }
14246                }
14247            }
14248        } else {
14249            for diagnostic in after.chain(before) {
14250                if diagnostic.range.start != selection.start
14251                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
14252                {
14253                    found = Some(diagnostic);
14254                    break;
14255                }
14256            }
14257        }
14258        let Some(next_diagnostic) = found else {
14259            return;
14260        };
14261
14262        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
14263            return;
14264        };
14265        self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14266            s.select_ranges(vec![
14267                next_diagnostic.range.start..next_diagnostic.range.start,
14268            ])
14269        });
14270        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
14271        self.refresh_inline_completion(false, true, window, cx);
14272    }
14273
14274    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
14275        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14276        let snapshot = self.snapshot(window, cx);
14277        let selection = self.selections.newest::<Point>(cx);
14278        self.go_to_hunk_before_or_after_position(
14279            &snapshot,
14280            selection.head(),
14281            Direction::Next,
14282            window,
14283            cx,
14284        );
14285    }
14286
14287    pub fn go_to_hunk_before_or_after_position(
14288        &mut self,
14289        snapshot: &EditorSnapshot,
14290        position: Point,
14291        direction: Direction,
14292        window: &mut Window,
14293        cx: &mut Context<Editor>,
14294    ) {
14295        let row = if direction == Direction::Next {
14296            self.hunk_after_position(snapshot, position)
14297                .map(|hunk| hunk.row_range.start)
14298        } else {
14299            self.hunk_before_position(snapshot, position)
14300        };
14301
14302        if let Some(row) = row {
14303            let destination = Point::new(row.0, 0);
14304            let autoscroll = Autoscroll::center();
14305
14306            self.unfold_ranges(&[destination..destination], false, false, cx);
14307            self.change_selections(Some(autoscroll), window, cx, |s| {
14308                s.select_ranges([destination..destination]);
14309            });
14310        }
14311    }
14312
14313    fn hunk_after_position(
14314        &mut self,
14315        snapshot: &EditorSnapshot,
14316        position: Point,
14317    ) -> Option<MultiBufferDiffHunk> {
14318        snapshot
14319            .buffer_snapshot
14320            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
14321            .find(|hunk| hunk.row_range.start.0 > position.row)
14322            .or_else(|| {
14323                snapshot
14324                    .buffer_snapshot
14325                    .diff_hunks_in_range(Point::zero()..position)
14326                    .find(|hunk| hunk.row_range.end.0 < position.row)
14327            })
14328    }
14329
14330    fn go_to_prev_hunk(
14331        &mut self,
14332        _: &GoToPreviousHunk,
14333        window: &mut Window,
14334        cx: &mut Context<Self>,
14335    ) {
14336        self.hide_mouse_cursor(&HideMouseCursorOrigin::MovementAction);
14337        let snapshot = self.snapshot(window, cx);
14338        let selection = self.selections.newest::<Point>(cx);
14339        self.go_to_hunk_before_or_after_position(
14340            &snapshot,
14341            selection.head(),
14342            Direction::Prev,
14343            window,
14344            cx,
14345        );
14346    }
14347
14348    fn hunk_before_position(
14349        &mut self,
14350        snapshot: &EditorSnapshot,
14351        position: Point,
14352    ) -> Option<MultiBufferRow> {
14353        snapshot
14354            .buffer_snapshot
14355            .diff_hunk_before(position)
14356            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
14357    }
14358
14359    fn go_to_next_change(
14360        &mut self,
14361        _: &GoToNextChange,
14362        window: &mut Window,
14363        cx: &mut Context<Self>,
14364    ) {
14365        if let Some(selections) = self
14366            .change_list
14367            .next_change(1, Direction::Next)
14368            .map(|s| s.to_vec())
14369        {
14370            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14371                let map = s.display_map();
14372                s.select_display_ranges(selections.iter().map(|a| {
14373                    let point = a.to_display_point(&map);
14374                    point..point
14375                }))
14376            })
14377        }
14378    }
14379
14380    fn go_to_previous_change(
14381        &mut self,
14382        _: &GoToPreviousChange,
14383        window: &mut Window,
14384        cx: &mut Context<Self>,
14385    ) {
14386        if let Some(selections) = self
14387            .change_list
14388            .next_change(1, Direction::Prev)
14389            .map(|s| s.to_vec())
14390        {
14391            self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
14392                let map = s.display_map();
14393                s.select_display_ranges(selections.iter().map(|a| {
14394                    let point = a.to_display_point(&map);
14395                    point..point
14396                }))
14397            })
14398        }
14399    }
14400
14401    fn go_to_line<T: 'static>(
14402        &mut self,
14403        position: Anchor,
14404        highlight_color: Option<Hsla>,
14405        window: &mut Window,
14406        cx: &mut Context<Self>,
14407    ) {
14408        let snapshot = self.snapshot(window, cx).display_snapshot;
14409        let position = position.to_point(&snapshot.buffer_snapshot);
14410        let start = snapshot
14411            .buffer_snapshot
14412            .clip_point(Point::new(position.row, 0), Bias::Left);
14413        let end = start + Point::new(1, 0);
14414        let start = snapshot.buffer_snapshot.anchor_before(start);
14415        let end = snapshot.buffer_snapshot.anchor_before(end);
14416
14417        self.highlight_rows::<T>(
14418            start..end,
14419            highlight_color
14420                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
14421            Default::default(),
14422            cx,
14423        );
14424
14425        if self.buffer.read(cx).is_singleton() {
14426            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
14427        }
14428    }
14429
14430    pub fn go_to_definition(
14431        &mut self,
14432        _: &GoToDefinition,
14433        window: &mut Window,
14434        cx: &mut Context<Self>,
14435    ) -> Task<Result<Navigated>> {
14436        let definition =
14437            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
14438        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
14439        cx.spawn_in(window, async move |editor, cx| {
14440            if definition.await? == Navigated::Yes {
14441                return Ok(Navigated::Yes);
14442            }
14443            match fallback_strategy {
14444                GoToDefinitionFallback::None => Ok(Navigated::No),
14445                GoToDefinitionFallback::FindAllReferences => {
14446                    match editor.update_in(cx, |editor, window, cx| {
14447                        editor.find_all_references(&FindAllReferences, window, cx)
14448                    })? {
14449                        Some(references) => references.await,
14450                        None => Ok(Navigated::No),
14451                    }
14452                }
14453            }
14454        })
14455    }
14456
14457    pub fn go_to_declaration(
14458        &mut self,
14459        _: &GoToDeclaration,
14460        window: &mut Window,
14461        cx: &mut Context<Self>,
14462    ) -> Task<Result<Navigated>> {
14463        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
14464    }
14465
14466    pub fn go_to_declaration_split(
14467        &mut self,
14468        _: &GoToDeclaration,
14469        window: &mut Window,
14470        cx: &mut Context<Self>,
14471    ) -> Task<Result<Navigated>> {
14472        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
14473    }
14474
14475    pub fn go_to_implementation(
14476        &mut self,
14477        _: &GoToImplementation,
14478        window: &mut Window,
14479        cx: &mut Context<Self>,
14480    ) -> Task<Result<Navigated>> {
14481        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
14482    }
14483
14484    pub fn go_to_implementation_split(
14485        &mut self,
14486        _: &GoToImplementationSplit,
14487        window: &mut Window,
14488        cx: &mut Context<Self>,
14489    ) -> Task<Result<Navigated>> {
14490        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
14491    }
14492
14493    pub fn go_to_type_definition(
14494        &mut self,
14495        _: &GoToTypeDefinition,
14496        window: &mut Window,
14497        cx: &mut Context<Self>,
14498    ) -> Task<Result<Navigated>> {
14499        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
14500    }
14501
14502    pub fn go_to_definition_split(
14503        &mut self,
14504        _: &GoToDefinitionSplit,
14505        window: &mut Window,
14506        cx: &mut Context<Self>,
14507    ) -> Task<Result<Navigated>> {
14508        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
14509    }
14510
14511    pub fn go_to_type_definition_split(
14512        &mut self,
14513        _: &GoToTypeDefinitionSplit,
14514        window: &mut Window,
14515        cx: &mut Context<Self>,
14516    ) -> Task<Result<Navigated>> {
14517        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
14518    }
14519
14520    fn go_to_definition_of_kind(
14521        &mut self,
14522        kind: GotoDefinitionKind,
14523        split: bool,
14524        window: &mut Window,
14525        cx: &mut Context<Self>,
14526    ) -> Task<Result<Navigated>> {
14527        let Some(provider) = self.semantics_provider.clone() else {
14528            return Task::ready(Ok(Navigated::No));
14529        };
14530        let head = self.selections.newest::<usize>(cx).head();
14531        let buffer = self.buffer.read(cx);
14532        let (buffer, head) = if let Some(text_anchor) = buffer.text_anchor_for_position(head, cx) {
14533            text_anchor
14534        } else {
14535            return Task::ready(Ok(Navigated::No));
14536        };
14537
14538        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
14539            return Task::ready(Ok(Navigated::No));
14540        };
14541
14542        cx.spawn_in(window, async move |editor, cx| {
14543            let definitions = definitions.await?;
14544            let navigated = editor
14545                .update_in(cx, |editor, window, cx| {
14546                    editor.navigate_to_hover_links(
14547                        Some(kind),
14548                        definitions
14549                            .into_iter()
14550                            .filter(|location| {
14551                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
14552                            })
14553                            .map(HoverLink::Text)
14554                            .collect::<Vec<_>>(),
14555                        split,
14556                        window,
14557                        cx,
14558                    )
14559                })?
14560                .await?;
14561            anyhow::Ok(navigated)
14562        })
14563    }
14564
14565    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
14566        let selection = self.selections.newest_anchor();
14567        let head = selection.head();
14568        let tail = selection.tail();
14569
14570        let Some((buffer, start_position)) =
14571            self.buffer.read(cx).text_anchor_for_position(head, cx)
14572        else {
14573            return;
14574        };
14575
14576        let end_position = if head != tail {
14577            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
14578                return;
14579            };
14580            Some(pos)
14581        } else {
14582            None
14583        };
14584
14585        let url_finder = cx.spawn_in(window, async move |editor, cx| {
14586            let url = if let Some(end_pos) = end_position {
14587                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
14588            } else {
14589                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
14590            };
14591
14592            if let Some(url) = url {
14593                editor.update(cx, |_, cx| {
14594                    cx.open_url(&url);
14595                })
14596            } else {
14597                Ok(())
14598            }
14599        });
14600
14601        url_finder.detach();
14602    }
14603
14604    pub fn open_selected_filename(
14605        &mut self,
14606        _: &OpenSelectedFilename,
14607        window: &mut Window,
14608        cx: &mut Context<Self>,
14609    ) {
14610        let Some(workspace) = self.workspace() else {
14611            return;
14612        };
14613
14614        let position = self.selections.newest_anchor().head();
14615
14616        let Some((buffer, buffer_position)) =
14617            self.buffer.read(cx).text_anchor_for_position(position, cx)
14618        else {
14619            return;
14620        };
14621
14622        let project = self.project.clone();
14623
14624        cx.spawn_in(window, async move |_, cx| {
14625            let result = find_file(&buffer, project, buffer_position, cx).await;
14626
14627            if let Some((_, path)) = result {
14628                workspace
14629                    .update_in(cx, |workspace, window, cx| {
14630                        workspace.open_resolved_path(path, window, cx)
14631                    })?
14632                    .await?;
14633            }
14634            anyhow::Ok(())
14635        })
14636        .detach();
14637    }
14638
14639    pub(crate) fn navigate_to_hover_links(
14640        &mut self,
14641        kind: Option<GotoDefinitionKind>,
14642        mut definitions: Vec<HoverLink>,
14643        split: bool,
14644        window: &mut Window,
14645        cx: &mut Context<Editor>,
14646    ) -> Task<Result<Navigated>> {
14647        // If there is one definition, just open it directly
14648        if definitions.len() == 1 {
14649            let definition = definitions.pop().unwrap();
14650
14651            enum TargetTaskResult {
14652                Location(Option<Location>),
14653                AlreadyNavigated,
14654            }
14655
14656            let target_task = match definition {
14657                HoverLink::Text(link) => {
14658                    Task::ready(anyhow::Ok(TargetTaskResult::Location(Some(link.target))))
14659                }
14660                HoverLink::InlayHint(lsp_location, server_id) => {
14661                    let computation =
14662                        self.compute_target_location(lsp_location, server_id, window, cx);
14663                    cx.background_spawn(async move {
14664                        let location = computation.await?;
14665                        Ok(TargetTaskResult::Location(location))
14666                    })
14667                }
14668                HoverLink::Url(url) => {
14669                    cx.open_url(&url);
14670                    Task::ready(Ok(TargetTaskResult::AlreadyNavigated))
14671                }
14672                HoverLink::File(path) => {
14673                    if let Some(workspace) = self.workspace() {
14674                        cx.spawn_in(window, async move |_, cx| {
14675                            workspace
14676                                .update_in(cx, |workspace, window, cx| {
14677                                    workspace.open_resolved_path(path, window, cx)
14678                                })?
14679                                .await
14680                                .map(|_| TargetTaskResult::AlreadyNavigated)
14681                        })
14682                    } else {
14683                        Task::ready(Ok(TargetTaskResult::Location(None)))
14684                    }
14685                }
14686            };
14687            cx.spawn_in(window, async move |editor, cx| {
14688                let target = match target_task.await.context("target resolution task")? {
14689                    TargetTaskResult::AlreadyNavigated => return Ok(Navigated::Yes),
14690                    TargetTaskResult::Location(None) => return Ok(Navigated::No),
14691                    TargetTaskResult::Location(Some(target)) => target,
14692                };
14693
14694                editor.update_in(cx, |editor, window, cx| {
14695                    let Some(workspace) = editor.workspace() else {
14696                        return Navigated::No;
14697                    };
14698                    let pane = workspace.read(cx).active_pane().clone();
14699
14700                    let range = target.range.to_point(target.buffer.read(cx));
14701                    let range = editor.range_for_match(&range);
14702                    let range = collapse_multiline_range(range);
14703
14704                    if !split
14705                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
14706                    {
14707                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
14708                    } else {
14709                        window.defer(cx, move |window, cx| {
14710                            let target_editor: Entity<Self> =
14711                                workspace.update(cx, |workspace, cx| {
14712                                    let pane = if split {
14713                                        workspace.adjacent_pane(window, cx)
14714                                    } else {
14715                                        workspace.active_pane().clone()
14716                                    };
14717
14718                                    workspace.open_project_item(
14719                                        pane,
14720                                        target.buffer.clone(),
14721                                        true,
14722                                        true,
14723                                        window,
14724                                        cx,
14725                                    )
14726                                });
14727                            target_editor.update(cx, |target_editor, cx| {
14728                                // When selecting a definition in a different buffer, disable the nav history
14729                                // to avoid creating a history entry at the previous cursor location.
14730                                pane.update(cx, |pane, _| pane.disable_history());
14731                                target_editor.go_to_singleton_buffer_range(range, window, cx);
14732                                pane.update(cx, |pane, _| pane.enable_history());
14733                            });
14734                        });
14735                    }
14736                    Navigated::Yes
14737                })
14738            })
14739        } else if !definitions.is_empty() {
14740            cx.spawn_in(window, async move |editor, cx| {
14741                let (title, location_tasks, workspace) = editor
14742                    .update_in(cx, |editor, window, cx| {
14743                        let tab_kind = match kind {
14744                            Some(GotoDefinitionKind::Implementation) => "Implementations",
14745                            _ => "Definitions",
14746                        };
14747                        let title = definitions
14748                            .iter()
14749                            .find_map(|definition| match definition {
14750                                HoverLink::Text(link) => link.origin.as_ref().map(|origin| {
14751                                    let buffer = origin.buffer.read(cx);
14752                                    format!(
14753                                        "{} for {}",
14754                                        tab_kind,
14755                                        buffer
14756                                            .text_for_range(origin.range.clone())
14757                                            .collect::<String>()
14758                                    )
14759                                }),
14760                                HoverLink::InlayHint(_, _) => None,
14761                                HoverLink::Url(_) => None,
14762                                HoverLink::File(_) => None,
14763                            })
14764                            .unwrap_or(tab_kind.to_string());
14765                        let location_tasks = definitions
14766                            .into_iter()
14767                            .map(|definition| match definition {
14768                                HoverLink::Text(link) => Task::ready(Ok(Some(link.target))),
14769                                HoverLink::InlayHint(lsp_location, server_id) => editor
14770                                    .compute_target_location(lsp_location, server_id, window, cx),
14771                                HoverLink::Url(_) => Task::ready(Ok(None)),
14772                                HoverLink::File(_) => Task::ready(Ok(None)),
14773                            })
14774                            .collect::<Vec<_>>();
14775                        (title, location_tasks, editor.workspace().clone())
14776                    })
14777                    .context("location tasks preparation")?;
14778
14779                let locations = future::join_all(location_tasks)
14780                    .await
14781                    .into_iter()
14782                    .filter_map(|location| location.transpose())
14783                    .collect::<Result<_>>()
14784                    .context("location tasks")?;
14785
14786                let Some(workspace) = workspace else {
14787                    return Ok(Navigated::No);
14788                };
14789                let opened = workspace
14790                    .update_in(cx, |workspace, window, cx| {
14791                        Self::open_locations_in_multibuffer(
14792                            workspace,
14793                            locations,
14794                            title,
14795                            split,
14796                            MultibufferSelectionMode::First,
14797                            window,
14798                            cx,
14799                        )
14800                    })
14801                    .ok();
14802
14803                anyhow::Ok(Navigated::from_bool(opened.is_some()))
14804            })
14805        } else {
14806            Task::ready(Ok(Navigated::No))
14807        }
14808    }
14809
14810    fn compute_target_location(
14811        &self,
14812        lsp_location: lsp::Location,
14813        server_id: LanguageServerId,
14814        window: &mut Window,
14815        cx: &mut Context<Self>,
14816    ) -> Task<anyhow::Result<Option<Location>>> {
14817        let Some(project) = self.project.clone() else {
14818            return Task::ready(Ok(None));
14819        };
14820
14821        cx.spawn_in(window, async move |editor, cx| {
14822            let location_task = editor.update(cx, |_, cx| {
14823                project.update(cx, |project, cx| {
14824                    let language_server_name = project
14825                        .language_server_statuses(cx)
14826                        .find(|(id, _)| server_id == *id)
14827                        .map(|(_, status)| LanguageServerName::from(status.name.as_str()));
14828                    language_server_name.map(|language_server_name| {
14829                        project.open_local_buffer_via_lsp(
14830                            lsp_location.uri.clone(),
14831                            server_id,
14832                            language_server_name,
14833                            cx,
14834                        )
14835                    })
14836                })
14837            })?;
14838            let location = match location_task {
14839                Some(task) => Some({
14840                    let target_buffer_handle = task.await.context("open local buffer")?;
14841                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
14842                        let target_start = target_buffer
14843                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
14844                        let target_end = target_buffer
14845                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
14846                        target_buffer.anchor_after(target_start)
14847                            ..target_buffer.anchor_before(target_end)
14848                    })?;
14849                    Location {
14850                        buffer: target_buffer_handle,
14851                        range,
14852                    }
14853                }),
14854                None => None,
14855            };
14856            Ok(location)
14857        })
14858    }
14859
14860    pub fn find_all_references(
14861        &mut self,
14862        _: &FindAllReferences,
14863        window: &mut Window,
14864        cx: &mut Context<Self>,
14865    ) -> Option<Task<Result<Navigated>>> {
14866        let selection = self.selections.newest::<usize>(cx);
14867        let multi_buffer = self.buffer.read(cx);
14868        let head = selection.head();
14869
14870        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
14871        let head_anchor = multi_buffer_snapshot.anchor_at(
14872            head,
14873            if head < selection.tail() {
14874                Bias::Right
14875            } else {
14876                Bias::Left
14877            },
14878        );
14879
14880        match self
14881            .find_all_references_task_sources
14882            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14883        {
14884            Ok(_) => {
14885                log::info!(
14886                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
14887                );
14888                return None;
14889            }
14890            Err(i) => {
14891                self.find_all_references_task_sources.insert(i, head_anchor);
14892            }
14893        }
14894
14895        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
14896        let workspace = self.workspace()?;
14897        let project = workspace.read(cx).project().clone();
14898        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
14899        Some(cx.spawn_in(window, async move |editor, cx| {
14900            let _cleanup = cx.on_drop(&editor, move |editor, _| {
14901                if let Ok(i) = editor
14902                    .find_all_references_task_sources
14903                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
14904                {
14905                    editor.find_all_references_task_sources.remove(i);
14906                }
14907            });
14908
14909            let locations = references.await?;
14910            if locations.is_empty() {
14911                return anyhow::Ok(Navigated::No);
14912            }
14913
14914            workspace.update_in(cx, |workspace, window, cx| {
14915                let title = locations
14916                    .first()
14917                    .as_ref()
14918                    .map(|location| {
14919                        let buffer = location.buffer.read(cx);
14920                        format!(
14921                            "References to `{}`",
14922                            buffer
14923                                .text_for_range(location.range.clone())
14924                                .collect::<String>()
14925                        )
14926                    })
14927                    .unwrap();
14928                Self::open_locations_in_multibuffer(
14929                    workspace,
14930                    locations,
14931                    title,
14932                    false,
14933                    MultibufferSelectionMode::First,
14934                    window,
14935                    cx,
14936                );
14937                Navigated::Yes
14938            })
14939        }))
14940    }
14941
14942    /// Opens a multibuffer with the given project locations in it
14943    pub fn open_locations_in_multibuffer(
14944        workspace: &mut Workspace,
14945        mut locations: Vec<Location>,
14946        title: String,
14947        split: bool,
14948        multibuffer_selection_mode: MultibufferSelectionMode,
14949        window: &mut Window,
14950        cx: &mut Context<Workspace>,
14951    ) {
14952        // If there are multiple definitions, open them in a multibuffer
14953        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
14954        let mut locations = locations.into_iter().peekable();
14955        let mut ranges: Vec<Range<Anchor>> = Vec::new();
14956        let capability = workspace.project().read(cx).capability();
14957
14958        let excerpt_buffer = cx.new(|cx| {
14959            let mut multibuffer = MultiBuffer::new(capability);
14960            while let Some(location) = locations.next() {
14961                let buffer = location.buffer.read(cx);
14962                let mut ranges_for_buffer = Vec::new();
14963                let range = location.range.to_point(buffer);
14964                ranges_for_buffer.push(range.clone());
14965
14966                while let Some(next_location) = locations.peek() {
14967                    if next_location.buffer == location.buffer {
14968                        ranges_for_buffer.push(next_location.range.to_point(buffer));
14969                        locations.next();
14970                    } else {
14971                        break;
14972                    }
14973                }
14974
14975                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
14976                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
14977                    PathKey::for_buffer(&location.buffer, cx),
14978                    location.buffer.clone(),
14979                    ranges_for_buffer,
14980                    DEFAULT_MULTIBUFFER_CONTEXT,
14981                    cx,
14982                );
14983                ranges.extend(new_ranges)
14984            }
14985
14986            multibuffer.with_title(title)
14987        });
14988
14989        let editor = cx.new(|cx| {
14990            Editor::for_multibuffer(
14991                excerpt_buffer,
14992                Some(workspace.project().clone()),
14993                window,
14994                cx,
14995            )
14996        });
14997        editor.update(cx, |editor, cx| {
14998            match multibuffer_selection_mode {
14999                MultibufferSelectionMode::First => {
15000                    if let Some(first_range) = ranges.first() {
15001                        editor.change_selections(None, window, cx, |selections| {
15002                            selections.clear_disjoint();
15003                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
15004                        });
15005                    }
15006                    editor.highlight_background::<Self>(
15007                        &ranges,
15008                        |theme| theme.editor_highlighted_line_background,
15009                        cx,
15010                    );
15011                }
15012                MultibufferSelectionMode::All => {
15013                    editor.change_selections(None, window, cx, |selections| {
15014                        selections.clear_disjoint();
15015                        selections.select_anchor_ranges(ranges);
15016                    });
15017                }
15018            }
15019            editor.register_buffers_with_language_servers(cx);
15020        });
15021
15022        let item = Box::new(editor);
15023        let item_id = item.item_id();
15024
15025        if split {
15026            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
15027        } else {
15028            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
15029                let (preview_item_id, preview_item_idx) =
15030                    workspace.active_pane().read_with(cx, |pane, _| {
15031                        (pane.preview_item_id(), pane.preview_item_idx())
15032                    });
15033
15034                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
15035
15036                if let Some(preview_item_id) = preview_item_id {
15037                    workspace.active_pane().update(cx, |pane, cx| {
15038                        pane.remove_item(preview_item_id, false, false, window, cx);
15039                    });
15040                }
15041            } else {
15042                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
15043            }
15044        }
15045        workspace.active_pane().update(cx, |pane, cx| {
15046            pane.set_preview_item_id(Some(item_id), cx);
15047        });
15048    }
15049
15050    pub fn rename(
15051        &mut self,
15052        _: &Rename,
15053        window: &mut Window,
15054        cx: &mut Context<Self>,
15055    ) -> Option<Task<Result<()>>> {
15056        use language::ToOffset as _;
15057
15058        let provider = self.semantics_provider.clone()?;
15059        let selection = self.selections.newest_anchor().clone();
15060        let (cursor_buffer, cursor_buffer_position) = self
15061            .buffer
15062            .read(cx)
15063            .text_anchor_for_position(selection.head(), cx)?;
15064        let (tail_buffer, cursor_buffer_position_end) = self
15065            .buffer
15066            .read(cx)
15067            .text_anchor_for_position(selection.tail(), cx)?;
15068        if tail_buffer != cursor_buffer {
15069            return None;
15070        }
15071
15072        let snapshot = cursor_buffer.read(cx).snapshot();
15073        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
15074        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
15075        let prepare_rename = provider
15076            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
15077            .unwrap_or_else(|| Task::ready(Ok(None)));
15078        drop(snapshot);
15079
15080        Some(cx.spawn_in(window, async move |this, cx| {
15081            let rename_range = if let Some(range) = prepare_rename.await? {
15082                Some(range)
15083            } else {
15084                this.update(cx, |this, cx| {
15085                    let buffer = this.buffer.read(cx).snapshot(cx);
15086                    let mut buffer_highlights = this
15087                        .document_highlights_for_position(selection.head(), &buffer)
15088                        .filter(|highlight| {
15089                            highlight.start.excerpt_id == selection.head().excerpt_id
15090                                && highlight.end.excerpt_id == selection.head().excerpt_id
15091                        });
15092                    buffer_highlights
15093                        .next()
15094                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
15095                })?
15096            };
15097            if let Some(rename_range) = rename_range {
15098                this.update_in(cx, |this, window, cx| {
15099                    let snapshot = cursor_buffer.read(cx).snapshot();
15100                    let rename_buffer_range = rename_range.to_offset(&snapshot);
15101                    let cursor_offset_in_rename_range =
15102                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
15103                    let cursor_offset_in_rename_range_end =
15104                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
15105
15106                    this.take_rename(false, window, cx);
15107                    let buffer = this.buffer.read(cx).read(cx);
15108                    let cursor_offset = selection.head().to_offset(&buffer);
15109                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
15110                    let rename_end = rename_start + rename_buffer_range.len();
15111                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
15112                    let mut old_highlight_id = None;
15113                    let old_name: Arc<str> = buffer
15114                        .chunks(rename_start..rename_end, true)
15115                        .map(|chunk| {
15116                            if old_highlight_id.is_none() {
15117                                old_highlight_id = chunk.syntax_highlight_id;
15118                            }
15119                            chunk.text
15120                        })
15121                        .collect::<String>()
15122                        .into();
15123
15124                    drop(buffer);
15125
15126                    // Position the selection in the rename editor so that it matches the current selection.
15127                    this.show_local_selections = false;
15128                    let rename_editor = cx.new(|cx| {
15129                        let mut editor = Editor::single_line(window, cx);
15130                        editor.buffer.update(cx, |buffer, cx| {
15131                            buffer.edit([(0..0, old_name.clone())], None, cx)
15132                        });
15133                        let rename_selection_range = match cursor_offset_in_rename_range
15134                            .cmp(&cursor_offset_in_rename_range_end)
15135                        {
15136                            Ordering::Equal => {
15137                                editor.select_all(&SelectAll, window, cx);
15138                                return editor;
15139                            }
15140                            Ordering::Less => {
15141                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
15142                            }
15143                            Ordering::Greater => {
15144                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
15145                            }
15146                        };
15147                        if rename_selection_range.end > old_name.len() {
15148                            editor.select_all(&SelectAll, window, cx);
15149                        } else {
15150                            editor.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
15151                                s.select_ranges([rename_selection_range]);
15152                            });
15153                        }
15154                        editor
15155                    });
15156                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
15157                        if e == &EditorEvent::Focused {
15158                            cx.emit(EditorEvent::FocusedIn)
15159                        }
15160                    })
15161                    .detach();
15162
15163                    let write_highlights =
15164                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
15165                    let read_highlights =
15166                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
15167                    let ranges = write_highlights
15168                        .iter()
15169                        .flat_map(|(_, ranges)| ranges.iter())
15170                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
15171                        .cloned()
15172                        .collect();
15173
15174                    this.highlight_text::<Rename>(
15175                        ranges,
15176                        HighlightStyle {
15177                            fade_out: Some(0.6),
15178                            ..Default::default()
15179                        },
15180                        cx,
15181                    );
15182                    let rename_focus_handle = rename_editor.focus_handle(cx);
15183                    window.focus(&rename_focus_handle);
15184                    let block_id = this.insert_blocks(
15185                        [BlockProperties {
15186                            style: BlockStyle::Flex,
15187                            placement: BlockPlacement::Below(range.start),
15188                            height: Some(1),
15189                            render: Arc::new({
15190                                let rename_editor = rename_editor.clone();
15191                                move |cx: &mut BlockContext| {
15192                                    let mut text_style = cx.editor_style.text.clone();
15193                                    if let Some(highlight_style) = old_highlight_id
15194                                        .and_then(|h| h.style(&cx.editor_style.syntax))
15195                                    {
15196                                        text_style = text_style.highlight(highlight_style);
15197                                    }
15198                                    div()
15199                                        .block_mouse_except_scroll()
15200                                        .pl(cx.anchor_x)
15201                                        .child(EditorElement::new(
15202                                            &rename_editor,
15203                                            EditorStyle {
15204                                                background: cx.theme().system().transparent,
15205                                                local_player: cx.editor_style.local_player,
15206                                                text: text_style,
15207                                                scrollbar_width: cx.editor_style.scrollbar_width,
15208                                                syntax: cx.editor_style.syntax.clone(),
15209                                                status: cx.editor_style.status.clone(),
15210                                                inlay_hints_style: HighlightStyle {
15211                                                    font_weight: Some(FontWeight::BOLD),
15212                                                    ..make_inlay_hints_style(cx.app)
15213                                                },
15214                                                inline_completion_styles: make_suggestion_styles(
15215                                                    cx.app,
15216                                                ),
15217                                                ..EditorStyle::default()
15218                                            },
15219                                        ))
15220                                        .into_any_element()
15221                                }
15222                            }),
15223                            priority: 0,
15224                            render_in_minimap: true,
15225                        }],
15226                        Some(Autoscroll::fit()),
15227                        cx,
15228                    )[0];
15229                    this.pending_rename = Some(RenameState {
15230                        range,
15231                        old_name,
15232                        editor: rename_editor,
15233                        block_id,
15234                    });
15235                })?;
15236            }
15237
15238            Ok(())
15239        }))
15240    }
15241
15242    pub fn confirm_rename(
15243        &mut self,
15244        _: &ConfirmRename,
15245        window: &mut Window,
15246        cx: &mut Context<Self>,
15247    ) -> Option<Task<Result<()>>> {
15248        let rename = self.take_rename(false, window, cx)?;
15249        let workspace = self.workspace()?.downgrade();
15250        let (buffer, start) = self
15251            .buffer
15252            .read(cx)
15253            .text_anchor_for_position(rename.range.start, cx)?;
15254        let (end_buffer, _) = self
15255            .buffer
15256            .read(cx)
15257            .text_anchor_for_position(rename.range.end, cx)?;
15258        if buffer != end_buffer {
15259            return None;
15260        }
15261
15262        let old_name = rename.old_name;
15263        let new_name = rename.editor.read(cx).text(cx);
15264
15265        let rename = self.semantics_provider.as_ref()?.perform_rename(
15266            &buffer,
15267            start,
15268            new_name.clone(),
15269            cx,
15270        )?;
15271
15272        Some(cx.spawn_in(window, async move |editor, cx| {
15273            let project_transaction = rename.await?;
15274            Self::open_project_transaction(
15275                &editor,
15276                workspace,
15277                project_transaction,
15278                format!("Rename: {}{}", old_name, new_name),
15279                cx,
15280            )
15281            .await?;
15282
15283            editor.update(cx, |editor, cx| {
15284                editor.refresh_document_highlights(cx);
15285            })?;
15286            Ok(())
15287        }))
15288    }
15289
15290    fn take_rename(
15291        &mut self,
15292        moving_cursor: bool,
15293        window: &mut Window,
15294        cx: &mut Context<Self>,
15295    ) -> Option<RenameState> {
15296        let rename = self.pending_rename.take()?;
15297        if rename.editor.focus_handle(cx).is_focused(window) {
15298            window.focus(&self.focus_handle);
15299        }
15300
15301        self.remove_blocks(
15302            [rename.block_id].into_iter().collect(),
15303            Some(Autoscroll::fit()),
15304            cx,
15305        );
15306        self.clear_highlights::<Rename>(cx);
15307        self.show_local_selections = true;
15308
15309        if moving_cursor {
15310            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
15311                editor.selections.newest::<usize>(cx).head()
15312            });
15313
15314            // Update the selection to match the position of the selection inside
15315            // the rename editor.
15316            let snapshot = self.buffer.read(cx).read(cx);
15317            let rename_range = rename.range.to_offset(&snapshot);
15318            let cursor_in_editor = snapshot
15319                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
15320                .min(rename_range.end);
15321            drop(snapshot);
15322
15323            self.change_selections(None, window, cx, |s| {
15324                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
15325            });
15326        } else {
15327            self.refresh_document_highlights(cx);
15328        }
15329
15330        Some(rename)
15331    }
15332
15333    pub fn pending_rename(&self) -> Option<&RenameState> {
15334        self.pending_rename.as_ref()
15335    }
15336
15337    fn format(
15338        &mut self,
15339        _: &Format,
15340        window: &mut Window,
15341        cx: &mut Context<Self>,
15342    ) -> Option<Task<Result<()>>> {
15343        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15344
15345        let project = match &self.project {
15346            Some(project) => project.clone(),
15347            None => return None,
15348        };
15349
15350        Some(self.perform_format(
15351            project,
15352            FormatTrigger::Manual,
15353            FormatTarget::Buffers,
15354            window,
15355            cx,
15356        ))
15357    }
15358
15359    fn format_selections(
15360        &mut self,
15361        _: &FormatSelections,
15362        window: &mut Window,
15363        cx: &mut Context<Self>,
15364    ) -> Option<Task<Result<()>>> {
15365        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15366
15367        let project = match &self.project {
15368            Some(project) => project.clone(),
15369            None => return None,
15370        };
15371
15372        let ranges = self
15373            .selections
15374            .all_adjusted(cx)
15375            .into_iter()
15376            .map(|selection| selection.range())
15377            .collect_vec();
15378
15379        Some(self.perform_format(
15380            project,
15381            FormatTrigger::Manual,
15382            FormatTarget::Ranges(ranges),
15383            window,
15384            cx,
15385        ))
15386    }
15387
15388    fn perform_format(
15389        &mut self,
15390        project: Entity<Project>,
15391        trigger: FormatTrigger,
15392        target: FormatTarget,
15393        window: &mut Window,
15394        cx: &mut Context<Self>,
15395    ) -> Task<Result<()>> {
15396        let buffer = self.buffer.clone();
15397        let (buffers, target) = match target {
15398            FormatTarget::Buffers => {
15399                let mut buffers = buffer.read(cx).all_buffers();
15400                if trigger == FormatTrigger::Save {
15401                    buffers.retain(|buffer| buffer.read(cx).is_dirty());
15402                }
15403                (buffers, LspFormatTarget::Buffers)
15404            }
15405            FormatTarget::Ranges(selection_ranges) => {
15406                let multi_buffer = buffer.read(cx);
15407                let snapshot = multi_buffer.read(cx);
15408                let mut buffers = HashSet::default();
15409                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
15410                    BTreeMap::new();
15411                for selection_range in selection_ranges {
15412                    for (buffer, buffer_range, _) in
15413                        snapshot.range_to_buffer_ranges(selection_range)
15414                    {
15415                        let buffer_id = buffer.remote_id();
15416                        let start = buffer.anchor_before(buffer_range.start);
15417                        let end = buffer.anchor_after(buffer_range.end);
15418                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
15419                        buffer_id_to_ranges
15420                            .entry(buffer_id)
15421                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
15422                            .or_insert_with(|| vec![start..end]);
15423                    }
15424                }
15425                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
15426            }
15427        };
15428
15429        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
15430        let selections_prev = transaction_id_prev
15431            .and_then(|transaction_id_prev| {
15432                // default to selections as they were after the last edit, if we have them,
15433                // instead of how they are now.
15434                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
15435                // will take you back to where you made the last edit, instead of staying where you scrolled
15436                self.selection_history
15437                    .transaction(transaction_id_prev)
15438                    .map(|t| t.0.clone())
15439            })
15440            .unwrap_or_else(|| {
15441                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
15442                self.selections.disjoint_anchors()
15443            });
15444
15445        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
15446        let format = project.update(cx, |project, cx| {
15447            project.format(buffers, target, true, trigger, cx)
15448        });
15449
15450        cx.spawn_in(window, async move |editor, cx| {
15451            let transaction = futures::select_biased! {
15452                transaction = format.log_err().fuse() => transaction,
15453                () = timeout => {
15454                    log::warn!("timed out waiting for formatting");
15455                    None
15456                }
15457            };
15458
15459            buffer
15460                .update(cx, |buffer, cx| {
15461                    if let Some(transaction) = transaction {
15462                        if !buffer.is_singleton() {
15463                            buffer.push_transaction(&transaction.0, cx);
15464                        }
15465                    }
15466                    cx.notify();
15467                })
15468                .ok();
15469
15470            if let Some(transaction_id_now) =
15471                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
15472            {
15473                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
15474                if has_new_transaction {
15475                    _ = editor.update(cx, |editor, _| {
15476                        editor
15477                            .selection_history
15478                            .insert_transaction(transaction_id_now, selections_prev);
15479                    });
15480                }
15481            }
15482
15483            Ok(())
15484        })
15485    }
15486
15487    fn organize_imports(
15488        &mut self,
15489        _: &OrganizeImports,
15490        window: &mut Window,
15491        cx: &mut Context<Self>,
15492    ) -> Option<Task<Result<()>>> {
15493        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
15494        let project = match &self.project {
15495            Some(project) => project.clone(),
15496            None => return None,
15497        };
15498        Some(self.perform_code_action_kind(
15499            project,
15500            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
15501            window,
15502            cx,
15503        ))
15504    }
15505
15506    fn perform_code_action_kind(
15507        &mut self,
15508        project: Entity<Project>,
15509        kind: CodeActionKind,
15510        window: &mut Window,
15511        cx: &mut Context<Self>,
15512    ) -> Task<Result<()>> {
15513        let buffer = self.buffer.clone();
15514        let buffers = buffer.read(cx).all_buffers();
15515        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
15516        let apply_action = project.update(cx, |project, cx| {
15517            project.apply_code_action_kind(buffers, kind, true, cx)
15518        });
15519        cx.spawn_in(window, async move |_, cx| {
15520            let transaction = futures::select_biased! {
15521                () = timeout => {
15522                    log::warn!("timed out waiting for executing code action");
15523                    None
15524                }
15525                transaction = apply_action.log_err().fuse() => transaction,
15526            };
15527            buffer
15528                .update(cx, |buffer, cx| {
15529                    // check if we need this
15530                    if let Some(transaction) = transaction {
15531                        if !buffer.is_singleton() {
15532                            buffer.push_transaction(&transaction.0, cx);
15533                        }
15534                    }
15535                    cx.notify();
15536                })
15537                .ok();
15538            Ok(())
15539        })
15540    }
15541
15542    fn restart_language_server(
15543        &mut self,
15544        _: &RestartLanguageServer,
15545        _: &mut Window,
15546        cx: &mut Context<Self>,
15547    ) {
15548        if let Some(project) = self.project.clone() {
15549            self.buffer.update(cx, |multi_buffer, cx| {
15550                project.update(cx, |project, cx| {
15551                    project.restart_language_servers_for_buffers(
15552                        multi_buffer.all_buffers().into_iter().collect(),
15553                        cx,
15554                    );
15555                });
15556            })
15557        }
15558    }
15559
15560    fn stop_language_server(
15561        &mut self,
15562        _: &StopLanguageServer,
15563        _: &mut Window,
15564        cx: &mut Context<Self>,
15565    ) {
15566        if let Some(project) = self.project.clone() {
15567            self.buffer.update(cx, |multi_buffer, cx| {
15568                project.update(cx, |project, cx| {
15569                    project.stop_language_servers_for_buffers(
15570                        multi_buffer.all_buffers().into_iter().collect(),
15571                        cx,
15572                    );
15573                    cx.emit(project::Event::RefreshInlayHints);
15574                });
15575            });
15576        }
15577    }
15578
15579    fn cancel_language_server_work(
15580        workspace: &mut Workspace,
15581        _: &actions::CancelLanguageServerWork,
15582        _: &mut Window,
15583        cx: &mut Context<Workspace>,
15584    ) {
15585        let project = workspace.project();
15586        let buffers = workspace
15587            .active_item(cx)
15588            .and_then(|item| item.act_as::<Editor>(cx))
15589            .map_or(HashSet::default(), |editor| {
15590                editor.read(cx).buffer.read(cx).all_buffers()
15591            });
15592        project.update(cx, |project, cx| {
15593            project.cancel_language_server_work_for_buffers(buffers, cx);
15594        });
15595    }
15596
15597    fn show_character_palette(
15598        &mut self,
15599        _: &ShowCharacterPalette,
15600        window: &mut Window,
15601        _: &mut Context<Self>,
15602    ) {
15603        window.show_character_palette();
15604    }
15605
15606    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
15607        if self.mode.is_minimap() {
15608            return;
15609        }
15610
15611        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
15612            let buffer = self.buffer.read(cx).snapshot(cx);
15613            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
15614            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
15615            let is_valid = buffer
15616                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
15617                .any(|entry| {
15618                    entry.diagnostic.is_primary
15619                        && !entry.range.is_empty()
15620                        && entry.range.start == primary_range_start
15621                        && entry.diagnostic.message == active_diagnostics.active_message
15622                });
15623
15624            if !is_valid {
15625                self.dismiss_diagnostics(cx);
15626            }
15627        }
15628    }
15629
15630    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
15631        match &self.active_diagnostics {
15632            ActiveDiagnostic::Group(group) => Some(group),
15633            _ => None,
15634        }
15635    }
15636
15637    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
15638        self.dismiss_diagnostics(cx);
15639        self.active_diagnostics = ActiveDiagnostic::All;
15640    }
15641
15642    fn activate_diagnostics(
15643        &mut self,
15644        buffer_id: BufferId,
15645        diagnostic: DiagnosticEntry<usize>,
15646        window: &mut Window,
15647        cx: &mut Context<Self>,
15648    ) {
15649        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15650            return;
15651        }
15652        self.dismiss_diagnostics(cx);
15653        let snapshot = self.snapshot(window, cx);
15654        let buffer = self.buffer.read(cx).snapshot(cx);
15655        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
15656            return;
15657        };
15658
15659        let diagnostic_group = buffer
15660            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
15661            .collect::<Vec<_>>();
15662
15663        let blocks =
15664            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
15665
15666        let blocks = self.display_map.update(cx, |display_map, cx| {
15667            display_map.insert_blocks(blocks, cx).into_iter().collect()
15668        });
15669        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
15670            active_range: buffer.anchor_before(diagnostic.range.start)
15671                ..buffer.anchor_after(diagnostic.range.end),
15672            active_message: diagnostic.diagnostic.message.clone(),
15673            group_id: diagnostic.diagnostic.group_id,
15674            blocks,
15675        });
15676        cx.notify();
15677    }
15678
15679    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
15680        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
15681            return;
15682        };
15683
15684        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
15685        if let ActiveDiagnostic::Group(group) = prev {
15686            self.display_map.update(cx, |display_map, cx| {
15687                display_map.remove_blocks(group.blocks, cx);
15688            });
15689            cx.notify();
15690        }
15691    }
15692
15693    /// Disable inline diagnostics rendering for this editor.
15694    pub fn disable_inline_diagnostics(&mut self) {
15695        self.inline_diagnostics_enabled = false;
15696        self.inline_diagnostics_update = Task::ready(());
15697        self.inline_diagnostics.clear();
15698    }
15699
15700    pub fn diagnostics_enabled(&self) -> bool {
15701        self.mode.is_full()
15702    }
15703
15704    pub fn inline_diagnostics_enabled(&self) -> bool {
15705        self.diagnostics_enabled() && self.inline_diagnostics_enabled
15706    }
15707
15708    pub fn show_inline_diagnostics(&self) -> bool {
15709        self.show_inline_diagnostics
15710    }
15711
15712    pub fn toggle_inline_diagnostics(
15713        &mut self,
15714        _: &ToggleInlineDiagnostics,
15715        window: &mut Window,
15716        cx: &mut Context<Editor>,
15717    ) {
15718        self.show_inline_diagnostics = !self.show_inline_diagnostics;
15719        self.refresh_inline_diagnostics(false, window, cx);
15720    }
15721
15722    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
15723        self.diagnostics_max_severity = severity;
15724        self.display_map.update(cx, |display_map, _| {
15725            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
15726        });
15727    }
15728
15729    pub fn toggle_diagnostics(
15730        &mut self,
15731        _: &ToggleDiagnostics,
15732        window: &mut Window,
15733        cx: &mut Context<Editor>,
15734    ) {
15735        if !self.diagnostics_enabled() {
15736            return;
15737        }
15738
15739        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15740            EditorSettings::get_global(cx)
15741                .diagnostics_max_severity
15742                .filter(|severity| severity != &DiagnosticSeverity::Off)
15743                .unwrap_or(DiagnosticSeverity::Hint)
15744        } else {
15745            DiagnosticSeverity::Off
15746        };
15747        self.set_max_diagnostics_severity(new_severity, cx);
15748        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
15749            self.active_diagnostics = ActiveDiagnostic::None;
15750            self.inline_diagnostics_update = Task::ready(());
15751            self.inline_diagnostics.clear();
15752        } else {
15753            self.refresh_inline_diagnostics(false, window, cx);
15754        }
15755
15756        cx.notify();
15757    }
15758
15759    pub fn toggle_minimap(
15760        &mut self,
15761        _: &ToggleMinimap,
15762        window: &mut Window,
15763        cx: &mut Context<Editor>,
15764    ) {
15765        if self.supports_minimap(cx) {
15766            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
15767        }
15768    }
15769
15770    fn refresh_inline_diagnostics(
15771        &mut self,
15772        debounce: bool,
15773        window: &mut Window,
15774        cx: &mut Context<Self>,
15775    ) {
15776        let max_severity = ProjectSettings::get_global(cx)
15777            .diagnostics
15778            .inline
15779            .max_severity
15780            .unwrap_or(self.diagnostics_max_severity);
15781
15782        if !self.inline_diagnostics_enabled()
15783            || !self.show_inline_diagnostics
15784            || max_severity == DiagnosticSeverity::Off
15785        {
15786            self.inline_diagnostics_update = Task::ready(());
15787            self.inline_diagnostics.clear();
15788            return;
15789        }
15790
15791        let debounce_ms = ProjectSettings::get_global(cx)
15792            .diagnostics
15793            .inline
15794            .update_debounce_ms;
15795        let debounce = if debounce && debounce_ms > 0 {
15796            Some(Duration::from_millis(debounce_ms))
15797        } else {
15798            None
15799        };
15800        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
15801            if let Some(debounce) = debounce {
15802                cx.background_executor().timer(debounce).await;
15803            }
15804            let Some(snapshot) = editor.upgrade().and_then(|editor| {
15805                editor
15806                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
15807                    .ok()
15808            }) else {
15809                return;
15810            };
15811
15812            let new_inline_diagnostics = cx
15813                .background_spawn(async move {
15814                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
15815                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
15816                        let message = diagnostic_entry
15817                            .diagnostic
15818                            .message
15819                            .split_once('\n')
15820                            .map(|(line, _)| line)
15821                            .map(SharedString::new)
15822                            .unwrap_or_else(|| {
15823                                SharedString::from(diagnostic_entry.diagnostic.message)
15824                            });
15825                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
15826                        let (Ok(i) | Err(i)) = inline_diagnostics
15827                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
15828                        inline_diagnostics.insert(
15829                            i,
15830                            (
15831                                start_anchor,
15832                                InlineDiagnostic {
15833                                    message,
15834                                    group_id: diagnostic_entry.diagnostic.group_id,
15835                                    start: diagnostic_entry.range.start.to_point(&snapshot),
15836                                    is_primary: diagnostic_entry.diagnostic.is_primary,
15837                                    severity: diagnostic_entry.diagnostic.severity,
15838                                },
15839                            ),
15840                        );
15841                    }
15842                    inline_diagnostics
15843                })
15844                .await;
15845
15846            editor
15847                .update(cx, |editor, cx| {
15848                    editor.inline_diagnostics = new_inline_diagnostics;
15849                    cx.notify();
15850                })
15851                .ok();
15852        });
15853    }
15854
15855    pub fn set_selections_from_remote(
15856        &mut self,
15857        selections: Vec<Selection<Anchor>>,
15858        pending_selection: Option<Selection<Anchor>>,
15859        window: &mut Window,
15860        cx: &mut Context<Self>,
15861    ) {
15862        let old_cursor_position = self.selections.newest_anchor().head();
15863        self.selections.change_with(cx, |s| {
15864            s.select_anchors(selections);
15865            if let Some(pending_selection) = pending_selection {
15866                s.set_pending(pending_selection, SelectMode::Character);
15867            } else {
15868                s.clear_pending();
15869            }
15870        });
15871        self.selections_did_change(false, &old_cursor_position, true, window, cx);
15872    }
15873
15874    pub fn transact(
15875        &mut self,
15876        window: &mut Window,
15877        cx: &mut Context<Self>,
15878        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
15879    ) -> Option<TransactionId> {
15880        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15881            this.start_transaction_at(Instant::now(), window, cx);
15882            update(this, window, cx);
15883            this.end_transaction_at(Instant::now(), cx)
15884        })
15885    }
15886
15887    pub fn start_transaction_at(
15888        &mut self,
15889        now: Instant,
15890        window: &mut Window,
15891        cx: &mut Context<Self>,
15892    ) {
15893        self.end_selection(window, cx);
15894        if let Some(tx_id) = self
15895            .buffer
15896            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
15897        {
15898            self.selection_history
15899                .insert_transaction(tx_id, self.selections.disjoint_anchors());
15900            cx.emit(EditorEvent::TransactionBegun {
15901                transaction_id: tx_id,
15902            })
15903        }
15904    }
15905
15906    pub fn end_transaction_at(
15907        &mut self,
15908        now: Instant,
15909        cx: &mut Context<Self>,
15910    ) -> Option<TransactionId> {
15911        if let Some(transaction_id) = self
15912            .buffer
15913            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
15914        {
15915            if let Some((_, end_selections)) =
15916                self.selection_history.transaction_mut(transaction_id)
15917            {
15918                *end_selections = Some(self.selections.disjoint_anchors());
15919            } else {
15920                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
15921            }
15922
15923            cx.emit(EditorEvent::Edited { transaction_id });
15924            Some(transaction_id)
15925        } else {
15926            None
15927        }
15928    }
15929
15930    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
15931        if self.selection_mark_mode {
15932            self.change_selections(None, window, cx, |s| {
15933                s.move_with(|_, sel| {
15934                    sel.collapse_to(sel.head(), SelectionGoal::None);
15935                });
15936            })
15937        }
15938        self.selection_mark_mode = true;
15939        cx.notify();
15940    }
15941
15942    pub fn swap_selection_ends(
15943        &mut self,
15944        _: &actions::SwapSelectionEnds,
15945        window: &mut Window,
15946        cx: &mut Context<Self>,
15947    ) {
15948        self.change_selections(None, window, cx, |s| {
15949            s.move_with(|_, sel| {
15950                if sel.start != sel.end {
15951                    sel.reversed = !sel.reversed
15952                }
15953            });
15954        });
15955        self.request_autoscroll(Autoscroll::newest(), cx);
15956        cx.notify();
15957    }
15958
15959    pub fn toggle_fold(
15960        &mut self,
15961        _: &actions::ToggleFold,
15962        window: &mut Window,
15963        cx: &mut Context<Self>,
15964    ) {
15965        if self.is_singleton(cx) {
15966            let selection = self.selections.newest::<Point>(cx);
15967
15968            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15969            let range = if selection.is_empty() {
15970                let point = selection.head().to_display_point(&display_map);
15971                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
15972                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
15973                    .to_point(&display_map);
15974                start..end
15975            } else {
15976                selection.range()
15977            };
15978            if display_map.folds_in_range(range).next().is_some() {
15979                self.unfold_lines(&Default::default(), window, cx)
15980            } else {
15981                self.fold(&Default::default(), window, cx)
15982            }
15983        } else {
15984            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
15985            let buffer_ids: HashSet<_> = self
15986                .selections
15987                .disjoint_anchor_ranges()
15988                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
15989                .collect();
15990
15991            let should_unfold = buffer_ids
15992                .iter()
15993                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
15994
15995            for buffer_id in buffer_ids {
15996                if should_unfold {
15997                    self.unfold_buffer(buffer_id, cx);
15998                } else {
15999                    self.fold_buffer(buffer_id, cx);
16000                }
16001            }
16002        }
16003    }
16004
16005    pub fn toggle_fold_recursive(
16006        &mut self,
16007        _: &actions::ToggleFoldRecursive,
16008        window: &mut Window,
16009        cx: &mut Context<Self>,
16010    ) {
16011        let selection = self.selections.newest::<Point>(cx);
16012
16013        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16014        let range = if selection.is_empty() {
16015            let point = selection.head().to_display_point(&display_map);
16016            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
16017            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
16018                .to_point(&display_map);
16019            start..end
16020        } else {
16021            selection.range()
16022        };
16023        if display_map.folds_in_range(range).next().is_some() {
16024            self.unfold_recursive(&Default::default(), window, cx)
16025        } else {
16026            self.fold_recursive(&Default::default(), window, cx)
16027        }
16028    }
16029
16030    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
16031        if self.is_singleton(cx) {
16032            let mut to_fold = Vec::new();
16033            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16034            let selections = self.selections.all_adjusted(cx);
16035
16036            for selection in selections {
16037                let range = selection.range().sorted();
16038                let buffer_start_row = range.start.row;
16039
16040                if range.start.row != range.end.row {
16041                    let mut found = false;
16042                    let mut row = range.start.row;
16043                    while row <= range.end.row {
16044                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
16045                        {
16046                            found = true;
16047                            row = crease.range().end.row + 1;
16048                            to_fold.push(crease);
16049                        } else {
16050                            row += 1
16051                        }
16052                    }
16053                    if found {
16054                        continue;
16055                    }
16056                }
16057
16058                for row in (0..=range.start.row).rev() {
16059                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16060                        if crease.range().end.row >= buffer_start_row {
16061                            to_fold.push(crease);
16062                            if row <= range.start.row {
16063                                break;
16064                            }
16065                        }
16066                    }
16067                }
16068            }
16069
16070            self.fold_creases(to_fold, true, window, cx);
16071        } else {
16072            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16073            let buffer_ids = self
16074                .selections
16075                .disjoint_anchor_ranges()
16076                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16077                .collect::<HashSet<_>>();
16078            for buffer_id in buffer_ids {
16079                self.fold_buffer(buffer_id, cx);
16080            }
16081        }
16082    }
16083
16084    fn fold_at_level(
16085        &mut self,
16086        fold_at: &FoldAtLevel,
16087        window: &mut Window,
16088        cx: &mut Context<Self>,
16089    ) {
16090        if !self.buffer.read(cx).is_singleton() {
16091            return;
16092        }
16093
16094        let fold_at_level = fold_at.0;
16095        let snapshot = self.buffer.read(cx).snapshot(cx);
16096        let mut to_fold = Vec::new();
16097        let mut stack = vec![(0, snapshot.max_row().0, 1)];
16098
16099        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
16100            while start_row < end_row {
16101                match self
16102                    .snapshot(window, cx)
16103                    .crease_for_buffer_row(MultiBufferRow(start_row))
16104                {
16105                    Some(crease) => {
16106                        let nested_start_row = crease.range().start.row + 1;
16107                        let nested_end_row = crease.range().end.row;
16108
16109                        if current_level < fold_at_level {
16110                            stack.push((nested_start_row, nested_end_row, current_level + 1));
16111                        } else if current_level == fold_at_level {
16112                            to_fold.push(crease);
16113                        }
16114
16115                        start_row = nested_end_row + 1;
16116                    }
16117                    None => start_row += 1,
16118                }
16119            }
16120        }
16121
16122        self.fold_creases(to_fold, true, window, cx);
16123    }
16124
16125    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
16126        if self.buffer.read(cx).is_singleton() {
16127            let mut fold_ranges = Vec::new();
16128            let snapshot = self.buffer.read(cx).snapshot(cx);
16129
16130            for row in 0..snapshot.max_row().0 {
16131                if let Some(foldable_range) = self
16132                    .snapshot(window, cx)
16133                    .crease_for_buffer_row(MultiBufferRow(row))
16134                {
16135                    fold_ranges.push(foldable_range);
16136                }
16137            }
16138
16139            self.fold_creases(fold_ranges, true, window, cx);
16140        } else {
16141            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
16142                editor
16143                    .update_in(cx, |editor, _, cx| {
16144                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16145                            editor.fold_buffer(buffer_id, cx);
16146                        }
16147                    })
16148                    .ok();
16149            });
16150        }
16151    }
16152
16153    pub fn fold_function_bodies(
16154        &mut self,
16155        _: &actions::FoldFunctionBodies,
16156        window: &mut Window,
16157        cx: &mut Context<Self>,
16158    ) {
16159        let snapshot = self.buffer.read(cx).snapshot(cx);
16160
16161        let ranges = snapshot
16162            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
16163            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
16164            .collect::<Vec<_>>();
16165
16166        let creases = ranges
16167            .into_iter()
16168            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
16169            .collect();
16170
16171        self.fold_creases(creases, true, window, cx);
16172    }
16173
16174    pub fn fold_recursive(
16175        &mut self,
16176        _: &actions::FoldRecursive,
16177        window: &mut Window,
16178        cx: &mut Context<Self>,
16179    ) {
16180        let mut to_fold = Vec::new();
16181        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16182        let selections = self.selections.all_adjusted(cx);
16183
16184        for selection in selections {
16185            let range = selection.range().sorted();
16186            let buffer_start_row = range.start.row;
16187
16188            if range.start.row != range.end.row {
16189                let mut found = false;
16190                for row in range.start.row..=range.end.row {
16191                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16192                        found = true;
16193                        to_fold.push(crease);
16194                    }
16195                }
16196                if found {
16197                    continue;
16198                }
16199            }
16200
16201            for row in (0..=range.start.row).rev() {
16202                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
16203                    if crease.range().end.row >= buffer_start_row {
16204                        to_fold.push(crease);
16205                    } else {
16206                        break;
16207                    }
16208                }
16209            }
16210        }
16211
16212        self.fold_creases(to_fold, true, window, cx);
16213    }
16214
16215    pub fn fold_at(
16216        &mut self,
16217        buffer_row: MultiBufferRow,
16218        window: &mut Window,
16219        cx: &mut Context<Self>,
16220    ) {
16221        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16222
16223        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
16224            let autoscroll = self
16225                .selections
16226                .all::<Point>(cx)
16227                .iter()
16228                .any(|selection| crease.range().overlaps(&selection.range()));
16229
16230            self.fold_creases(vec![crease], autoscroll, window, cx);
16231        }
16232    }
16233
16234    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
16235        if self.is_singleton(cx) {
16236            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16237            let buffer = &display_map.buffer_snapshot;
16238            let selections = self.selections.all::<Point>(cx);
16239            let ranges = selections
16240                .iter()
16241                .map(|s| {
16242                    let range = s.display_range(&display_map).sorted();
16243                    let mut start = range.start.to_point(&display_map);
16244                    let mut end = range.end.to_point(&display_map);
16245                    start.column = 0;
16246                    end.column = buffer.line_len(MultiBufferRow(end.row));
16247                    start..end
16248                })
16249                .collect::<Vec<_>>();
16250
16251            self.unfold_ranges(&ranges, true, true, cx);
16252        } else {
16253            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
16254            let buffer_ids = self
16255                .selections
16256                .disjoint_anchor_ranges()
16257                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
16258                .collect::<HashSet<_>>();
16259            for buffer_id in buffer_ids {
16260                self.unfold_buffer(buffer_id, cx);
16261            }
16262        }
16263    }
16264
16265    pub fn unfold_recursive(
16266        &mut self,
16267        _: &UnfoldRecursive,
16268        _window: &mut Window,
16269        cx: &mut Context<Self>,
16270    ) {
16271        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16272        let selections = self.selections.all::<Point>(cx);
16273        let ranges = selections
16274            .iter()
16275            .map(|s| {
16276                let mut range = s.display_range(&display_map).sorted();
16277                *range.start.column_mut() = 0;
16278                *range.end.column_mut() = display_map.line_len(range.end.row());
16279                let start = range.start.to_point(&display_map);
16280                let end = range.end.to_point(&display_map);
16281                start..end
16282            })
16283            .collect::<Vec<_>>();
16284
16285        self.unfold_ranges(&ranges, true, true, cx);
16286    }
16287
16288    pub fn unfold_at(
16289        &mut self,
16290        buffer_row: MultiBufferRow,
16291        _window: &mut Window,
16292        cx: &mut Context<Self>,
16293    ) {
16294        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16295
16296        let intersection_range = Point::new(buffer_row.0, 0)
16297            ..Point::new(
16298                buffer_row.0,
16299                display_map.buffer_snapshot.line_len(buffer_row),
16300            );
16301
16302        let autoscroll = self
16303            .selections
16304            .all::<Point>(cx)
16305            .iter()
16306            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
16307
16308        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
16309    }
16310
16311    pub fn unfold_all(
16312        &mut self,
16313        _: &actions::UnfoldAll,
16314        _window: &mut Window,
16315        cx: &mut Context<Self>,
16316    ) {
16317        if self.buffer.read(cx).is_singleton() {
16318            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16319            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
16320        } else {
16321            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
16322                editor
16323                    .update(cx, |editor, cx| {
16324                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
16325                            editor.unfold_buffer(buffer_id, cx);
16326                        }
16327                    })
16328                    .ok();
16329            });
16330        }
16331    }
16332
16333    pub fn fold_selected_ranges(
16334        &mut self,
16335        _: &FoldSelectedRanges,
16336        window: &mut Window,
16337        cx: &mut Context<Self>,
16338    ) {
16339        let selections = self.selections.all_adjusted(cx);
16340        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16341        let ranges = selections
16342            .into_iter()
16343            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
16344            .collect::<Vec<_>>();
16345        self.fold_creases(ranges, true, window, cx);
16346    }
16347
16348    pub fn fold_ranges<T: ToOffset + Clone>(
16349        &mut self,
16350        ranges: Vec<Range<T>>,
16351        auto_scroll: bool,
16352        window: &mut Window,
16353        cx: &mut Context<Self>,
16354    ) {
16355        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16356        let ranges = ranges
16357            .into_iter()
16358            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
16359            .collect::<Vec<_>>();
16360        self.fold_creases(ranges, auto_scroll, window, cx);
16361    }
16362
16363    pub fn fold_creases<T: ToOffset + Clone>(
16364        &mut self,
16365        creases: Vec<Crease<T>>,
16366        auto_scroll: bool,
16367        _window: &mut Window,
16368        cx: &mut Context<Self>,
16369    ) {
16370        if creases.is_empty() {
16371            return;
16372        }
16373
16374        let mut buffers_affected = HashSet::default();
16375        let multi_buffer = self.buffer().read(cx);
16376        for crease in &creases {
16377            if let Some((_, buffer, _)) =
16378                multi_buffer.excerpt_containing(crease.range().start.clone(), cx)
16379            {
16380                buffers_affected.insert(buffer.read(cx).remote_id());
16381            };
16382        }
16383
16384        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
16385
16386        if auto_scroll {
16387            self.request_autoscroll(Autoscroll::fit(), cx);
16388        }
16389
16390        cx.notify();
16391
16392        self.scrollbar_marker_state.dirty = true;
16393        self.folds_did_change(cx);
16394    }
16395
16396    /// Removes any folds whose ranges intersect any of the given ranges.
16397    pub fn unfold_ranges<T: ToOffset + Clone>(
16398        &mut self,
16399        ranges: &[Range<T>],
16400        inclusive: bool,
16401        auto_scroll: bool,
16402        cx: &mut Context<Self>,
16403    ) {
16404        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16405            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
16406        });
16407        self.folds_did_change(cx);
16408    }
16409
16410    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16411        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
16412            return;
16413        }
16414        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16415        self.display_map.update(cx, |display_map, cx| {
16416            display_map.fold_buffers([buffer_id], cx)
16417        });
16418        cx.emit(EditorEvent::BufferFoldToggled {
16419            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
16420            folded: true,
16421        });
16422        cx.notify();
16423    }
16424
16425    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16426        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
16427            return;
16428        }
16429        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
16430        self.display_map.update(cx, |display_map, cx| {
16431            display_map.unfold_buffers([buffer_id], cx);
16432        });
16433        cx.emit(EditorEvent::BufferFoldToggled {
16434            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
16435            folded: false,
16436        });
16437        cx.notify();
16438    }
16439
16440    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
16441        self.display_map.read(cx).is_buffer_folded(buffer)
16442    }
16443
16444    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
16445        self.display_map.read(cx).folded_buffers()
16446    }
16447
16448    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
16449        self.display_map.update(cx, |display_map, cx| {
16450            display_map.disable_header_for_buffer(buffer_id, cx);
16451        });
16452        cx.notify();
16453    }
16454
16455    /// Removes any folds with the given ranges.
16456    pub fn remove_folds_with_type<T: ToOffset + Clone>(
16457        &mut self,
16458        ranges: &[Range<T>],
16459        type_id: TypeId,
16460        auto_scroll: bool,
16461        cx: &mut Context<Self>,
16462    ) {
16463        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
16464            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
16465        });
16466        self.folds_did_change(cx);
16467    }
16468
16469    fn remove_folds_with<T: ToOffset + Clone>(
16470        &mut self,
16471        ranges: &[Range<T>],
16472        auto_scroll: bool,
16473        cx: &mut Context<Self>,
16474        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
16475    ) {
16476        if ranges.is_empty() {
16477            return;
16478        }
16479
16480        let mut buffers_affected = HashSet::default();
16481        let multi_buffer = self.buffer().read(cx);
16482        for range in ranges {
16483            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
16484                buffers_affected.insert(buffer.read(cx).remote_id());
16485            };
16486        }
16487
16488        self.display_map.update(cx, update);
16489
16490        if auto_scroll {
16491            self.request_autoscroll(Autoscroll::fit(), cx);
16492        }
16493
16494        cx.notify();
16495        self.scrollbar_marker_state.dirty = true;
16496        self.active_indent_guides_state.dirty = true;
16497    }
16498
16499    pub fn update_fold_widths(
16500        &mut self,
16501        widths: impl IntoIterator<Item = (FoldId, Pixels)>,
16502        cx: &mut Context<Self>,
16503    ) -> bool {
16504        self.display_map
16505            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
16506    }
16507
16508    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
16509        self.display_map.read(cx).fold_placeholder.clone()
16510    }
16511
16512    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
16513        self.buffer.update(cx, |buffer, cx| {
16514            buffer.set_all_diff_hunks_expanded(cx);
16515        });
16516    }
16517
16518    pub fn expand_all_diff_hunks(
16519        &mut self,
16520        _: &ExpandAllDiffHunks,
16521        _window: &mut Window,
16522        cx: &mut Context<Self>,
16523    ) {
16524        self.buffer.update(cx, |buffer, cx| {
16525            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
16526        });
16527    }
16528
16529    pub fn toggle_selected_diff_hunks(
16530        &mut self,
16531        _: &ToggleSelectedDiffHunks,
16532        _window: &mut Window,
16533        cx: &mut Context<Self>,
16534    ) {
16535        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16536        self.toggle_diff_hunks_in_ranges(ranges, cx);
16537    }
16538
16539    pub fn diff_hunks_in_ranges<'a>(
16540        &'a self,
16541        ranges: &'a [Range<Anchor>],
16542        buffer: &'a MultiBufferSnapshot,
16543    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
16544        ranges.iter().flat_map(move |range| {
16545            let end_excerpt_id = range.end.excerpt_id;
16546            let range = range.to_point(buffer);
16547            let mut peek_end = range.end;
16548            if range.end.row < buffer.max_row().0 {
16549                peek_end = Point::new(range.end.row + 1, 0);
16550            }
16551            buffer
16552                .diff_hunks_in_range(range.start..peek_end)
16553                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
16554        })
16555    }
16556
16557    pub fn has_stageable_diff_hunks_in_ranges(
16558        &self,
16559        ranges: &[Range<Anchor>],
16560        snapshot: &MultiBufferSnapshot,
16561    ) -> bool {
16562        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
16563        hunks.any(|hunk| hunk.status().has_secondary_hunk())
16564    }
16565
16566    pub fn toggle_staged_selected_diff_hunks(
16567        &mut self,
16568        _: &::git::ToggleStaged,
16569        _: &mut Window,
16570        cx: &mut Context<Self>,
16571    ) {
16572        let snapshot = self.buffer.read(cx).snapshot(cx);
16573        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16574        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
16575        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16576    }
16577
16578    pub fn set_render_diff_hunk_controls(
16579        &mut self,
16580        render_diff_hunk_controls: RenderDiffHunkControlsFn,
16581        cx: &mut Context<Self>,
16582    ) {
16583        self.render_diff_hunk_controls = render_diff_hunk_controls;
16584        cx.notify();
16585    }
16586
16587    pub fn stage_and_next(
16588        &mut self,
16589        _: &::git::StageAndNext,
16590        window: &mut Window,
16591        cx: &mut Context<Self>,
16592    ) {
16593        self.do_stage_or_unstage_and_next(true, window, cx);
16594    }
16595
16596    pub fn unstage_and_next(
16597        &mut self,
16598        _: &::git::UnstageAndNext,
16599        window: &mut Window,
16600        cx: &mut Context<Self>,
16601    ) {
16602        self.do_stage_or_unstage_and_next(false, window, cx);
16603    }
16604
16605    pub fn stage_or_unstage_diff_hunks(
16606        &mut self,
16607        stage: bool,
16608        ranges: Vec<Range<Anchor>>,
16609        cx: &mut Context<Self>,
16610    ) {
16611        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
16612        cx.spawn(async move |this, cx| {
16613            task.await?;
16614            this.update(cx, |this, cx| {
16615                let snapshot = this.buffer.read(cx).snapshot(cx);
16616                let chunk_by = this
16617                    .diff_hunks_in_ranges(&ranges, &snapshot)
16618                    .chunk_by(|hunk| hunk.buffer_id);
16619                for (buffer_id, hunks) in &chunk_by {
16620                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
16621                }
16622            })
16623        })
16624        .detach_and_log_err(cx);
16625    }
16626
16627    fn save_buffers_for_ranges_if_needed(
16628        &mut self,
16629        ranges: &[Range<Anchor>],
16630        cx: &mut Context<Editor>,
16631    ) -> Task<Result<()>> {
16632        let multibuffer = self.buffer.read(cx);
16633        let snapshot = multibuffer.read(cx);
16634        let buffer_ids: HashSet<_> = ranges
16635            .iter()
16636            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
16637            .collect();
16638        drop(snapshot);
16639
16640        let mut buffers = HashSet::default();
16641        for buffer_id in buffer_ids {
16642            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
16643                let buffer = buffer_entity.read(cx);
16644                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
16645                {
16646                    buffers.insert(buffer_entity);
16647                }
16648            }
16649        }
16650
16651        if let Some(project) = &self.project {
16652            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
16653        } else {
16654            Task::ready(Ok(()))
16655        }
16656    }
16657
16658    fn do_stage_or_unstage_and_next(
16659        &mut self,
16660        stage: bool,
16661        window: &mut Window,
16662        cx: &mut Context<Self>,
16663    ) {
16664        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
16665
16666        if ranges.iter().any(|range| range.start != range.end) {
16667            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16668            return;
16669        }
16670
16671        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
16672        let snapshot = self.snapshot(window, cx);
16673        let position = self.selections.newest::<Point>(cx).head();
16674        let mut row = snapshot
16675            .buffer_snapshot
16676            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
16677            .find(|hunk| hunk.row_range.start.0 > position.row)
16678            .map(|hunk| hunk.row_range.start);
16679
16680        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
16681        // Outside of the project diff editor, wrap around to the beginning.
16682        if !all_diff_hunks_expanded {
16683            row = row.or_else(|| {
16684                snapshot
16685                    .buffer_snapshot
16686                    .diff_hunks_in_range(Point::zero()..position)
16687                    .find(|hunk| hunk.row_range.end.0 < position.row)
16688                    .map(|hunk| hunk.row_range.start)
16689            });
16690        }
16691
16692        if let Some(row) = row {
16693            let destination = Point::new(row.0, 0);
16694            let autoscroll = Autoscroll::center();
16695
16696            self.unfold_ranges(&[destination..destination], false, false, cx);
16697            self.change_selections(Some(autoscroll), window, cx, |s| {
16698                s.select_ranges([destination..destination]);
16699            });
16700        }
16701    }
16702
16703    fn do_stage_or_unstage(
16704        &self,
16705        stage: bool,
16706        buffer_id: BufferId,
16707        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
16708        cx: &mut App,
16709    ) -> Option<()> {
16710        let project = self.project.as_ref()?;
16711        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
16712        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
16713        let buffer_snapshot = buffer.read(cx).snapshot();
16714        let file_exists = buffer_snapshot
16715            .file()
16716            .is_some_and(|file| file.disk_state().exists());
16717        diff.update(cx, |diff, cx| {
16718            diff.stage_or_unstage_hunks(
16719                stage,
16720                &hunks
16721                    .map(|hunk| buffer_diff::DiffHunk {
16722                        buffer_range: hunk.buffer_range,
16723                        diff_base_byte_range: hunk.diff_base_byte_range,
16724                        secondary_status: hunk.secondary_status,
16725                        range: Point::zero()..Point::zero(), // unused
16726                    })
16727                    .collect::<Vec<_>>(),
16728                &buffer_snapshot,
16729                file_exists,
16730                cx,
16731            )
16732        });
16733        None
16734    }
16735
16736    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
16737        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
16738        self.buffer
16739            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
16740    }
16741
16742    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
16743        self.buffer.update(cx, |buffer, cx| {
16744            let ranges = vec![Anchor::min()..Anchor::max()];
16745            if !buffer.all_diff_hunks_expanded()
16746                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
16747            {
16748                buffer.collapse_diff_hunks(ranges, cx);
16749                true
16750            } else {
16751                false
16752            }
16753        })
16754    }
16755
16756    fn toggle_diff_hunks_in_ranges(
16757        &mut self,
16758        ranges: Vec<Range<Anchor>>,
16759        cx: &mut Context<Editor>,
16760    ) {
16761        self.buffer.update(cx, |buffer, cx| {
16762            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
16763            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
16764        })
16765    }
16766
16767    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
16768        self.buffer.update(cx, |buffer, cx| {
16769            let snapshot = buffer.snapshot(cx);
16770            let excerpt_id = range.end.excerpt_id;
16771            let point_range = range.to_point(&snapshot);
16772            let expand = !buffer.single_hunk_is_expanded(range, cx);
16773            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
16774        })
16775    }
16776
16777    pub(crate) fn apply_all_diff_hunks(
16778        &mut self,
16779        _: &ApplyAllDiffHunks,
16780        window: &mut Window,
16781        cx: &mut Context<Self>,
16782    ) {
16783        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16784
16785        let buffers = self.buffer.read(cx).all_buffers();
16786        for branch_buffer in buffers {
16787            branch_buffer.update(cx, |branch_buffer, cx| {
16788                branch_buffer.merge_into_base(Vec::new(), cx);
16789            });
16790        }
16791
16792        if let Some(project) = self.project.clone() {
16793            self.save(true, project, window, cx).detach_and_log_err(cx);
16794        }
16795    }
16796
16797    pub(crate) fn apply_selected_diff_hunks(
16798        &mut self,
16799        _: &ApplyDiffHunk,
16800        window: &mut Window,
16801        cx: &mut Context<Self>,
16802    ) {
16803        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
16804        let snapshot = self.snapshot(window, cx);
16805        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
16806        let mut ranges_by_buffer = HashMap::default();
16807        self.transact(window, cx, |editor, _window, cx| {
16808            for hunk in hunks {
16809                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
16810                    ranges_by_buffer
16811                        .entry(buffer.clone())
16812                        .or_insert_with(Vec::new)
16813                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
16814                }
16815            }
16816
16817            for (buffer, ranges) in ranges_by_buffer {
16818                buffer.update(cx, |buffer, cx| {
16819                    buffer.merge_into_base(ranges, cx);
16820                });
16821            }
16822        });
16823
16824        if let Some(project) = self.project.clone() {
16825            self.save(true, project, window, cx).detach_and_log_err(cx);
16826        }
16827    }
16828
16829    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
16830        if hovered != self.gutter_hovered {
16831            self.gutter_hovered = hovered;
16832            cx.notify();
16833        }
16834    }
16835
16836    pub fn insert_blocks(
16837        &mut self,
16838        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
16839        autoscroll: Option<Autoscroll>,
16840        cx: &mut Context<Self>,
16841    ) -> Vec<CustomBlockId> {
16842        let blocks = self
16843            .display_map
16844            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
16845        if let Some(autoscroll) = autoscroll {
16846            self.request_autoscroll(autoscroll, cx);
16847        }
16848        cx.notify();
16849        blocks
16850    }
16851
16852    pub fn resize_blocks(
16853        &mut self,
16854        heights: HashMap<CustomBlockId, u32>,
16855        autoscroll: Option<Autoscroll>,
16856        cx: &mut Context<Self>,
16857    ) {
16858        self.display_map
16859            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
16860        if let Some(autoscroll) = autoscroll {
16861            self.request_autoscroll(autoscroll, cx);
16862        }
16863        cx.notify();
16864    }
16865
16866    pub fn replace_blocks(
16867        &mut self,
16868        renderers: HashMap<CustomBlockId, RenderBlock>,
16869        autoscroll: Option<Autoscroll>,
16870        cx: &mut Context<Self>,
16871    ) {
16872        self.display_map
16873            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
16874        if let Some(autoscroll) = autoscroll {
16875            self.request_autoscroll(autoscroll, cx);
16876        }
16877        cx.notify();
16878    }
16879
16880    pub fn remove_blocks(
16881        &mut self,
16882        block_ids: HashSet<CustomBlockId>,
16883        autoscroll: Option<Autoscroll>,
16884        cx: &mut Context<Self>,
16885    ) {
16886        self.display_map.update(cx, |display_map, cx| {
16887            display_map.remove_blocks(block_ids, cx)
16888        });
16889        if let Some(autoscroll) = autoscroll {
16890            self.request_autoscroll(autoscroll, cx);
16891        }
16892        cx.notify();
16893    }
16894
16895    pub fn row_for_block(
16896        &self,
16897        block_id: CustomBlockId,
16898        cx: &mut Context<Self>,
16899    ) -> Option<DisplayRow> {
16900        self.display_map
16901            .update(cx, |map, cx| map.row_for_block(block_id, cx))
16902    }
16903
16904    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
16905        self.focused_block = Some(focused_block);
16906    }
16907
16908    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
16909        self.focused_block.take()
16910    }
16911
16912    pub fn insert_creases(
16913        &mut self,
16914        creases: impl IntoIterator<Item = Crease<Anchor>>,
16915        cx: &mut Context<Self>,
16916    ) -> Vec<CreaseId> {
16917        self.display_map
16918            .update(cx, |map, cx| map.insert_creases(creases, cx))
16919    }
16920
16921    pub fn remove_creases(
16922        &mut self,
16923        ids: impl IntoIterator<Item = CreaseId>,
16924        cx: &mut Context<Self>,
16925    ) -> Vec<(CreaseId, Range<Anchor>)> {
16926        self.display_map
16927            .update(cx, |map, cx| map.remove_creases(ids, cx))
16928    }
16929
16930    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
16931        self.display_map
16932            .update(cx, |map, cx| map.snapshot(cx))
16933            .longest_row()
16934    }
16935
16936    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
16937        self.display_map
16938            .update(cx, |map, cx| map.snapshot(cx))
16939            .max_point()
16940    }
16941
16942    pub fn text(&self, cx: &App) -> String {
16943        self.buffer.read(cx).read(cx).text()
16944    }
16945
16946    pub fn is_empty(&self, cx: &App) -> bool {
16947        self.buffer.read(cx).read(cx).is_empty()
16948    }
16949
16950    pub fn text_option(&self, cx: &App) -> Option<String> {
16951        let text = self.text(cx);
16952        let text = text.trim();
16953
16954        if text.is_empty() {
16955            return None;
16956        }
16957
16958        Some(text.to_string())
16959    }
16960
16961    pub fn set_text(
16962        &mut self,
16963        text: impl Into<Arc<str>>,
16964        window: &mut Window,
16965        cx: &mut Context<Self>,
16966    ) {
16967        self.transact(window, cx, |this, _, cx| {
16968            this.buffer
16969                .read(cx)
16970                .as_singleton()
16971                .expect("you can only call set_text on editors for singleton buffers")
16972                .update(cx, |buffer, cx| buffer.set_text(text, cx));
16973        });
16974    }
16975
16976    pub fn display_text(&self, cx: &mut App) -> String {
16977        self.display_map
16978            .update(cx, |map, cx| map.snapshot(cx))
16979            .text()
16980    }
16981
16982    fn create_minimap(
16983        &self,
16984        minimap_settings: MinimapSettings,
16985        window: &mut Window,
16986        cx: &mut Context<Self>,
16987    ) -> Option<Entity<Self>> {
16988        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
16989            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
16990    }
16991
16992    fn initialize_new_minimap(
16993        &self,
16994        minimap_settings: MinimapSettings,
16995        window: &mut Window,
16996        cx: &mut Context<Self>,
16997    ) -> Entity<Self> {
16998        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
16999
17000        let mut minimap = Editor::new_internal(
17001            EditorMode::Minimap {
17002                parent: cx.weak_entity(),
17003            },
17004            self.buffer.clone(),
17005            self.project.clone(),
17006            Some(self.display_map.clone()),
17007            window,
17008            cx,
17009        );
17010        minimap.scroll_manager.clone_state(&self.scroll_manager);
17011        minimap.set_text_style_refinement(TextStyleRefinement {
17012            font_size: Some(MINIMAP_FONT_SIZE),
17013            font_weight: Some(MINIMAP_FONT_WEIGHT),
17014            ..Default::default()
17015        });
17016        minimap.update_minimap_configuration(minimap_settings, cx);
17017        cx.new(|_| minimap)
17018    }
17019
17020    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
17021        let current_line_highlight = minimap_settings
17022            .current_line_highlight
17023            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
17024        self.set_current_line_highlight(Some(current_line_highlight));
17025    }
17026
17027    pub fn minimap(&self) -> Option<&Entity<Self>> {
17028        self.minimap
17029            .as_ref()
17030            .filter(|_| self.minimap_visibility.visible())
17031    }
17032
17033    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
17034        let mut wrap_guides = smallvec![];
17035
17036        if self.show_wrap_guides == Some(false) {
17037            return wrap_guides;
17038        }
17039
17040        let settings = self.buffer.read(cx).language_settings(cx);
17041        if settings.show_wrap_guides {
17042            match self.soft_wrap_mode(cx) {
17043                SoftWrap::Column(soft_wrap) => {
17044                    wrap_guides.push((soft_wrap as usize, true));
17045                }
17046                SoftWrap::Bounded(soft_wrap) => {
17047                    wrap_guides.push((soft_wrap as usize, true));
17048                }
17049                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
17050            }
17051            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
17052        }
17053
17054        wrap_guides
17055    }
17056
17057    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
17058        let settings = self.buffer.read(cx).language_settings(cx);
17059        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
17060        match mode {
17061            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
17062                SoftWrap::None
17063            }
17064            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
17065            language_settings::SoftWrap::PreferredLineLength => {
17066                SoftWrap::Column(settings.preferred_line_length)
17067            }
17068            language_settings::SoftWrap::Bounded => {
17069                SoftWrap::Bounded(settings.preferred_line_length)
17070            }
17071        }
17072    }
17073
17074    pub fn set_soft_wrap_mode(
17075        &mut self,
17076        mode: language_settings::SoftWrap,
17077
17078        cx: &mut Context<Self>,
17079    ) {
17080        self.soft_wrap_mode_override = Some(mode);
17081        cx.notify();
17082    }
17083
17084    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
17085        self.hard_wrap = hard_wrap;
17086        cx.notify();
17087    }
17088
17089    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
17090        self.text_style_refinement = Some(style);
17091    }
17092
17093    /// called by the Element so we know what style we were most recently rendered with.
17094    pub(crate) fn set_style(
17095        &mut self,
17096        style: EditorStyle,
17097        window: &mut Window,
17098        cx: &mut Context<Self>,
17099    ) {
17100        // We intentionally do not inform the display map about the minimap style
17101        // so that wrapping is not recalculated and stays consistent for the editor
17102        // and its linked minimap.
17103        if !self.mode.is_minimap() {
17104            let rem_size = window.rem_size();
17105            self.display_map.update(cx, |map, cx| {
17106                map.set_font(
17107                    style.text.font(),
17108                    style.text.font_size.to_pixels(rem_size),
17109                    cx,
17110                )
17111            });
17112        }
17113        self.style = Some(style);
17114    }
17115
17116    pub fn style(&self) -> Option<&EditorStyle> {
17117        self.style.as_ref()
17118    }
17119
17120    // Called by the element. This method is not designed to be called outside of the editor
17121    // element's layout code because it does not notify when rewrapping is computed synchronously.
17122    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
17123        self.display_map
17124            .update(cx, |map, cx| map.set_wrap_width(width, cx))
17125    }
17126
17127    pub fn set_soft_wrap(&mut self) {
17128        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
17129    }
17130
17131    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
17132        if self.soft_wrap_mode_override.is_some() {
17133            self.soft_wrap_mode_override.take();
17134        } else {
17135            let soft_wrap = match self.soft_wrap_mode(cx) {
17136                SoftWrap::GitDiff => return,
17137                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
17138                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
17139                    language_settings::SoftWrap::None
17140                }
17141            };
17142            self.soft_wrap_mode_override = Some(soft_wrap);
17143        }
17144        cx.notify();
17145    }
17146
17147    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
17148        let Some(workspace) = self.workspace() else {
17149            return;
17150        };
17151        let fs = workspace.read(cx).app_state().fs.clone();
17152        let current_show = TabBarSettings::get_global(cx).show;
17153        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
17154            setting.show = Some(!current_show);
17155        });
17156    }
17157
17158    pub fn toggle_indent_guides(
17159        &mut self,
17160        _: &ToggleIndentGuides,
17161        _: &mut Window,
17162        cx: &mut Context<Self>,
17163    ) {
17164        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
17165            self.buffer
17166                .read(cx)
17167                .language_settings(cx)
17168                .indent_guides
17169                .enabled
17170        });
17171        self.show_indent_guides = Some(!currently_enabled);
17172        cx.notify();
17173    }
17174
17175    fn should_show_indent_guides(&self) -> Option<bool> {
17176        self.show_indent_guides
17177    }
17178
17179    pub fn toggle_line_numbers(
17180        &mut self,
17181        _: &ToggleLineNumbers,
17182        _: &mut Window,
17183        cx: &mut Context<Self>,
17184    ) {
17185        let mut editor_settings = EditorSettings::get_global(cx).clone();
17186        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
17187        EditorSettings::override_global(editor_settings, cx);
17188    }
17189
17190    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
17191        if let Some(show_line_numbers) = self.show_line_numbers {
17192            return show_line_numbers;
17193        }
17194        EditorSettings::get_global(cx).gutter.line_numbers
17195    }
17196
17197    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
17198        self.use_relative_line_numbers
17199            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
17200    }
17201
17202    pub fn toggle_relative_line_numbers(
17203        &mut self,
17204        _: &ToggleRelativeLineNumbers,
17205        _: &mut Window,
17206        cx: &mut Context<Self>,
17207    ) {
17208        let is_relative = self.should_use_relative_line_numbers(cx);
17209        self.set_relative_line_number(Some(!is_relative), cx)
17210    }
17211
17212    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
17213        self.use_relative_line_numbers = is_relative;
17214        cx.notify();
17215    }
17216
17217    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
17218        self.show_gutter = show_gutter;
17219        cx.notify();
17220    }
17221
17222    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
17223        self.show_scrollbars = ScrollbarAxes {
17224            horizontal: show,
17225            vertical: show,
17226        };
17227        cx.notify();
17228    }
17229
17230    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17231        self.show_scrollbars.vertical = show;
17232        cx.notify();
17233    }
17234
17235    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
17236        self.show_scrollbars.horizontal = show;
17237        cx.notify();
17238    }
17239
17240    pub fn set_minimap_visibility(
17241        &mut self,
17242        minimap_visibility: MinimapVisibility,
17243        window: &mut Window,
17244        cx: &mut Context<Self>,
17245    ) {
17246        if self.minimap_visibility != minimap_visibility {
17247            if minimap_visibility.visible() && self.minimap.is_none() {
17248                let minimap_settings = EditorSettings::get_global(cx).minimap;
17249                self.minimap =
17250                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
17251            }
17252            self.minimap_visibility = minimap_visibility;
17253            cx.notify();
17254        }
17255    }
17256
17257    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17258        self.set_show_scrollbars(false, cx);
17259        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
17260    }
17261
17262    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
17263        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
17264    }
17265
17266    /// Normally the text in full mode and auto height editors is padded on the
17267    /// left side by roughly half a character width for improved hit testing.
17268    ///
17269    /// Use this method to disable this for cases where this is not wanted (e.g.
17270    /// if you want to align the editor text with some other text above or below)
17271    /// or if you want to add this padding to single-line editors.
17272    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
17273        self.offset_content = offset_content;
17274        cx.notify();
17275    }
17276
17277    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
17278        self.show_line_numbers = Some(show_line_numbers);
17279        cx.notify();
17280    }
17281
17282    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
17283        self.disable_expand_excerpt_buttons = true;
17284        cx.notify();
17285    }
17286
17287    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
17288        self.show_git_diff_gutter = Some(show_git_diff_gutter);
17289        cx.notify();
17290    }
17291
17292    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
17293        self.show_code_actions = Some(show_code_actions);
17294        cx.notify();
17295    }
17296
17297    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
17298        self.show_runnables = Some(show_runnables);
17299        cx.notify();
17300    }
17301
17302    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
17303        self.show_breakpoints = Some(show_breakpoints);
17304        cx.notify();
17305    }
17306
17307    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
17308        if self.display_map.read(cx).masked != masked {
17309            self.display_map.update(cx, |map, _| map.masked = masked);
17310        }
17311        cx.notify()
17312    }
17313
17314    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
17315        self.show_wrap_guides = Some(show_wrap_guides);
17316        cx.notify();
17317    }
17318
17319    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
17320        self.show_indent_guides = Some(show_indent_guides);
17321        cx.notify();
17322    }
17323
17324    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
17325        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
17326            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
17327                if let Some(dir) = file.abs_path(cx).parent() {
17328                    return Some(dir.to_owned());
17329                }
17330            }
17331
17332            if let Some(project_path) = buffer.read(cx).project_path(cx) {
17333                return Some(project_path.path.to_path_buf());
17334            }
17335        }
17336
17337        None
17338    }
17339
17340    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
17341        self.active_excerpt(cx)?
17342            .1
17343            .read(cx)
17344            .file()
17345            .and_then(|f| f.as_local())
17346    }
17347
17348    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17349        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17350            let buffer = buffer.read(cx);
17351            if let Some(project_path) = buffer.project_path(cx) {
17352                let project = self.project.as_ref()?.read(cx);
17353                project.absolute_path(&project_path, cx)
17354            } else {
17355                buffer
17356                    .file()
17357                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
17358            }
17359        })
17360    }
17361
17362    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
17363        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
17364            let project_path = buffer.read(cx).project_path(cx)?;
17365            let project = self.project.as_ref()?.read(cx);
17366            let entry = project.entry_for_path(&project_path, cx)?;
17367            let path = entry.path.to_path_buf();
17368            Some(path)
17369        })
17370    }
17371
17372    pub fn reveal_in_finder(
17373        &mut self,
17374        _: &RevealInFileManager,
17375        _window: &mut Window,
17376        cx: &mut Context<Self>,
17377    ) {
17378        if let Some(target) = self.target_file(cx) {
17379            cx.reveal_path(&target.abs_path(cx));
17380        }
17381    }
17382
17383    pub fn copy_path(
17384        &mut self,
17385        _: &zed_actions::workspace::CopyPath,
17386        _window: &mut Window,
17387        cx: &mut Context<Self>,
17388    ) {
17389        if let Some(path) = self.target_file_abs_path(cx) {
17390            if let Some(path) = path.to_str() {
17391                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17392            }
17393        }
17394    }
17395
17396    pub fn copy_relative_path(
17397        &mut self,
17398        _: &zed_actions::workspace::CopyRelativePath,
17399        _window: &mut Window,
17400        cx: &mut Context<Self>,
17401    ) {
17402        if let Some(path) = self.target_file_path(cx) {
17403            if let Some(path) = path.to_str() {
17404                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
17405            }
17406        }
17407    }
17408
17409    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
17410        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
17411            buffer.read(cx).project_path(cx)
17412        } else {
17413            None
17414        }
17415    }
17416
17417    // Returns true if the editor handled a go-to-line request
17418    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
17419        maybe!({
17420            let breakpoint_store = self.breakpoint_store.as_ref()?;
17421
17422            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
17423            else {
17424                self.clear_row_highlights::<ActiveDebugLine>();
17425                return None;
17426            };
17427
17428            let position = active_stack_frame.position;
17429            let buffer_id = position.buffer_id?;
17430            let snapshot = self
17431                .project
17432                .as_ref()?
17433                .read(cx)
17434                .buffer_for_id(buffer_id, cx)?
17435                .read(cx)
17436                .snapshot();
17437
17438            let mut handled = false;
17439            for (id, ExcerptRange { context, .. }) in
17440                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
17441            {
17442                if context.start.cmp(&position, &snapshot).is_ge()
17443                    || context.end.cmp(&position, &snapshot).is_lt()
17444                {
17445                    continue;
17446                }
17447                let snapshot = self.buffer.read(cx).snapshot(cx);
17448                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
17449
17450                handled = true;
17451                self.clear_row_highlights::<ActiveDebugLine>();
17452
17453                self.go_to_line::<ActiveDebugLine>(
17454                    multibuffer_anchor,
17455                    Some(cx.theme().colors().editor_debugger_active_line_background),
17456                    window,
17457                    cx,
17458                );
17459
17460                cx.notify();
17461            }
17462
17463            handled.then_some(())
17464        })
17465        .is_some()
17466    }
17467
17468    pub fn copy_file_name_without_extension(
17469        &mut self,
17470        _: &CopyFileNameWithoutExtension,
17471        _: &mut Window,
17472        cx: &mut Context<Self>,
17473    ) {
17474        if let Some(file) = self.target_file(cx) {
17475            if let Some(file_stem) = file.path().file_stem() {
17476                if let Some(name) = file_stem.to_str() {
17477                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17478                }
17479            }
17480        }
17481    }
17482
17483    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
17484        if let Some(file) = self.target_file(cx) {
17485            if let Some(file_name) = file.path().file_name() {
17486                if let Some(name) = file_name.to_str() {
17487                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
17488                }
17489            }
17490        }
17491    }
17492
17493    pub fn toggle_git_blame(
17494        &mut self,
17495        _: &::git::Blame,
17496        window: &mut Window,
17497        cx: &mut Context<Self>,
17498    ) {
17499        self.show_git_blame_gutter = !self.show_git_blame_gutter;
17500
17501        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
17502            self.start_git_blame(true, window, cx);
17503        }
17504
17505        cx.notify();
17506    }
17507
17508    pub fn toggle_git_blame_inline(
17509        &mut self,
17510        _: &ToggleGitBlameInline,
17511        window: &mut Window,
17512        cx: &mut Context<Self>,
17513    ) {
17514        self.toggle_git_blame_inline_internal(true, window, cx);
17515        cx.notify();
17516    }
17517
17518    pub fn open_git_blame_commit(
17519        &mut self,
17520        _: &OpenGitBlameCommit,
17521        window: &mut Window,
17522        cx: &mut Context<Self>,
17523    ) {
17524        self.open_git_blame_commit_internal(window, cx);
17525    }
17526
17527    fn open_git_blame_commit_internal(
17528        &mut self,
17529        window: &mut Window,
17530        cx: &mut Context<Self>,
17531    ) -> Option<()> {
17532        let blame = self.blame.as_ref()?;
17533        let snapshot = self.snapshot(window, cx);
17534        let cursor = self.selections.newest::<Point>(cx).head();
17535        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
17536        let blame_entry = blame
17537            .update(cx, |blame, cx| {
17538                blame
17539                    .blame_for_rows(
17540                        &[RowInfo {
17541                            buffer_id: Some(buffer.remote_id()),
17542                            buffer_row: Some(point.row),
17543                            ..Default::default()
17544                        }],
17545                        cx,
17546                    )
17547                    .next()
17548            })
17549            .flatten()?;
17550        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
17551        let repo = blame.read(cx).repository(cx)?;
17552        let workspace = self.workspace()?.downgrade();
17553        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
17554        None
17555    }
17556
17557    pub fn git_blame_inline_enabled(&self) -> bool {
17558        self.git_blame_inline_enabled
17559    }
17560
17561    pub fn toggle_selection_menu(
17562        &mut self,
17563        _: &ToggleSelectionMenu,
17564        _: &mut Window,
17565        cx: &mut Context<Self>,
17566    ) {
17567        self.show_selection_menu = self
17568            .show_selection_menu
17569            .map(|show_selections_menu| !show_selections_menu)
17570            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
17571
17572        cx.notify();
17573    }
17574
17575    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
17576        self.show_selection_menu
17577            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
17578    }
17579
17580    fn start_git_blame(
17581        &mut self,
17582        user_triggered: bool,
17583        window: &mut Window,
17584        cx: &mut Context<Self>,
17585    ) {
17586        if let Some(project) = self.project.as_ref() {
17587            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
17588                return;
17589            };
17590
17591            if buffer.read(cx).file().is_none() {
17592                return;
17593            }
17594
17595            let focused = self.focus_handle(cx).contains_focused(window, cx);
17596
17597            let project = project.clone();
17598            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
17599            self.blame_subscription =
17600                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
17601            self.blame = Some(blame);
17602        }
17603    }
17604
17605    fn toggle_git_blame_inline_internal(
17606        &mut self,
17607        user_triggered: bool,
17608        window: &mut Window,
17609        cx: &mut Context<Self>,
17610    ) {
17611        if self.git_blame_inline_enabled {
17612            self.git_blame_inline_enabled = false;
17613            self.show_git_blame_inline = false;
17614            self.show_git_blame_inline_delay_task.take();
17615        } else {
17616            self.git_blame_inline_enabled = true;
17617            self.start_git_blame_inline(user_triggered, window, cx);
17618        }
17619
17620        cx.notify();
17621    }
17622
17623    fn start_git_blame_inline(
17624        &mut self,
17625        user_triggered: bool,
17626        window: &mut Window,
17627        cx: &mut Context<Self>,
17628    ) {
17629        self.start_git_blame(user_triggered, window, cx);
17630
17631        if ProjectSettings::get_global(cx)
17632            .git
17633            .inline_blame_delay()
17634            .is_some()
17635        {
17636            self.start_inline_blame_timer(window, cx);
17637        } else {
17638            self.show_git_blame_inline = true
17639        }
17640    }
17641
17642    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
17643        self.blame.as_ref()
17644    }
17645
17646    pub fn show_git_blame_gutter(&self) -> bool {
17647        self.show_git_blame_gutter
17648    }
17649
17650    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
17651        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
17652    }
17653
17654    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
17655        self.show_git_blame_inline
17656            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
17657            && !self.newest_selection_head_on_empty_line(cx)
17658            && self.has_blame_entries(cx)
17659    }
17660
17661    fn has_blame_entries(&self, cx: &App) -> bool {
17662        self.blame()
17663            .map_or(false, |blame| blame.read(cx).has_generated_entries())
17664    }
17665
17666    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
17667        let cursor_anchor = self.selections.newest_anchor().head();
17668
17669        let snapshot = self.buffer.read(cx).snapshot(cx);
17670        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
17671
17672        snapshot.line_len(buffer_row) == 0
17673    }
17674
17675    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
17676        let buffer_and_selection = maybe!({
17677            let selection = self.selections.newest::<Point>(cx);
17678            let selection_range = selection.range();
17679
17680            let multi_buffer = self.buffer().read(cx);
17681            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17682            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
17683
17684            let (buffer, range, _) = if selection.reversed {
17685                buffer_ranges.first()
17686            } else {
17687                buffer_ranges.last()
17688            }?;
17689
17690            let selection = text::ToPoint::to_point(&range.start, &buffer).row
17691                ..text::ToPoint::to_point(&range.end, &buffer).row;
17692            Some((
17693                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
17694                selection,
17695            ))
17696        });
17697
17698        let Some((buffer, selection)) = buffer_and_selection else {
17699            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
17700        };
17701
17702        let Some(project) = self.project.as_ref() else {
17703            return Task::ready(Err(anyhow!("editor does not have project")));
17704        };
17705
17706        project.update(cx, |project, cx| {
17707            project.get_permalink_to_line(&buffer, selection, cx)
17708        })
17709    }
17710
17711    pub fn copy_permalink_to_line(
17712        &mut self,
17713        _: &CopyPermalinkToLine,
17714        window: &mut Window,
17715        cx: &mut Context<Self>,
17716    ) {
17717        let permalink_task = self.get_permalink_to_line(cx);
17718        let workspace = self.workspace();
17719
17720        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17721            Ok(permalink) => {
17722                cx.update(|_, cx| {
17723                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
17724                })
17725                .ok();
17726            }
17727            Err(err) => {
17728                let message = format!("Failed to copy permalink: {err}");
17729
17730                anyhow::Result::<()>::Err(err).log_err();
17731
17732                if let Some(workspace) = workspace {
17733                    workspace
17734                        .update_in(cx, |workspace, _, cx| {
17735                            struct CopyPermalinkToLine;
17736
17737                            workspace.show_toast(
17738                                Toast::new(
17739                                    NotificationId::unique::<CopyPermalinkToLine>(),
17740                                    message,
17741                                ),
17742                                cx,
17743                            )
17744                        })
17745                        .ok();
17746                }
17747            }
17748        })
17749        .detach();
17750    }
17751
17752    pub fn copy_file_location(
17753        &mut self,
17754        _: &CopyFileLocation,
17755        _: &mut Window,
17756        cx: &mut Context<Self>,
17757    ) {
17758        let selection = self.selections.newest::<Point>(cx).start.row + 1;
17759        if let Some(file) = self.target_file(cx) {
17760            if let Some(path) = file.path().to_str() {
17761                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
17762            }
17763        }
17764    }
17765
17766    pub fn open_permalink_to_line(
17767        &mut self,
17768        _: &OpenPermalinkToLine,
17769        window: &mut Window,
17770        cx: &mut Context<Self>,
17771    ) {
17772        let permalink_task = self.get_permalink_to_line(cx);
17773        let workspace = self.workspace();
17774
17775        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
17776            Ok(permalink) => {
17777                cx.update(|_, cx| {
17778                    cx.open_url(permalink.as_ref());
17779                })
17780                .ok();
17781            }
17782            Err(err) => {
17783                let message = format!("Failed to open permalink: {err}");
17784
17785                anyhow::Result::<()>::Err(err).log_err();
17786
17787                if let Some(workspace) = workspace {
17788                    workspace
17789                        .update(cx, |workspace, cx| {
17790                            struct OpenPermalinkToLine;
17791
17792                            workspace.show_toast(
17793                                Toast::new(
17794                                    NotificationId::unique::<OpenPermalinkToLine>(),
17795                                    message,
17796                                ),
17797                                cx,
17798                            )
17799                        })
17800                        .ok();
17801                }
17802            }
17803        })
17804        .detach();
17805    }
17806
17807    pub fn insert_uuid_v4(
17808        &mut self,
17809        _: &InsertUuidV4,
17810        window: &mut Window,
17811        cx: &mut Context<Self>,
17812    ) {
17813        self.insert_uuid(UuidVersion::V4, window, cx);
17814    }
17815
17816    pub fn insert_uuid_v7(
17817        &mut self,
17818        _: &InsertUuidV7,
17819        window: &mut Window,
17820        cx: &mut Context<Self>,
17821    ) {
17822        self.insert_uuid(UuidVersion::V7, window, cx);
17823    }
17824
17825    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
17826        self.hide_mouse_cursor(&HideMouseCursorOrigin::TypingAction);
17827        self.transact(window, cx, |this, window, cx| {
17828            let edits = this
17829                .selections
17830                .all::<Point>(cx)
17831                .into_iter()
17832                .map(|selection| {
17833                    let uuid = match version {
17834                        UuidVersion::V4 => uuid::Uuid::new_v4(),
17835                        UuidVersion::V7 => uuid::Uuid::now_v7(),
17836                    };
17837
17838                    (selection.range(), uuid.to_string())
17839                });
17840            this.edit(edits, cx);
17841            this.refresh_inline_completion(true, false, window, cx);
17842        });
17843    }
17844
17845    pub fn open_selections_in_multibuffer(
17846        &mut self,
17847        _: &OpenSelectionsInMultibuffer,
17848        window: &mut Window,
17849        cx: &mut Context<Self>,
17850    ) {
17851        let multibuffer = self.buffer.read(cx);
17852
17853        let Some(buffer) = multibuffer.as_singleton() else {
17854            return;
17855        };
17856
17857        let Some(workspace) = self.workspace() else {
17858            return;
17859        };
17860
17861        let locations = self
17862            .selections
17863            .disjoint_anchors()
17864            .iter()
17865            .map(|selection| {
17866                let range = if selection.reversed {
17867                    selection.end.text_anchor..selection.start.text_anchor
17868                } else {
17869                    selection.start.text_anchor..selection.end.text_anchor
17870                };
17871                Location {
17872                    buffer: buffer.clone(),
17873                    range,
17874                }
17875            })
17876            .collect::<Vec<_>>();
17877
17878        let title = multibuffer.title(cx).to_string();
17879
17880        cx.spawn_in(window, async move |_, cx| {
17881            workspace.update_in(cx, |workspace, window, cx| {
17882                Self::open_locations_in_multibuffer(
17883                    workspace,
17884                    locations,
17885                    format!("Selections for '{title}'"),
17886                    false,
17887                    MultibufferSelectionMode::All,
17888                    window,
17889                    cx,
17890                );
17891            })
17892        })
17893        .detach();
17894    }
17895
17896    /// Adds a row highlight for the given range. If a row has multiple highlights, the
17897    /// last highlight added will be used.
17898    ///
17899    /// If the range ends at the beginning of a line, then that line will not be highlighted.
17900    pub fn highlight_rows<T: 'static>(
17901        &mut self,
17902        range: Range<Anchor>,
17903        color: Hsla,
17904        options: RowHighlightOptions,
17905        cx: &mut Context<Self>,
17906    ) {
17907        let snapshot = self.buffer().read(cx).snapshot(cx);
17908        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17909        let ix = row_highlights.binary_search_by(|highlight| {
17910            Ordering::Equal
17911                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
17912                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
17913        });
17914
17915        if let Err(mut ix) = ix {
17916            let index = post_inc(&mut self.highlight_order);
17917
17918            // If this range intersects with the preceding highlight, then merge it with
17919            // the preceding highlight. Otherwise insert a new highlight.
17920            let mut merged = false;
17921            if ix > 0 {
17922                let prev_highlight = &mut row_highlights[ix - 1];
17923                if prev_highlight
17924                    .range
17925                    .end
17926                    .cmp(&range.start, &snapshot)
17927                    .is_ge()
17928                {
17929                    ix -= 1;
17930                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
17931                        prev_highlight.range.end = range.end;
17932                    }
17933                    merged = true;
17934                    prev_highlight.index = index;
17935                    prev_highlight.color = color;
17936                    prev_highlight.options = options;
17937                }
17938            }
17939
17940            if !merged {
17941                row_highlights.insert(
17942                    ix,
17943                    RowHighlight {
17944                        range: range.clone(),
17945                        index,
17946                        color,
17947                        options,
17948                        type_id: TypeId::of::<T>(),
17949                    },
17950                );
17951            }
17952
17953            // If any of the following highlights intersect with this one, merge them.
17954            while let Some(next_highlight) = row_highlights.get(ix + 1) {
17955                let highlight = &row_highlights[ix];
17956                if next_highlight
17957                    .range
17958                    .start
17959                    .cmp(&highlight.range.end, &snapshot)
17960                    .is_le()
17961                {
17962                    if next_highlight
17963                        .range
17964                        .end
17965                        .cmp(&highlight.range.end, &snapshot)
17966                        .is_gt()
17967                    {
17968                        row_highlights[ix].range.end = next_highlight.range.end;
17969                    }
17970                    row_highlights.remove(ix + 1);
17971                } else {
17972                    break;
17973                }
17974            }
17975        }
17976    }
17977
17978    /// Remove any highlighted row ranges of the given type that intersect the
17979    /// given ranges.
17980    pub fn remove_highlighted_rows<T: 'static>(
17981        &mut self,
17982        ranges_to_remove: Vec<Range<Anchor>>,
17983        cx: &mut Context<Self>,
17984    ) {
17985        let snapshot = self.buffer().read(cx).snapshot(cx);
17986        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
17987        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
17988        row_highlights.retain(|highlight| {
17989            while let Some(range_to_remove) = ranges_to_remove.peek() {
17990                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
17991                    Ordering::Less | Ordering::Equal => {
17992                        ranges_to_remove.next();
17993                    }
17994                    Ordering::Greater => {
17995                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
17996                            Ordering::Less | Ordering::Equal => {
17997                                return false;
17998                            }
17999                            Ordering::Greater => break,
18000                        }
18001                    }
18002                }
18003            }
18004
18005            true
18006        })
18007    }
18008
18009    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
18010    pub fn clear_row_highlights<T: 'static>(&mut self) {
18011        self.highlighted_rows.remove(&TypeId::of::<T>());
18012    }
18013
18014    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
18015    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
18016        self.highlighted_rows
18017            .get(&TypeId::of::<T>())
18018            .map_or(&[] as &[_], |vec| vec.as_slice())
18019            .iter()
18020            .map(|highlight| (highlight.range.clone(), highlight.color))
18021    }
18022
18023    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
18024    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
18025    /// Allows to ignore certain kinds of highlights.
18026    pub fn highlighted_display_rows(
18027        &self,
18028        window: &mut Window,
18029        cx: &mut App,
18030    ) -> BTreeMap<DisplayRow, LineHighlight> {
18031        let snapshot = self.snapshot(window, cx);
18032        let mut used_highlight_orders = HashMap::default();
18033        self.highlighted_rows
18034            .iter()
18035            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
18036            .fold(
18037                BTreeMap::<DisplayRow, LineHighlight>::new(),
18038                |mut unique_rows, highlight| {
18039                    let start = highlight.range.start.to_display_point(&snapshot);
18040                    let end = highlight.range.end.to_display_point(&snapshot);
18041                    let start_row = start.row().0;
18042                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
18043                        && end.column() == 0
18044                    {
18045                        end.row().0.saturating_sub(1)
18046                    } else {
18047                        end.row().0
18048                    };
18049                    for row in start_row..=end_row {
18050                        let used_index =
18051                            used_highlight_orders.entry(row).or_insert(highlight.index);
18052                        if highlight.index >= *used_index {
18053                            *used_index = highlight.index;
18054                            unique_rows.insert(
18055                                DisplayRow(row),
18056                                LineHighlight {
18057                                    include_gutter: highlight.options.include_gutter,
18058                                    border: None,
18059                                    background: highlight.color.into(),
18060                                    type_id: Some(highlight.type_id),
18061                                },
18062                            );
18063                        }
18064                    }
18065                    unique_rows
18066                },
18067            )
18068    }
18069
18070    pub fn highlighted_display_row_for_autoscroll(
18071        &self,
18072        snapshot: &DisplaySnapshot,
18073    ) -> Option<DisplayRow> {
18074        self.highlighted_rows
18075            .values()
18076            .flat_map(|highlighted_rows| highlighted_rows.iter())
18077            .filter_map(|highlight| {
18078                if highlight.options.autoscroll {
18079                    Some(highlight.range.start.to_display_point(snapshot).row())
18080                } else {
18081                    None
18082                }
18083            })
18084            .min()
18085    }
18086
18087    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
18088        self.highlight_background::<SearchWithinRange>(
18089            ranges,
18090            |colors| colors.editor_document_highlight_read_background,
18091            cx,
18092        )
18093    }
18094
18095    pub fn set_breadcrumb_header(&mut self, new_header: String) {
18096        self.breadcrumb_header = Some(new_header);
18097    }
18098
18099    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
18100        self.clear_background_highlights::<SearchWithinRange>(cx);
18101    }
18102
18103    pub fn highlight_background<T: 'static>(
18104        &mut self,
18105        ranges: &[Range<Anchor>],
18106        color_fetcher: fn(&ThemeColors) -> Hsla,
18107        cx: &mut Context<Self>,
18108    ) {
18109        self.background_highlights
18110            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18111        self.scrollbar_marker_state.dirty = true;
18112        cx.notify();
18113    }
18114
18115    pub fn clear_background_highlights<T: 'static>(
18116        &mut self,
18117        cx: &mut Context<Self>,
18118    ) -> Option<BackgroundHighlight> {
18119        let text_highlights = self.background_highlights.remove(&TypeId::of::<T>())?;
18120        if !text_highlights.1.is_empty() {
18121            self.scrollbar_marker_state.dirty = true;
18122            cx.notify();
18123        }
18124        Some(text_highlights)
18125    }
18126
18127    pub fn highlight_gutter<T: 'static>(
18128        &mut self,
18129        ranges: &[Range<Anchor>],
18130        color_fetcher: fn(&App) -> Hsla,
18131        cx: &mut Context<Self>,
18132    ) {
18133        self.gutter_highlights
18134            .insert(TypeId::of::<T>(), (color_fetcher, Arc::from(ranges)));
18135        cx.notify();
18136    }
18137
18138    pub fn clear_gutter_highlights<T: 'static>(
18139        &mut self,
18140        cx: &mut Context<Self>,
18141    ) -> Option<GutterHighlight> {
18142        cx.notify();
18143        self.gutter_highlights.remove(&TypeId::of::<T>())
18144    }
18145
18146    #[cfg(feature = "test-support")]
18147    pub fn all_text_background_highlights(
18148        &self,
18149        window: &mut Window,
18150        cx: &mut Context<Self>,
18151    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18152        let snapshot = self.snapshot(window, cx);
18153        let buffer = &snapshot.buffer_snapshot;
18154        let start = buffer.anchor_before(0);
18155        let end = buffer.anchor_after(buffer.len());
18156        let theme = cx.theme().colors();
18157        self.background_highlights_in_range(start..end, &snapshot, theme)
18158    }
18159
18160    #[cfg(feature = "test-support")]
18161    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
18162        let snapshot = self.buffer().read(cx).snapshot(cx);
18163
18164        let highlights = self
18165            .background_highlights
18166            .get(&TypeId::of::<items::BufferSearchHighlights>());
18167
18168        if let Some((_color, ranges)) = highlights {
18169            ranges
18170                .iter()
18171                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
18172                .collect_vec()
18173        } else {
18174            vec![]
18175        }
18176    }
18177
18178    fn document_highlights_for_position<'a>(
18179        &'a self,
18180        position: Anchor,
18181        buffer: &'a MultiBufferSnapshot,
18182    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
18183        let read_highlights = self
18184            .background_highlights
18185            .get(&TypeId::of::<DocumentHighlightRead>())
18186            .map(|h| &h.1);
18187        let write_highlights = self
18188            .background_highlights
18189            .get(&TypeId::of::<DocumentHighlightWrite>())
18190            .map(|h| &h.1);
18191        let left_position = position.bias_left(buffer);
18192        let right_position = position.bias_right(buffer);
18193        read_highlights
18194            .into_iter()
18195            .chain(write_highlights)
18196            .flat_map(move |ranges| {
18197                let start_ix = match ranges.binary_search_by(|probe| {
18198                    let cmp = probe.end.cmp(&left_position, buffer);
18199                    if cmp.is_ge() {
18200                        Ordering::Greater
18201                    } else {
18202                        Ordering::Less
18203                    }
18204                }) {
18205                    Ok(i) | Err(i) => i,
18206                };
18207
18208                ranges[start_ix..]
18209                    .iter()
18210                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
18211            })
18212    }
18213
18214    pub fn has_background_highlights<T: 'static>(&self) -> bool {
18215        self.background_highlights
18216            .get(&TypeId::of::<T>())
18217            .map_or(false, |(_, highlights)| !highlights.is_empty())
18218    }
18219
18220    pub fn background_highlights_in_range(
18221        &self,
18222        search_range: Range<Anchor>,
18223        display_snapshot: &DisplaySnapshot,
18224        theme: &ThemeColors,
18225    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18226        let mut results = Vec::new();
18227        for (color_fetcher, ranges) in self.background_highlights.values() {
18228            let color = color_fetcher(theme);
18229            let start_ix = match ranges.binary_search_by(|probe| {
18230                let cmp = probe
18231                    .end
18232                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18233                if cmp.is_gt() {
18234                    Ordering::Greater
18235                } else {
18236                    Ordering::Less
18237                }
18238            }) {
18239                Ok(i) | Err(i) => i,
18240            };
18241            for range in &ranges[start_ix..] {
18242                if range
18243                    .start
18244                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18245                    .is_ge()
18246                {
18247                    break;
18248                }
18249
18250                let start = range.start.to_display_point(display_snapshot);
18251                let end = range.end.to_display_point(display_snapshot);
18252                results.push((start..end, color))
18253            }
18254        }
18255        results
18256    }
18257
18258    pub fn background_highlight_row_ranges<T: 'static>(
18259        &self,
18260        search_range: Range<Anchor>,
18261        display_snapshot: &DisplaySnapshot,
18262        count: usize,
18263    ) -> Vec<RangeInclusive<DisplayPoint>> {
18264        let mut results = Vec::new();
18265        let Some((_, ranges)) = self.background_highlights.get(&TypeId::of::<T>()) else {
18266            return vec![];
18267        };
18268
18269        let start_ix = match ranges.binary_search_by(|probe| {
18270            let cmp = probe
18271                .end
18272                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18273            if cmp.is_gt() {
18274                Ordering::Greater
18275            } else {
18276                Ordering::Less
18277            }
18278        }) {
18279            Ok(i) | Err(i) => i,
18280        };
18281        let mut push_region = |start: Option<Point>, end: Option<Point>| {
18282            if let (Some(start_display), Some(end_display)) = (start, end) {
18283                results.push(
18284                    start_display.to_display_point(display_snapshot)
18285                        ..=end_display.to_display_point(display_snapshot),
18286                );
18287            }
18288        };
18289        let mut start_row: Option<Point> = None;
18290        let mut end_row: Option<Point> = None;
18291        if ranges.len() > count {
18292            return Vec::new();
18293        }
18294        for range in &ranges[start_ix..] {
18295            if range
18296                .start
18297                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18298                .is_ge()
18299            {
18300                break;
18301            }
18302            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
18303            if let Some(current_row) = &end_row {
18304                if end.row == current_row.row {
18305                    continue;
18306                }
18307            }
18308            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
18309            if start_row.is_none() {
18310                assert_eq!(end_row, None);
18311                start_row = Some(start);
18312                end_row = Some(end);
18313                continue;
18314            }
18315            if let Some(current_end) = end_row.as_mut() {
18316                if start.row > current_end.row + 1 {
18317                    push_region(start_row, end_row);
18318                    start_row = Some(start);
18319                    end_row = Some(end);
18320                } else {
18321                    // Merge two hunks.
18322                    *current_end = end;
18323                }
18324            } else {
18325                unreachable!();
18326            }
18327        }
18328        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
18329        push_region(start_row, end_row);
18330        results
18331    }
18332
18333    pub fn gutter_highlights_in_range(
18334        &self,
18335        search_range: Range<Anchor>,
18336        display_snapshot: &DisplaySnapshot,
18337        cx: &App,
18338    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
18339        let mut results = Vec::new();
18340        for (color_fetcher, ranges) in self.gutter_highlights.values() {
18341            let color = color_fetcher(cx);
18342            let start_ix = match ranges.binary_search_by(|probe| {
18343                let cmp = probe
18344                    .end
18345                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
18346                if cmp.is_gt() {
18347                    Ordering::Greater
18348                } else {
18349                    Ordering::Less
18350                }
18351            }) {
18352                Ok(i) | Err(i) => i,
18353            };
18354            for range in &ranges[start_ix..] {
18355                if range
18356                    .start
18357                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
18358                    .is_ge()
18359                {
18360                    break;
18361                }
18362
18363                let start = range.start.to_display_point(display_snapshot);
18364                let end = range.end.to_display_point(display_snapshot);
18365                results.push((start..end, color))
18366            }
18367        }
18368        results
18369    }
18370
18371    /// Get the text ranges corresponding to the redaction query
18372    pub fn redacted_ranges(
18373        &self,
18374        search_range: Range<Anchor>,
18375        display_snapshot: &DisplaySnapshot,
18376        cx: &App,
18377    ) -> Vec<Range<DisplayPoint>> {
18378        display_snapshot
18379            .buffer_snapshot
18380            .redacted_ranges(search_range, |file| {
18381                if let Some(file) = file {
18382                    file.is_private()
18383                        && EditorSettings::get(
18384                            Some(SettingsLocation {
18385                                worktree_id: file.worktree_id(cx),
18386                                path: file.path().as_ref(),
18387                            }),
18388                            cx,
18389                        )
18390                        .redact_private_values
18391                } else {
18392                    false
18393                }
18394            })
18395            .map(|range| {
18396                range.start.to_display_point(display_snapshot)
18397                    ..range.end.to_display_point(display_snapshot)
18398            })
18399            .collect()
18400    }
18401
18402    pub fn highlight_text<T: 'static>(
18403        &mut self,
18404        ranges: Vec<Range<Anchor>>,
18405        style: HighlightStyle,
18406        cx: &mut Context<Self>,
18407    ) {
18408        self.display_map.update(cx, |map, _| {
18409            map.highlight_text(TypeId::of::<T>(), ranges, style)
18410        });
18411        cx.notify();
18412    }
18413
18414    pub(crate) fn highlight_inlays<T: 'static>(
18415        &mut self,
18416        highlights: Vec<InlayHighlight>,
18417        style: HighlightStyle,
18418        cx: &mut Context<Self>,
18419    ) {
18420        self.display_map.update(cx, |map, _| {
18421            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
18422        });
18423        cx.notify();
18424    }
18425
18426    pub fn text_highlights<'a, T: 'static>(
18427        &'a self,
18428        cx: &'a App,
18429    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
18430        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
18431    }
18432
18433    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
18434        let cleared = self
18435            .display_map
18436            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
18437        if cleared {
18438            cx.notify();
18439        }
18440    }
18441
18442    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
18443        (self.read_only(cx) || self.blink_manager.read(cx).visible())
18444            && self.focus_handle.is_focused(window)
18445    }
18446
18447    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
18448        self.show_cursor_when_unfocused = is_enabled;
18449        cx.notify();
18450    }
18451
18452    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
18453        cx.notify();
18454    }
18455
18456    fn on_debug_session_event(
18457        &mut self,
18458        _session: Entity<Session>,
18459        event: &SessionEvent,
18460        cx: &mut Context<Self>,
18461    ) {
18462        match event {
18463            SessionEvent::InvalidateInlineValue => {
18464                self.refresh_inline_values(cx);
18465            }
18466            _ => {}
18467        }
18468    }
18469
18470    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
18471        let Some(project) = self.project.clone() else {
18472            return;
18473        };
18474
18475        if !self.inline_value_cache.enabled {
18476            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
18477            self.splice_inlays(&inlays, Vec::new(), cx);
18478            return;
18479        }
18480
18481        let current_execution_position = self
18482            .highlighted_rows
18483            .get(&TypeId::of::<ActiveDebugLine>())
18484            .and_then(|lines| lines.last().map(|line| line.range.start));
18485
18486        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
18487            let inline_values = editor
18488                .update(cx, |editor, cx| {
18489                    let Some(current_execution_position) = current_execution_position else {
18490                        return Some(Task::ready(Ok(Vec::new())));
18491                    };
18492
18493                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
18494                        let snapshot = buffer.snapshot(cx);
18495
18496                        let excerpt = snapshot.excerpt_containing(
18497                            current_execution_position..current_execution_position,
18498                        )?;
18499
18500                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
18501                    })?;
18502
18503                    let range =
18504                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
18505
18506                    project.inline_values(buffer, range, cx)
18507                })
18508                .ok()
18509                .flatten()?
18510                .await
18511                .context("refreshing debugger inlays")
18512                .log_err()?;
18513
18514            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
18515
18516            for (buffer_id, inline_value) in inline_values
18517                .into_iter()
18518                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
18519            {
18520                buffer_inline_values
18521                    .entry(buffer_id)
18522                    .or_default()
18523                    .push(inline_value);
18524            }
18525
18526            editor
18527                .update(cx, |editor, cx| {
18528                    let snapshot = editor.buffer.read(cx).snapshot(cx);
18529                    let mut new_inlays = Vec::default();
18530
18531                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
18532                        let buffer_id = buffer_snapshot.remote_id();
18533                        buffer_inline_values
18534                            .get(&buffer_id)
18535                            .into_iter()
18536                            .flatten()
18537                            .for_each(|hint| {
18538                                let inlay = Inlay::debugger_hint(
18539                                    post_inc(&mut editor.next_inlay_id),
18540                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
18541                                    hint.text(),
18542                                );
18543
18544                                new_inlays.push(inlay);
18545                            });
18546                    }
18547
18548                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
18549                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
18550
18551                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
18552                })
18553                .ok()?;
18554            Some(())
18555        });
18556    }
18557
18558    fn on_buffer_event(
18559        &mut self,
18560        multibuffer: &Entity<MultiBuffer>,
18561        event: &multi_buffer::Event,
18562        window: &mut Window,
18563        cx: &mut Context<Self>,
18564    ) {
18565        match event {
18566            multi_buffer::Event::Edited {
18567                singleton_buffer_edited,
18568                edited_buffer: buffer_edited,
18569            } => {
18570                self.scrollbar_marker_state.dirty = true;
18571                self.active_indent_guides_state.dirty = true;
18572                self.refresh_active_diagnostics(cx);
18573                self.refresh_code_actions(window, cx);
18574                self.refresh_selected_text_highlights(true, window, cx);
18575                refresh_matching_bracket_highlights(self, window, cx);
18576                if self.has_active_inline_completion() {
18577                    self.update_visible_inline_completion(window, cx);
18578                }
18579                if let Some(buffer) = buffer_edited {
18580                    let buffer_id = buffer.read(cx).remote_id();
18581                    if !self.registered_buffers.contains_key(&buffer_id) {
18582                        if let Some(project) = self.project.as_ref() {
18583                            project.update(cx, |project, cx| {
18584                                self.registered_buffers.insert(
18585                                    buffer_id,
18586                                    project.register_buffer_with_language_servers(&buffer, cx),
18587                                );
18588                            })
18589                        }
18590                    }
18591                }
18592                cx.emit(EditorEvent::BufferEdited);
18593                cx.emit(SearchEvent::MatchesInvalidated);
18594                if *singleton_buffer_edited {
18595                    if let Some(project) = &self.project {
18596                        #[allow(clippy::mutable_key_type)]
18597                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
18598                            multibuffer
18599                                .all_buffers()
18600                                .into_iter()
18601                                .filter_map(|buffer| {
18602                                    buffer.update(cx, |buffer, cx| {
18603                                        let language = buffer.language()?;
18604                                        let should_discard = project.update(cx, |project, cx| {
18605                                            project.is_local()
18606                                                && !project.has_language_servers_for(buffer, cx)
18607                                        });
18608                                        should_discard.not().then_some(language.clone())
18609                                    })
18610                                })
18611                                .collect::<HashSet<_>>()
18612                        });
18613                        if !languages_affected.is_empty() {
18614                            self.refresh_inlay_hints(
18615                                InlayHintRefreshReason::BufferEdited(languages_affected),
18616                                cx,
18617                            );
18618                        }
18619                    }
18620                }
18621
18622                let Some(project) = &self.project else { return };
18623                let (telemetry, is_via_ssh) = {
18624                    let project = project.read(cx);
18625                    let telemetry = project.client().telemetry().clone();
18626                    let is_via_ssh = project.is_via_ssh();
18627                    (telemetry, is_via_ssh)
18628                };
18629                refresh_linked_ranges(self, window, cx);
18630                telemetry.log_edit_event("editor", is_via_ssh);
18631            }
18632            multi_buffer::Event::ExcerptsAdded {
18633                buffer,
18634                predecessor,
18635                excerpts,
18636            } => {
18637                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18638                let buffer_id = buffer.read(cx).remote_id();
18639                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
18640                    if let Some(project) = &self.project {
18641                        update_uncommitted_diff_for_buffer(
18642                            cx.entity(),
18643                            project,
18644                            [buffer.clone()],
18645                            self.buffer.clone(),
18646                            cx,
18647                        )
18648                        .detach();
18649                    }
18650                }
18651                cx.emit(EditorEvent::ExcerptsAdded {
18652                    buffer: buffer.clone(),
18653                    predecessor: *predecessor,
18654                    excerpts: excerpts.clone(),
18655                });
18656                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18657            }
18658            multi_buffer::Event::ExcerptsRemoved {
18659                ids,
18660                removed_buffer_ids,
18661            } => {
18662                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
18663                let buffer = self.buffer.read(cx);
18664                self.registered_buffers
18665                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
18666                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18667                cx.emit(EditorEvent::ExcerptsRemoved {
18668                    ids: ids.clone(),
18669                    removed_buffer_ids: removed_buffer_ids.clone(),
18670                })
18671            }
18672            multi_buffer::Event::ExcerptsEdited {
18673                excerpt_ids,
18674                buffer_ids,
18675            } => {
18676                self.display_map.update(cx, |map, cx| {
18677                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
18678                });
18679                cx.emit(EditorEvent::ExcerptsEdited {
18680                    ids: excerpt_ids.clone(),
18681                })
18682            }
18683            multi_buffer::Event::ExcerptsExpanded { ids } => {
18684                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18685                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
18686            }
18687            multi_buffer::Event::Reparsed(buffer_id) => {
18688                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18689                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18690
18691                cx.emit(EditorEvent::Reparsed(*buffer_id));
18692            }
18693            multi_buffer::Event::DiffHunksToggled => {
18694                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18695            }
18696            multi_buffer::Event::LanguageChanged(buffer_id) => {
18697                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
18698                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
18699                cx.emit(EditorEvent::Reparsed(*buffer_id));
18700                cx.notify();
18701            }
18702            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
18703            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
18704            multi_buffer::Event::FileHandleChanged
18705            | multi_buffer::Event::Reloaded
18706            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
18707            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
18708            multi_buffer::Event::DiagnosticsUpdated => {
18709                self.refresh_active_diagnostics(cx);
18710                self.refresh_inline_diagnostics(true, window, cx);
18711                self.scrollbar_marker_state.dirty = true;
18712                cx.notify();
18713            }
18714            _ => {}
18715        };
18716    }
18717
18718    pub fn start_temporary_diff_override(&mut self) {
18719        self.load_diff_task.take();
18720        self.temporary_diff_override = true;
18721    }
18722
18723    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
18724        self.temporary_diff_override = false;
18725        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
18726        self.buffer.update(cx, |buffer, cx| {
18727            buffer.set_all_diff_hunks_collapsed(cx);
18728        });
18729
18730        if let Some(project) = self.project.clone() {
18731            self.load_diff_task = Some(
18732                update_uncommitted_diff_for_buffer(
18733                    cx.entity(),
18734                    &project,
18735                    self.buffer.read(cx).all_buffers(),
18736                    self.buffer.clone(),
18737                    cx,
18738                )
18739                .shared(),
18740            );
18741        }
18742    }
18743
18744    fn on_display_map_changed(
18745        &mut self,
18746        _: Entity<DisplayMap>,
18747        _: &mut Window,
18748        cx: &mut Context<Self>,
18749    ) {
18750        cx.notify();
18751    }
18752
18753    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18754        let new_severity = if self.diagnostics_enabled() {
18755            EditorSettings::get_global(cx)
18756                .diagnostics_max_severity
18757                .unwrap_or(DiagnosticSeverity::Hint)
18758        } else {
18759            DiagnosticSeverity::Off
18760        };
18761        self.set_max_diagnostics_severity(new_severity, cx);
18762        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
18763        self.update_edit_prediction_settings(cx);
18764        self.refresh_inline_completion(true, false, window, cx);
18765        self.refresh_inlay_hints(
18766            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
18767                self.selections.newest_anchor().head(),
18768                &self.buffer.read(cx).snapshot(cx),
18769                cx,
18770            )),
18771            cx,
18772        );
18773
18774        let old_cursor_shape = self.cursor_shape;
18775
18776        {
18777            let editor_settings = EditorSettings::get_global(cx);
18778            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
18779            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
18780            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
18781            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
18782        }
18783
18784        if old_cursor_shape != self.cursor_shape {
18785            cx.emit(EditorEvent::CursorShapeChanged);
18786        }
18787
18788        let project_settings = ProjectSettings::get_global(cx);
18789        self.serialize_dirty_buffers =
18790            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
18791
18792        if self.mode.is_full() {
18793            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
18794            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
18795            if self.show_inline_diagnostics != show_inline_diagnostics {
18796                self.show_inline_diagnostics = show_inline_diagnostics;
18797                self.refresh_inline_diagnostics(false, window, cx);
18798            }
18799
18800            if self.git_blame_inline_enabled != inline_blame_enabled {
18801                self.toggle_git_blame_inline_internal(false, window, cx);
18802            }
18803
18804            let minimap_settings = EditorSettings::get_global(cx).minimap;
18805            if self.minimap_visibility != MinimapVisibility::Disabled {
18806                if self.minimap_visibility.settings_visibility()
18807                    != minimap_settings.minimap_enabled()
18808                {
18809                    self.set_minimap_visibility(
18810                        MinimapVisibility::for_mode(self.mode(), cx),
18811                        window,
18812                        cx,
18813                    );
18814                } else if let Some(minimap_entity) = self.minimap.as_ref() {
18815                    minimap_entity.update(cx, |minimap_editor, cx| {
18816                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
18817                    })
18818                }
18819            }
18820        }
18821
18822        cx.notify();
18823    }
18824
18825    pub fn set_searchable(&mut self, searchable: bool) {
18826        self.searchable = searchable;
18827    }
18828
18829    pub fn searchable(&self) -> bool {
18830        self.searchable
18831    }
18832
18833    fn open_proposed_changes_editor(
18834        &mut self,
18835        _: &OpenProposedChangesEditor,
18836        window: &mut Window,
18837        cx: &mut Context<Self>,
18838    ) {
18839        let Some(workspace) = self.workspace() else {
18840            cx.propagate();
18841            return;
18842        };
18843
18844        let selections = self.selections.all::<usize>(cx);
18845        let multi_buffer = self.buffer.read(cx);
18846        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18847        let mut new_selections_by_buffer = HashMap::default();
18848        for selection in selections {
18849            for (buffer, range, _) in
18850                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
18851            {
18852                let mut range = range.to_point(buffer);
18853                range.start.column = 0;
18854                range.end.column = buffer.line_len(range.end.row);
18855                new_selections_by_buffer
18856                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
18857                    .or_insert(Vec::new())
18858                    .push(range)
18859            }
18860        }
18861
18862        let proposed_changes_buffers = new_selections_by_buffer
18863            .into_iter()
18864            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
18865            .collect::<Vec<_>>();
18866        let proposed_changes_editor = cx.new(|cx| {
18867            ProposedChangesEditor::new(
18868                "Proposed changes",
18869                proposed_changes_buffers,
18870                self.project.clone(),
18871                window,
18872                cx,
18873            )
18874        });
18875
18876        window.defer(cx, move |window, cx| {
18877            workspace.update(cx, |workspace, cx| {
18878                workspace.active_pane().update(cx, |pane, cx| {
18879                    pane.add_item(
18880                        Box::new(proposed_changes_editor),
18881                        true,
18882                        true,
18883                        None,
18884                        window,
18885                        cx,
18886                    );
18887                });
18888            });
18889        });
18890    }
18891
18892    pub fn open_excerpts_in_split(
18893        &mut self,
18894        _: &OpenExcerptsSplit,
18895        window: &mut Window,
18896        cx: &mut Context<Self>,
18897    ) {
18898        self.open_excerpts_common(None, true, window, cx)
18899    }
18900
18901    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
18902        self.open_excerpts_common(None, false, window, cx)
18903    }
18904
18905    fn open_excerpts_common(
18906        &mut self,
18907        jump_data: Option<JumpData>,
18908        split: bool,
18909        window: &mut Window,
18910        cx: &mut Context<Self>,
18911    ) {
18912        let Some(workspace) = self.workspace() else {
18913            cx.propagate();
18914            return;
18915        };
18916
18917        if self.buffer.read(cx).is_singleton() {
18918            cx.propagate();
18919            return;
18920        }
18921
18922        let mut new_selections_by_buffer = HashMap::default();
18923        match &jump_data {
18924            Some(JumpData::MultiBufferPoint {
18925                excerpt_id,
18926                position,
18927                anchor,
18928                line_offset_from_top,
18929            }) => {
18930                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18931                if let Some(buffer) = multi_buffer_snapshot
18932                    .buffer_id_for_excerpt(*excerpt_id)
18933                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
18934                {
18935                    let buffer_snapshot = buffer.read(cx).snapshot();
18936                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
18937                        language::ToPoint::to_point(anchor, &buffer_snapshot)
18938                    } else {
18939                        buffer_snapshot.clip_point(*position, Bias::Left)
18940                    };
18941                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
18942                    new_selections_by_buffer.insert(
18943                        buffer,
18944                        (
18945                            vec![jump_to_offset..jump_to_offset],
18946                            Some(*line_offset_from_top),
18947                        ),
18948                    );
18949                }
18950            }
18951            Some(JumpData::MultiBufferRow {
18952                row,
18953                line_offset_from_top,
18954            }) => {
18955                let point = MultiBufferPoint::new(row.0, 0);
18956                if let Some((buffer, buffer_point, _)) =
18957                    self.buffer.read(cx).point_to_buffer_point(point, cx)
18958                {
18959                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
18960                    new_selections_by_buffer
18961                        .entry(buffer)
18962                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
18963                        .0
18964                        .push(buffer_offset..buffer_offset)
18965                }
18966            }
18967            None => {
18968                let selections = self.selections.all::<usize>(cx);
18969                let multi_buffer = self.buffer.read(cx);
18970                for selection in selections {
18971                    for (snapshot, range, _, anchor) in multi_buffer
18972                        .snapshot(cx)
18973                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
18974                    {
18975                        if let Some(anchor) = anchor {
18976                            // selection is in a deleted hunk
18977                            let Some(buffer_id) = anchor.buffer_id else {
18978                                continue;
18979                            };
18980                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
18981                                continue;
18982                            };
18983                            let offset = text::ToOffset::to_offset(
18984                                &anchor.text_anchor,
18985                                &buffer_handle.read(cx).snapshot(),
18986                            );
18987                            let range = offset..offset;
18988                            new_selections_by_buffer
18989                                .entry(buffer_handle)
18990                                .or_insert((Vec::new(), None))
18991                                .0
18992                                .push(range)
18993                        } else {
18994                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
18995                            else {
18996                                continue;
18997                            };
18998                            new_selections_by_buffer
18999                                .entry(buffer_handle)
19000                                .or_insert((Vec::new(), None))
19001                                .0
19002                                .push(range)
19003                        }
19004                    }
19005                }
19006            }
19007        }
19008
19009        new_selections_by_buffer
19010            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
19011
19012        if new_selections_by_buffer.is_empty() {
19013            return;
19014        }
19015
19016        // We defer the pane interaction because we ourselves are a workspace item
19017        // and activating a new item causes the pane to call a method on us reentrantly,
19018        // which panics if we're on the stack.
19019        window.defer(cx, move |window, cx| {
19020            workspace.update(cx, |workspace, cx| {
19021                let pane = if split {
19022                    workspace.adjacent_pane(window, cx)
19023                } else {
19024                    workspace.active_pane().clone()
19025                };
19026
19027                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
19028                    let editor = buffer
19029                        .read(cx)
19030                        .file()
19031                        .is_none()
19032                        .then(|| {
19033                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
19034                            // so `workspace.open_project_item` will never find them, always opening a new editor.
19035                            // Instead, we try to activate the existing editor in the pane first.
19036                            let (editor, pane_item_index) =
19037                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
19038                                    let editor = item.downcast::<Editor>()?;
19039                                    let singleton_buffer =
19040                                        editor.read(cx).buffer().read(cx).as_singleton()?;
19041                                    if singleton_buffer == buffer {
19042                                        Some((editor, i))
19043                                    } else {
19044                                        None
19045                                    }
19046                                })?;
19047                            pane.update(cx, |pane, cx| {
19048                                pane.activate_item(pane_item_index, true, true, window, cx)
19049                            });
19050                            Some(editor)
19051                        })
19052                        .flatten()
19053                        .unwrap_or_else(|| {
19054                            workspace.open_project_item::<Self>(
19055                                pane.clone(),
19056                                buffer,
19057                                true,
19058                                true,
19059                                window,
19060                                cx,
19061                            )
19062                        });
19063
19064                    editor.update(cx, |editor, cx| {
19065                        let autoscroll = match scroll_offset {
19066                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
19067                            None => Autoscroll::newest(),
19068                        };
19069                        let nav_history = editor.nav_history.take();
19070                        editor.change_selections(Some(autoscroll), window, cx, |s| {
19071                            s.select_ranges(ranges);
19072                        });
19073                        editor.nav_history = nav_history;
19074                    });
19075                }
19076            })
19077        });
19078    }
19079
19080    // For now, don't allow opening excerpts in buffers that aren't backed by
19081    // regular project files.
19082    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
19083        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
19084    }
19085
19086    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
19087        let snapshot = self.buffer.read(cx).read(cx);
19088        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
19089        Some(
19090            ranges
19091                .iter()
19092                .map(move |range| {
19093                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
19094                })
19095                .collect(),
19096        )
19097    }
19098
19099    fn selection_replacement_ranges(
19100        &self,
19101        range: Range<OffsetUtf16>,
19102        cx: &mut App,
19103    ) -> Vec<Range<OffsetUtf16>> {
19104        let selections = self.selections.all::<OffsetUtf16>(cx);
19105        let newest_selection = selections
19106            .iter()
19107            .max_by_key(|selection| selection.id)
19108            .unwrap();
19109        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
19110        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
19111        let snapshot = self.buffer.read(cx).read(cx);
19112        selections
19113            .into_iter()
19114            .map(|mut selection| {
19115                selection.start.0 =
19116                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
19117                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
19118                snapshot.clip_offset_utf16(selection.start, Bias::Left)
19119                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
19120            })
19121            .collect()
19122    }
19123
19124    fn report_editor_event(
19125        &self,
19126        event_type: &'static str,
19127        file_extension: Option<String>,
19128        cx: &App,
19129    ) {
19130        if cfg!(any(test, feature = "test-support")) {
19131            return;
19132        }
19133
19134        let Some(project) = &self.project else { return };
19135
19136        // If None, we are in a file without an extension
19137        let file = self
19138            .buffer
19139            .read(cx)
19140            .as_singleton()
19141            .and_then(|b| b.read(cx).file());
19142        let file_extension = file_extension.or(file
19143            .as_ref()
19144            .and_then(|file| Path::new(file.file_name(cx)).extension())
19145            .and_then(|e| e.to_str())
19146            .map(|a| a.to_string()));
19147
19148        let vim_mode = vim_enabled(cx);
19149
19150        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
19151        let copilot_enabled = edit_predictions_provider
19152            == language::language_settings::EditPredictionProvider::Copilot;
19153        let copilot_enabled_for_language = self
19154            .buffer
19155            .read(cx)
19156            .language_settings(cx)
19157            .show_edit_predictions;
19158
19159        let project = project.read(cx);
19160        telemetry::event!(
19161            event_type,
19162            file_extension,
19163            vim_mode,
19164            copilot_enabled,
19165            copilot_enabled_for_language,
19166            edit_predictions_provider,
19167            is_via_ssh = project.is_via_ssh(),
19168        );
19169    }
19170
19171    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
19172    /// with each line being an array of {text, highlight} objects.
19173    fn copy_highlight_json(
19174        &mut self,
19175        _: &CopyHighlightJson,
19176        window: &mut Window,
19177        cx: &mut Context<Self>,
19178    ) {
19179        #[derive(Serialize)]
19180        struct Chunk<'a> {
19181            text: String,
19182            highlight: Option<&'a str>,
19183        }
19184
19185        let snapshot = self.buffer.read(cx).snapshot(cx);
19186        let range = self
19187            .selected_text_range(false, window, cx)
19188            .and_then(|selection| {
19189                if selection.range.is_empty() {
19190                    None
19191                } else {
19192                    Some(selection.range)
19193                }
19194            })
19195            .unwrap_or_else(|| 0..snapshot.len());
19196
19197        let chunks = snapshot.chunks(range, true);
19198        let mut lines = Vec::new();
19199        let mut line: VecDeque<Chunk> = VecDeque::new();
19200
19201        let Some(style) = self.style.as_ref() else {
19202            return;
19203        };
19204
19205        for chunk in chunks {
19206            let highlight = chunk
19207                .syntax_highlight_id
19208                .and_then(|id| id.name(&style.syntax));
19209            let mut chunk_lines = chunk.text.split('\n').peekable();
19210            while let Some(text) = chunk_lines.next() {
19211                let mut merged_with_last_token = false;
19212                if let Some(last_token) = line.back_mut() {
19213                    if last_token.highlight == highlight {
19214                        last_token.text.push_str(text);
19215                        merged_with_last_token = true;
19216                    }
19217                }
19218
19219                if !merged_with_last_token {
19220                    line.push_back(Chunk {
19221                        text: text.into(),
19222                        highlight,
19223                    });
19224                }
19225
19226                if chunk_lines.peek().is_some() {
19227                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
19228                        line.pop_front();
19229                    }
19230                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
19231                        line.pop_back();
19232                    }
19233
19234                    lines.push(mem::take(&mut line));
19235                }
19236            }
19237        }
19238
19239        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
19240            return;
19241        };
19242        cx.write_to_clipboard(ClipboardItem::new_string(lines));
19243    }
19244
19245    pub fn open_context_menu(
19246        &mut self,
19247        _: &OpenContextMenu,
19248        window: &mut Window,
19249        cx: &mut Context<Self>,
19250    ) {
19251        self.request_autoscroll(Autoscroll::newest(), cx);
19252        let position = self.selections.newest_display(cx).start;
19253        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
19254    }
19255
19256    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
19257        &self.inlay_hint_cache
19258    }
19259
19260    pub fn replay_insert_event(
19261        &mut self,
19262        text: &str,
19263        relative_utf16_range: Option<Range<isize>>,
19264        window: &mut Window,
19265        cx: &mut Context<Self>,
19266    ) {
19267        if !self.input_enabled {
19268            cx.emit(EditorEvent::InputIgnored { text: text.into() });
19269            return;
19270        }
19271        if let Some(relative_utf16_range) = relative_utf16_range {
19272            let selections = self.selections.all::<OffsetUtf16>(cx);
19273            self.change_selections(None, window, cx, |s| {
19274                let new_ranges = selections.into_iter().map(|range| {
19275                    let start = OffsetUtf16(
19276                        range
19277                            .head()
19278                            .0
19279                            .saturating_add_signed(relative_utf16_range.start),
19280                    );
19281                    let end = OffsetUtf16(
19282                        range
19283                            .head()
19284                            .0
19285                            .saturating_add_signed(relative_utf16_range.end),
19286                    );
19287                    start..end
19288                });
19289                s.select_ranges(new_ranges);
19290            });
19291        }
19292
19293        self.handle_input(text, window, cx);
19294    }
19295
19296    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
19297        let Some(provider) = self.semantics_provider.as_ref() else {
19298            return false;
19299        };
19300
19301        let mut supports = false;
19302        self.buffer().update(cx, |this, cx| {
19303            this.for_each_buffer(|buffer| {
19304                supports |= provider.supports_inlay_hints(buffer, cx);
19305            });
19306        });
19307
19308        supports
19309    }
19310
19311    pub fn is_focused(&self, window: &Window) -> bool {
19312        self.focus_handle.is_focused(window)
19313    }
19314
19315    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19316        cx.emit(EditorEvent::Focused);
19317
19318        if let Some(descendant) = self
19319            .last_focused_descendant
19320            .take()
19321            .and_then(|descendant| descendant.upgrade())
19322        {
19323            window.focus(&descendant);
19324        } else {
19325            if let Some(blame) = self.blame.as_ref() {
19326                blame.update(cx, GitBlame::focus)
19327            }
19328
19329            self.blink_manager.update(cx, BlinkManager::enable);
19330            self.show_cursor_names(window, cx);
19331            self.buffer.update(cx, |buffer, cx| {
19332                buffer.finalize_last_transaction(cx);
19333                if self.leader_id.is_none() {
19334                    buffer.set_active_selections(
19335                        &self.selections.disjoint_anchors(),
19336                        self.selections.line_mode,
19337                        self.cursor_shape,
19338                        cx,
19339                    );
19340                }
19341            });
19342        }
19343    }
19344
19345    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
19346        cx.emit(EditorEvent::FocusedIn)
19347    }
19348
19349    fn handle_focus_out(
19350        &mut self,
19351        event: FocusOutEvent,
19352        _window: &mut Window,
19353        cx: &mut Context<Self>,
19354    ) {
19355        if event.blurred != self.focus_handle {
19356            self.last_focused_descendant = Some(event.blurred);
19357        }
19358        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
19359    }
19360
19361    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19362        self.blink_manager.update(cx, BlinkManager::disable);
19363        self.buffer
19364            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
19365
19366        if let Some(blame) = self.blame.as_ref() {
19367            blame.update(cx, GitBlame::blur)
19368        }
19369        if !self.hover_state.focused(window, cx) {
19370            hide_hover(self, cx);
19371        }
19372        if !self
19373            .context_menu
19374            .borrow()
19375            .as_ref()
19376            .is_some_and(|context_menu| context_menu.focused(window, cx))
19377        {
19378            self.hide_context_menu(window, cx);
19379        }
19380        self.discard_inline_completion(false, cx);
19381        cx.emit(EditorEvent::Blurred);
19382        cx.notify();
19383    }
19384
19385    pub fn register_action<A: Action>(
19386        &mut self,
19387        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
19388    ) -> Subscription {
19389        let id = self.next_editor_action_id.post_inc();
19390        let listener = Arc::new(listener);
19391        self.editor_actions.borrow_mut().insert(
19392            id,
19393            Box::new(move |window, _| {
19394                let listener = listener.clone();
19395                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
19396                    let action = action.downcast_ref().unwrap();
19397                    if phase == DispatchPhase::Bubble {
19398                        listener(action, window, cx)
19399                    }
19400                })
19401            }),
19402        );
19403
19404        let editor_actions = self.editor_actions.clone();
19405        Subscription::new(move || {
19406            editor_actions.borrow_mut().remove(&id);
19407        })
19408    }
19409
19410    pub fn file_header_size(&self) -> u32 {
19411        FILE_HEADER_HEIGHT
19412    }
19413
19414    pub fn restore(
19415        &mut self,
19416        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
19417        window: &mut Window,
19418        cx: &mut Context<Self>,
19419    ) {
19420        let workspace = self.workspace();
19421        let project = self.project.as_ref();
19422        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
19423            let mut tasks = Vec::new();
19424            for (buffer_id, changes) in revert_changes {
19425                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
19426                    buffer.update(cx, |buffer, cx| {
19427                        buffer.edit(
19428                            changes
19429                                .into_iter()
19430                                .map(|(range, text)| (range, text.to_string())),
19431                            None,
19432                            cx,
19433                        );
19434                    });
19435
19436                    if let Some(project) =
19437                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
19438                    {
19439                        project.update(cx, |project, cx| {
19440                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
19441                        })
19442                    }
19443                }
19444            }
19445            tasks
19446        });
19447        cx.spawn_in(window, async move |_, cx| {
19448            for (buffer, task) in save_tasks {
19449                let result = task.await;
19450                if result.is_err() {
19451                    let Some(path) = buffer
19452                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
19453                        .ok()
19454                    else {
19455                        continue;
19456                    };
19457                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
19458                        let Some(task) = cx
19459                            .update_window_entity(&workspace, |workspace, window, cx| {
19460                                workspace
19461                                    .open_path_preview(path, None, false, false, false, window, cx)
19462                            })
19463                            .ok()
19464                        else {
19465                            continue;
19466                        };
19467                        task.await.log_err();
19468                    }
19469                }
19470            }
19471        })
19472        .detach();
19473        self.change_selections(None, window, cx, |selections| selections.refresh());
19474    }
19475
19476    pub fn to_pixel_point(
19477        &self,
19478        source: multi_buffer::Anchor,
19479        editor_snapshot: &EditorSnapshot,
19480        window: &mut Window,
19481    ) -> Option<gpui::Point<Pixels>> {
19482        let source_point = source.to_display_point(editor_snapshot);
19483        self.display_to_pixel_point(source_point, editor_snapshot, window)
19484    }
19485
19486    pub fn display_to_pixel_point(
19487        &self,
19488        source: DisplayPoint,
19489        editor_snapshot: &EditorSnapshot,
19490        window: &mut Window,
19491    ) -> Option<gpui::Point<Pixels>> {
19492        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
19493        let text_layout_details = self.text_layout_details(window);
19494        let scroll_top = text_layout_details
19495            .scroll_anchor
19496            .scroll_position(editor_snapshot)
19497            .y;
19498
19499        if source.row().as_f32() < scroll_top.floor() {
19500            return None;
19501        }
19502        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
19503        let source_y = line_height * (source.row().as_f32() - scroll_top);
19504        Some(gpui::Point::new(source_x, source_y))
19505    }
19506
19507    pub fn has_visible_completions_menu(&self) -> bool {
19508        !self.edit_prediction_preview_is_active()
19509            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
19510                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
19511            })
19512    }
19513
19514    pub fn register_addon<T: Addon>(&mut self, instance: T) {
19515        if self.mode.is_minimap() {
19516            return;
19517        }
19518        self.addons
19519            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
19520    }
19521
19522    pub fn unregister_addon<T: Addon>(&mut self) {
19523        self.addons.remove(&std::any::TypeId::of::<T>());
19524    }
19525
19526    pub fn addon<T: Addon>(&self) -> Option<&T> {
19527        let type_id = std::any::TypeId::of::<T>();
19528        self.addons
19529            .get(&type_id)
19530            .and_then(|item| item.to_any().downcast_ref::<T>())
19531    }
19532
19533    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
19534        let type_id = std::any::TypeId::of::<T>();
19535        self.addons
19536            .get_mut(&type_id)
19537            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
19538    }
19539
19540    fn character_size(&self, window: &mut Window) -> gpui::Size<Pixels> {
19541        let text_layout_details = self.text_layout_details(window);
19542        let style = &text_layout_details.editor_style;
19543        let font_id = window.text_system().resolve_font(&style.text.font());
19544        let font_size = style.text.font_size.to_pixels(window.rem_size());
19545        let line_height = style.text.line_height_in_pixels(window.rem_size());
19546        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
19547
19548        gpui::Size::new(em_width, line_height)
19549    }
19550
19551    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
19552        self.load_diff_task.clone()
19553    }
19554
19555    fn read_metadata_from_db(
19556        &mut self,
19557        item_id: u64,
19558        workspace_id: WorkspaceId,
19559        window: &mut Window,
19560        cx: &mut Context<Editor>,
19561    ) {
19562        if self.is_singleton(cx)
19563            && !self.mode.is_minimap()
19564            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
19565        {
19566            let buffer_snapshot = OnceCell::new();
19567
19568            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
19569                if !folds.is_empty() {
19570                    let snapshot =
19571                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19572                    self.fold_ranges(
19573                        folds
19574                            .into_iter()
19575                            .map(|(start, end)| {
19576                                snapshot.clip_offset(start, Bias::Left)
19577                                    ..snapshot.clip_offset(end, Bias::Right)
19578                            })
19579                            .collect(),
19580                        false,
19581                        window,
19582                        cx,
19583                    );
19584                }
19585            }
19586
19587            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
19588                if !selections.is_empty() {
19589                    let snapshot =
19590                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
19591                    self.change_selections(None, window, cx, |s| {
19592                        s.select_ranges(selections.into_iter().map(|(start, end)| {
19593                            snapshot.clip_offset(start, Bias::Left)
19594                                ..snapshot.clip_offset(end, Bias::Right)
19595                        }));
19596                    });
19597                }
19598            };
19599        }
19600
19601        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
19602    }
19603}
19604
19605fn vim_enabled(cx: &App) -> bool {
19606    cx.global::<SettingsStore>()
19607        .raw_user_settings()
19608        .get("vim_mode")
19609        == Some(&serde_json::Value::Bool(true))
19610}
19611
19612fn process_completion_for_edit(
19613    completion: &Completion,
19614    intent: CompletionIntent,
19615    buffer: &Entity<Buffer>,
19616    cursor_position: &text::Anchor,
19617    cx: &mut Context<Editor>,
19618) -> CompletionEdit {
19619    let buffer = buffer.read(cx);
19620    let buffer_snapshot = buffer.snapshot();
19621    let (snippet, new_text) = if completion.is_snippet() {
19622        let mut snippet_source = completion.new_text.clone();
19623        if let Some(scope) = buffer_snapshot.language_scope_at(cursor_position) {
19624            if scope.prefers_label_for_snippet_in_completion() {
19625                if let Some(label) = completion.label() {
19626                    if matches!(
19627                        completion.kind(),
19628                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
19629                    ) {
19630                        snippet_source = label;
19631                    }
19632                }
19633            }
19634        }
19635        match Snippet::parse(&snippet_source).log_err() {
19636            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
19637            None => (None, completion.new_text.clone()),
19638        }
19639    } else {
19640        (None, completion.new_text.clone())
19641    };
19642
19643    let mut range_to_replace = {
19644        let replace_range = &completion.replace_range;
19645        if let CompletionSource::Lsp {
19646            insert_range: Some(insert_range),
19647            ..
19648        } = &completion.source
19649        {
19650            debug_assert_eq!(
19651                insert_range.start, replace_range.start,
19652                "insert_range and replace_range should start at the same position"
19653            );
19654            debug_assert!(
19655                insert_range
19656                    .start
19657                    .cmp(&cursor_position, &buffer_snapshot)
19658                    .is_le(),
19659                "insert_range should start before or at cursor position"
19660            );
19661            debug_assert!(
19662                replace_range
19663                    .start
19664                    .cmp(&cursor_position, &buffer_snapshot)
19665                    .is_le(),
19666                "replace_range should start before or at cursor position"
19667            );
19668            debug_assert!(
19669                insert_range
19670                    .end
19671                    .cmp(&cursor_position, &buffer_snapshot)
19672                    .is_le(),
19673                "insert_range should end before or at cursor position"
19674            );
19675
19676            let should_replace = match intent {
19677                CompletionIntent::CompleteWithInsert => false,
19678                CompletionIntent::CompleteWithReplace => true,
19679                CompletionIntent::Complete | CompletionIntent::Compose => {
19680                    let insert_mode =
19681                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
19682                            .completions
19683                            .lsp_insert_mode;
19684                    match insert_mode {
19685                        LspInsertMode::Insert => false,
19686                        LspInsertMode::Replace => true,
19687                        LspInsertMode::ReplaceSubsequence => {
19688                            let mut text_to_replace = buffer.chars_for_range(
19689                                buffer.anchor_before(replace_range.start)
19690                                    ..buffer.anchor_after(replace_range.end),
19691                            );
19692                            let mut current_needle = text_to_replace.next();
19693                            for haystack_ch in completion.label.text.chars() {
19694                                if let Some(needle_ch) = current_needle {
19695                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
19696                                        current_needle = text_to_replace.next();
19697                                    }
19698                                }
19699                            }
19700                            current_needle.is_none()
19701                        }
19702                        LspInsertMode::ReplaceSuffix => {
19703                            if replace_range
19704                                .end
19705                                .cmp(&cursor_position, &buffer_snapshot)
19706                                .is_gt()
19707                            {
19708                                let range_after_cursor = *cursor_position..replace_range.end;
19709                                let text_after_cursor = buffer
19710                                    .text_for_range(
19711                                        buffer.anchor_before(range_after_cursor.start)
19712                                            ..buffer.anchor_after(range_after_cursor.end),
19713                                    )
19714                                    .collect::<String>()
19715                                    .to_ascii_lowercase();
19716                                completion
19717                                    .label
19718                                    .text
19719                                    .to_ascii_lowercase()
19720                                    .ends_with(&text_after_cursor)
19721                            } else {
19722                                true
19723                            }
19724                        }
19725                    }
19726                }
19727            };
19728
19729            if should_replace {
19730                replace_range.clone()
19731            } else {
19732                insert_range.clone()
19733            }
19734        } else {
19735            replace_range.clone()
19736        }
19737    };
19738
19739    if range_to_replace
19740        .end
19741        .cmp(&cursor_position, &buffer_snapshot)
19742        .is_lt()
19743    {
19744        range_to_replace.end = *cursor_position;
19745    }
19746
19747    CompletionEdit {
19748        new_text,
19749        replace_range: range_to_replace.to_offset(&buffer),
19750        snippet,
19751    }
19752}
19753
19754struct CompletionEdit {
19755    new_text: String,
19756    replace_range: Range<usize>,
19757    snippet: Option<Snippet>,
19758}
19759
19760fn insert_extra_newline_brackets(
19761    buffer: &MultiBufferSnapshot,
19762    range: Range<usize>,
19763    language: &language::LanguageScope,
19764) -> bool {
19765    let leading_whitespace_len = buffer
19766        .reversed_chars_at(range.start)
19767        .take_while(|c| c.is_whitespace() && *c != '\n')
19768        .map(|c| c.len_utf8())
19769        .sum::<usize>();
19770    let trailing_whitespace_len = buffer
19771        .chars_at(range.end)
19772        .take_while(|c| c.is_whitespace() && *c != '\n')
19773        .map(|c| c.len_utf8())
19774        .sum::<usize>();
19775    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
19776
19777    language.brackets().any(|(pair, enabled)| {
19778        let pair_start = pair.start.trim_end();
19779        let pair_end = pair.end.trim_start();
19780
19781        enabled
19782            && pair.newline
19783            && buffer.contains_str_at(range.end, pair_end)
19784            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
19785    })
19786}
19787
19788fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
19789    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
19790        [(buffer, range, _)] => (*buffer, range.clone()),
19791        _ => return false,
19792    };
19793    let pair = {
19794        let mut result: Option<BracketMatch> = None;
19795
19796        for pair in buffer
19797            .all_bracket_ranges(range.clone())
19798            .filter(move |pair| {
19799                pair.open_range.start <= range.start && pair.close_range.end >= range.end
19800            })
19801        {
19802            let len = pair.close_range.end - pair.open_range.start;
19803
19804            if let Some(existing) = &result {
19805                let existing_len = existing.close_range.end - existing.open_range.start;
19806                if len > existing_len {
19807                    continue;
19808                }
19809            }
19810
19811            result = Some(pair);
19812        }
19813
19814        result
19815    };
19816    let Some(pair) = pair else {
19817        return false;
19818    };
19819    pair.newline_only
19820        && buffer
19821            .chars_for_range(pair.open_range.end..range.start)
19822            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
19823            .all(|c| c.is_whitespace() && c != '\n')
19824}
19825
19826fn update_uncommitted_diff_for_buffer(
19827    editor: Entity<Editor>,
19828    project: &Entity<Project>,
19829    buffers: impl IntoIterator<Item = Entity<Buffer>>,
19830    buffer: Entity<MultiBuffer>,
19831    cx: &mut App,
19832) -> Task<()> {
19833    let mut tasks = Vec::new();
19834    project.update(cx, |project, cx| {
19835        for buffer in buffers {
19836            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
19837                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
19838            }
19839        }
19840    });
19841    cx.spawn(async move |cx| {
19842        let diffs = future::join_all(tasks).await;
19843        if editor
19844            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
19845            .unwrap_or(false)
19846        {
19847            return;
19848        }
19849
19850        buffer
19851            .update(cx, |buffer, cx| {
19852                for diff in diffs.into_iter().flatten() {
19853                    buffer.add_diff(diff, cx);
19854                }
19855            })
19856            .ok();
19857    })
19858}
19859
19860fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
19861    let tab_size = tab_size.get() as usize;
19862    let mut width = offset;
19863
19864    for ch in text.chars() {
19865        width += if ch == '\t' {
19866            tab_size - (width % tab_size)
19867        } else {
19868            1
19869        };
19870    }
19871
19872    width - offset
19873}
19874
19875#[cfg(test)]
19876mod tests {
19877    use super::*;
19878
19879    #[test]
19880    fn test_string_size_with_expanded_tabs() {
19881        let nz = |val| NonZeroU32::new(val).unwrap();
19882        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
19883        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
19884        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
19885        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
19886        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
19887        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
19888        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
19889        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
19890    }
19891}
19892
19893/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
19894struct WordBreakingTokenizer<'a> {
19895    input: &'a str,
19896}
19897
19898impl<'a> WordBreakingTokenizer<'a> {
19899    fn new(input: &'a str) -> Self {
19900        Self { input }
19901    }
19902}
19903
19904fn is_char_ideographic(ch: char) -> bool {
19905    use unicode_script::Script::*;
19906    use unicode_script::UnicodeScript;
19907    matches!(ch.script(), Han | Tangut | Yi)
19908}
19909
19910fn is_grapheme_ideographic(text: &str) -> bool {
19911    text.chars().any(is_char_ideographic)
19912}
19913
19914fn is_grapheme_whitespace(text: &str) -> bool {
19915    text.chars().any(|x| x.is_whitespace())
19916}
19917
19918fn should_stay_with_preceding_ideograph(text: &str) -> bool {
19919    text.chars().next().map_or(false, |ch| {
19920        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
19921    })
19922}
19923
19924#[derive(PartialEq, Eq, Debug, Clone, Copy)]
19925enum WordBreakToken<'a> {
19926    Word { token: &'a str, grapheme_len: usize },
19927    InlineWhitespace { token: &'a str, grapheme_len: usize },
19928    Newline,
19929}
19930
19931impl<'a> Iterator for WordBreakingTokenizer<'a> {
19932    /// Yields a span, the count of graphemes in the token, and whether it was
19933    /// whitespace. Note that it also breaks at word boundaries.
19934    type Item = WordBreakToken<'a>;
19935
19936    fn next(&mut self) -> Option<Self::Item> {
19937        use unicode_segmentation::UnicodeSegmentation;
19938        if self.input.is_empty() {
19939            return None;
19940        }
19941
19942        let mut iter = self.input.graphemes(true).peekable();
19943        let mut offset = 0;
19944        let mut grapheme_len = 0;
19945        if let Some(first_grapheme) = iter.next() {
19946            let is_newline = first_grapheme == "\n";
19947            let is_whitespace = is_grapheme_whitespace(first_grapheme);
19948            offset += first_grapheme.len();
19949            grapheme_len += 1;
19950            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
19951                if let Some(grapheme) = iter.peek().copied() {
19952                    if should_stay_with_preceding_ideograph(grapheme) {
19953                        offset += grapheme.len();
19954                        grapheme_len += 1;
19955                    }
19956                }
19957            } else {
19958                let mut words = self.input[offset..].split_word_bound_indices().peekable();
19959                let mut next_word_bound = words.peek().copied();
19960                if next_word_bound.map_or(false, |(i, _)| i == 0) {
19961                    next_word_bound = words.next();
19962                }
19963                while let Some(grapheme) = iter.peek().copied() {
19964                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
19965                        break;
19966                    };
19967                    if is_grapheme_whitespace(grapheme) != is_whitespace
19968                        || (grapheme == "\n") != is_newline
19969                    {
19970                        break;
19971                    };
19972                    offset += grapheme.len();
19973                    grapheme_len += 1;
19974                    iter.next();
19975                }
19976            }
19977            let token = &self.input[..offset];
19978            self.input = &self.input[offset..];
19979            if token == "\n" {
19980                Some(WordBreakToken::Newline)
19981            } else if is_whitespace {
19982                Some(WordBreakToken::InlineWhitespace {
19983                    token,
19984                    grapheme_len,
19985                })
19986            } else {
19987                Some(WordBreakToken::Word {
19988                    token,
19989                    grapheme_len,
19990                })
19991            }
19992        } else {
19993            None
19994        }
19995    }
19996}
19997
19998#[test]
19999fn test_word_breaking_tokenizer() {
20000    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
20001        ("", &[]),
20002        ("  ", &[whitespace("  ", 2)]),
20003        ("Ʒ", &[word("Ʒ", 1)]),
20004        ("Ǽ", &[word("Ǽ", 1)]),
20005        ("", &[word("", 1)]),
20006        ("⋑⋑", &[word("⋑⋑", 2)]),
20007        (
20008            "原理,进而",
20009            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
20010        ),
20011        (
20012            "hello world",
20013            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
20014        ),
20015        (
20016            "hello, world",
20017            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
20018        ),
20019        (
20020            "  hello world",
20021            &[
20022                whitespace("  ", 2),
20023                word("hello", 5),
20024                whitespace(" ", 1),
20025                word("world", 5),
20026            ],
20027        ),
20028        (
20029            "这是什么 \n 钢笔",
20030            &[
20031                word("", 1),
20032                word("", 1),
20033                word("", 1),
20034                word("", 1),
20035                whitespace(" ", 1),
20036                newline(),
20037                whitespace(" ", 1),
20038                word("", 1),
20039                word("", 1),
20040            ],
20041        ),
20042        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
20043    ];
20044
20045    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20046        WordBreakToken::Word {
20047            token,
20048            grapheme_len,
20049        }
20050    }
20051
20052    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
20053        WordBreakToken::InlineWhitespace {
20054            token,
20055            grapheme_len,
20056        }
20057    }
20058
20059    fn newline() -> WordBreakToken<'static> {
20060        WordBreakToken::Newline
20061    }
20062
20063    for (input, result) in tests {
20064        assert_eq!(
20065            WordBreakingTokenizer::new(input)
20066                .collect::<Vec<_>>()
20067                .as_slice(),
20068            *result,
20069        );
20070    }
20071}
20072
20073fn wrap_with_prefix(
20074    line_prefix: String,
20075    unwrapped_text: String,
20076    wrap_column: usize,
20077    tab_size: NonZeroU32,
20078    preserve_existing_whitespace: bool,
20079) -> String {
20080    let line_prefix_len = char_len_with_expanded_tabs(0, &line_prefix, tab_size);
20081    let mut wrapped_text = String::new();
20082    let mut current_line = line_prefix.clone();
20083
20084    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
20085    let mut current_line_len = line_prefix_len;
20086    let mut in_whitespace = false;
20087    for token in tokenizer {
20088        let have_preceding_whitespace = in_whitespace;
20089        match token {
20090            WordBreakToken::Word {
20091                token,
20092                grapheme_len,
20093            } => {
20094                in_whitespace = false;
20095                if current_line_len + grapheme_len > wrap_column
20096                    && current_line_len != line_prefix_len
20097                {
20098                    wrapped_text.push_str(current_line.trim_end());
20099                    wrapped_text.push('\n');
20100                    current_line.truncate(line_prefix.len());
20101                    current_line_len = line_prefix_len;
20102                }
20103                current_line.push_str(token);
20104                current_line_len += grapheme_len;
20105            }
20106            WordBreakToken::InlineWhitespace {
20107                mut token,
20108                mut grapheme_len,
20109            } => {
20110                in_whitespace = true;
20111                if have_preceding_whitespace && !preserve_existing_whitespace {
20112                    continue;
20113                }
20114                if !preserve_existing_whitespace {
20115                    token = " ";
20116                    grapheme_len = 1;
20117                }
20118                if current_line_len + grapheme_len > wrap_column {
20119                    wrapped_text.push_str(current_line.trim_end());
20120                    wrapped_text.push('\n');
20121                    current_line.truncate(line_prefix.len());
20122                    current_line_len = line_prefix_len;
20123                } else if current_line_len != line_prefix_len || preserve_existing_whitespace {
20124                    current_line.push_str(token);
20125                    current_line_len += grapheme_len;
20126                }
20127            }
20128            WordBreakToken::Newline => {
20129                in_whitespace = true;
20130                if preserve_existing_whitespace {
20131                    wrapped_text.push_str(current_line.trim_end());
20132                    wrapped_text.push('\n');
20133                    current_line.truncate(line_prefix.len());
20134                    current_line_len = line_prefix_len;
20135                } else if have_preceding_whitespace {
20136                    continue;
20137                } else if current_line_len + 1 > wrap_column && current_line_len != line_prefix_len
20138                {
20139                    wrapped_text.push_str(current_line.trim_end());
20140                    wrapped_text.push('\n');
20141                    current_line.truncate(line_prefix.len());
20142                    current_line_len = line_prefix_len;
20143                } else if current_line_len != line_prefix_len {
20144                    current_line.push(' ');
20145                    current_line_len += 1;
20146                }
20147            }
20148        }
20149    }
20150
20151    if !current_line.is_empty() {
20152        wrapped_text.push_str(&current_line);
20153    }
20154    wrapped_text
20155}
20156
20157#[test]
20158fn test_wrap_with_prefix() {
20159    assert_eq!(
20160        wrap_with_prefix(
20161            "# ".to_string(),
20162            "abcdefg".to_string(),
20163            4,
20164            NonZeroU32::new(4).unwrap(),
20165            false,
20166        ),
20167        "# abcdefg"
20168    );
20169    assert_eq!(
20170        wrap_with_prefix(
20171            "".to_string(),
20172            "\thello world".to_string(),
20173            8,
20174            NonZeroU32::new(4).unwrap(),
20175            false,
20176        ),
20177        "hello\nworld"
20178    );
20179    assert_eq!(
20180        wrap_with_prefix(
20181            "// ".to_string(),
20182            "xx \nyy zz aa bb cc".to_string(),
20183            12,
20184            NonZeroU32::new(4).unwrap(),
20185            false,
20186        ),
20187        "// xx yy zz\n// aa bb cc"
20188    );
20189    assert_eq!(
20190        wrap_with_prefix(
20191            String::new(),
20192            "这是什么 \n 钢笔".to_string(),
20193            3,
20194            NonZeroU32::new(4).unwrap(),
20195            false,
20196        ),
20197        "这是什\n么 钢\n"
20198    );
20199}
20200
20201pub trait CollaborationHub {
20202    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
20203    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
20204    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
20205}
20206
20207impl CollaborationHub for Entity<Project> {
20208    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
20209        self.read(cx).collaborators()
20210    }
20211
20212    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
20213        self.read(cx).user_store().read(cx).participant_indices()
20214    }
20215
20216    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
20217        let this = self.read(cx);
20218        let user_ids = this.collaborators().values().map(|c| c.user_id);
20219        this.user_store().read(cx).participant_names(user_ids, cx)
20220    }
20221}
20222
20223pub trait SemanticsProvider {
20224    fn hover(
20225        &self,
20226        buffer: &Entity<Buffer>,
20227        position: text::Anchor,
20228        cx: &mut App,
20229    ) -> Option<Task<Vec<project::Hover>>>;
20230
20231    fn inline_values(
20232        &self,
20233        buffer_handle: Entity<Buffer>,
20234        range: Range<text::Anchor>,
20235        cx: &mut App,
20236    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20237
20238    fn inlay_hints(
20239        &self,
20240        buffer_handle: Entity<Buffer>,
20241        range: Range<text::Anchor>,
20242        cx: &mut App,
20243    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
20244
20245    fn resolve_inlay_hint(
20246        &self,
20247        hint: InlayHint,
20248        buffer_handle: Entity<Buffer>,
20249        server_id: LanguageServerId,
20250        cx: &mut App,
20251    ) -> Option<Task<anyhow::Result<InlayHint>>>;
20252
20253    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
20254
20255    fn document_highlights(
20256        &self,
20257        buffer: &Entity<Buffer>,
20258        position: text::Anchor,
20259        cx: &mut App,
20260    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
20261
20262    fn definitions(
20263        &self,
20264        buffer: &Entity<Buffer>,
20265        position: text::Anchor,
20266        kind: GotoDefinitionKind,
20267        cx: &mut App,
20268    ) -> Option<Task<Result<Vec<LocationLink>>>>;
20269
20270    fn range_for_rename(
20271        &self,
20272        buffer: &Entity<Buffer>,
20273        position: text::Anchor,
20274        cx: &mut App,
20275    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
20276
20277    fn perform_rename(
20278        &self,
20279        buffer: &Entity<Buffer>,
20280        position: text::Anchor,
20281        new_name: String,
20282        cx: &mut App,
20283    ) -> Option<Task<Result<ProjectTransaction>>>;
20284}
20285
20286pub trait CompletionProvider {
20287    fn completions(
20288        &self,
20289        excerpt_id: ExcerptId,
20290        buffer: &Entity<Buffer>,
20291        buffer_position: text::Anchor,
20292        trigger: CompletionContext,
20293        window: &mut Window,
20294        cx: &mut Context<Editor>,
20295    ) -> Task<Result<Vec<CompletionResponse>>>;
20296
20297    fn resolve_completions(
20298        &self,
20299        buffer: Entity<Buffer>,
20300        completion_indices: Vec<usize>,
20301        completions: Rc<RefCell<Box<[Completion]>>>,
20302        cx: &mut Context<Editor>,
20303    ) -> Task<Result<bool>>;
20304
20305    fn apply_additional_edits_for_completion(
20306        &self,
20307        _buffer: Entity<Buffer>,
20308        _completions: Rc<RefCell<Box<[Completion]>>>,
20309        _completion_index: usize,
20310        _push_to_history: bool,
20311        _cx: &mut Context<Editor>,
20312    ) -> Task<Result<Option<language::Transaction>>> {
20313        Task::ready(Ok(None))
20314    }
20315
20316    fn is_completion_trigger(
20317        &self,
20318        buffer: &Entity<Buffer>,
20319        position: language::Anchor,
20320        text: &str,
20321        trigger_in_words: bool,
20322        menu_is_open: bool,
20323        cx: &mut Context<Editor>,
20324    ) -> bool;
20325
20326    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
20327
20328    fn sort_completions(&self) -> bool {
20329        true
20330    }
20331
20332    fn filter_completions(&self) -> bool {
20333        true
20334    }
20335}
20336
20337pub trait CodeActionProvider {
20338    fn id(&self) -> Arc<str>;
20339
20340    fn code_actions(
20341        &self,
20342        buffer: &Entity<Buffer>,
20343        range: Range<text::Anchor>,
20344        window: &mut Window,
20345        cx: &mut App,
20346    ) -> Task<Result<Vec<CodeAction>>>;
20347
20348    fn apply_code_action(
20349        &self,
20350        buffer_handle: Entity<Buffer>,
20351        action: CodeAction,
20352        excerpt_id: ExcerptId,
20353        push_to_history: bool,
20354        window: &mut Window,
20355        cx: &mut App,
20356    ) -> Task<Result<ProjectTransaction>>;
20357}
20358
20359impl CodeActionProvider for Entity<Project> {
20360    fn id(&self) -> Arc<str> {
20361        "project".into()
20362    }
20363
20364    fn code_actions(
20365        &self,
20366        buffer: &Entity<Buffer>,
20367        range: Range<text::Anchor>,
20368        _window: &mut Window,
20369        cx: &mut App,
20370    ) -> Task<Result<Vec<CodeAction>>> {
20371        self.update(cx, |project, cx| {
20372            let code_lens = project.code_lens(buffer, range.clone(), cx);
20373            let code_actions = project.code_actions(buffer, range, None, cx);
20374            cx.background_spawn(async move {
20375                let (code_lens, code_actions) = join(code_lens, code_actions).await;
20376                Ok(code_lens
20377                    .context("code lens fetch")?
20378                    .into_iter()
20379                    .chain(code_actions.context("code action fetch")?)
20380                    .collect())
20381            })
20382        })
20383    }
20384
20385    fn apply_code_action(
20386        &self,
20387        buffer_handle: Entity<Buffer>,
20388        action: CodeAction,
20389        _excerpt_id: ExcerptId,
20390        push_to_history: bool,
20391        _window: &mut Window,
20392        cx: &mut App,
20393    ) -> Task<Result<ProjectTransaction>> {
20394        self.update(cx, |project, cx| {
20395            project.apply_code_action(buffer_handle, action, push_to_history, cx)
20396        })
20397    }
20398}
20399
20400fn snippet_completions(
20401    project: &Project,
20402    buffer: &Entity<Buffer>,
20403    buffer_position: text::Anchor,
20404    cx: &mut App,
20405) -> Task<Result<CompletionResponse>> {
20406    let languages = buffer.read(cx).languages_at(buffer_position);
20407    let snippet_store = project.snippets().read(cx);
20408
20409    let scopes: Vec<_> = languages
20410        .iter()
20411        .filter_map(|language| {
20412            let language_name = language.lsp_id();
20413            let snippets = snippet_store.snippets_for(Some(language_name), cx);
20414
20415            if snippets.is_empty() {
20416                None
20417            } else {
20418                Some((language.default_scope(), snippets))
20419            }
20420        })
20421        .collect();
20422
20423    if scopes.is_empty() {
20424        return Task::ready(Ok(CompletionResponse {
20425            completions: vec![],
20426            is_incomplete: false,
20427        }));
20428    }
20429
20430    let snapshot = buffer.read(cx).text_snapshot();
20431    let chars: String = snapshot
20432        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
20433        .collect();
20434    let executor = cx.background_executor().clone();
20435
20436    cx.background_spawn(async move {
20437        let mut is_incomplete = false;
20438        let mut completions: Vec<Completion> = Vec::new();
20439        for (scope, snippets) in scopes.into_iter() {
20440            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
20441            let mut last_word = chars
20442                .chars()
20443                .take_while(|c| classifier.is_word(*c))
20444                .collect::<String>();
20445            last_word = last_word.chars().rev().collect();
20446
20447            if last_word.is_empty() {
20448                return Ok(CompletionResponse {
20449                    completions: vec![],
20450                    is_incomplete: true,
20451                });
20452            }
20453
20454            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
20455            let to_lsp = |point: &text::Anchor| {
20456                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
20457                point_to_lsp(end)
20458            };
20459            let lsp_end = to_lsp(&buffer_position);
20460
20461            let candidates = snippets
20462                .iter()
20463                .enumerate()
20464                .flat_map(|(ix, snippet)| {
20465                    snippet
20466                        .prefix
20467                        .iter()
20468                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
20469                })
20470                .collect::<Vec<StringMatchCandidate>>();
20471
20472            const MAX_RESULTS: usize = 100;
20473            let mut matches = fuzzy::match_strings(
20474                &candidates,
20475                &last_word,
20476                last_word.chars().any(|c| c.is_uppercase()),
20477                MAX_RESULTS,
20478                &Default::default(),
20479                executor.clone(),
20480            )
20481            .await;
20482
20483            if matches.len() >= MAX_RESULTS {
20484                is_incomplete = true;
20485            }
20486
20487            // Remove all candidates where the query's start does not match the start of any word in the candidate
20488            if let Some(query_start) = last_word.chars().next() {
20489                matches.retain(|string_match| {
20490                    split_words(&string_match.string).any(|word| {
20491                        // Check that the first codepoint of the word as lowercase matches the first
20492                        // codepoint of the query as lowercase
20493                        word.chars()
20494                            .flat_map(|codepoint| codepoint.to_lowercase())
20495                            .zip(query_start.to_lowercase())
20496                            .all(|(word_cp, query_cp)| word_cp == query_cp)
20497                    })
20498                });
20499            }
20500
20501            let matched_strings = matches
20502                .into_iter()
20503                .map(|m| m.string)
20504                .collect::<HashSet<_>>();
20505
20506            completions.extend(snippets.iter().filter_map(|snippet| {
20507                let matching_prefix = snippet
20508                    .prefix
20509                    .iter()
20510                    .find(|prefix| matched_strings.contains(*prefix))?;
20511                let start = as_offset - last_word.len();
20512                let start = snapshot.anchor_before(start);
20513                let range = start..buffer_position;
20514                let lsp_start = to_lsp(&start);
20515                let lsp_range = lsp::Range {
20516                    start: lsp_start,
20517                    end: lsp_end,
20518                };
20519                Some(Completion {
20520                    replace_range: range,
20521                    new_text: snippet.body.clone(),
20522                    source: CompletionSource::Lsp {
20523                        insert_range: None,
20524                        server_id: LanguageServerId(usize::MAX),
20525                        resolved: true,
20526                        lsp_completion: Box::new(lsp::CompletionItem {
20527                            label: snippet.prefix.first().unwrap().clone(),
20528                            kind: Some(CompletionItemKind::SNIPPET),
20529                            label_details: snippet.description.as_ref().map(|description| {
20530                                lsp::CompletionItemLabelDetails {
20531                                    detail: Some(description.clone()),
20532                                    description: None,
20533                                }
20534                            }),
20535                            insert_text_format: Some(InsertTextFormat::SNIPPET),
20536                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
20537                                lsp::InsertReplaceEdit {
20538                                    new_text: snippet.body.clone(),
20539                                    insert: lsp_range,
20540                                    replace: lsp_range,
20541                                },
20542                            )),
20543                            filter_text: Some(snippet.body.clone()),
20544                            sort_text: Some(char::MAX.to_string()),
20545                            ..lsp::CompletionItem::default()
20546                        }),
20547                        lsp_defaults: None,
20548                    },
20549                    label: CodeLabel {
20550                        text: matching_prefix.clone(),
20551                        runs: Vec::new(),
20552                        filter_range: 0..matching_prefix.len(),
20553                    },
20554                    icon_path: None,
20555                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
20556                        single_line: snippet.name.clone().into(),
20557                        plain_text: snippet
20558                            .description
20559                            .clone()
20560                            .map(|description| description.into()),
20561                    }),
20562                    insert_text_mode: None,
20563                    confirm: None,
20564                })
20565            }))
20566        }
20567
20568        Ok(CompletionResponse {
20569            completions,
20570            is_incomplete,
20571        })
20572    })
20573}
20574
20575impl CompletionProvider for Entity<Project> {
20576    fn completions(
20577        &self,
20578        _excerpt_id: ExcerptId,
20579        buffer: &Entity<Buffer>,
20580        buffer_position: text::Anchor,
20581        options: CompletionContext,
20582        _window: &mut Window,
20583        cx: &mut Context<Editor>,
20584    ) -> Task<Result<Vec<CompletionResponse>>> {
20585        self.update(cx, |project, cx| {
20586            let snippets = snippet_completions(project, buffer, buffer_position, cx);
20587            let project_completions = project.completions(buffer, buffer_position, options, cx);
20588            cx.background_spawn(async move {
20589                let mut responses = project_completions.await?;
20590                let snippets = snippets.await?;
20591                if !snippets.completions.is_empty() {
20592                    responses.push(snippets);
20593                }
20594                Ok(responses)
20595            })
20596        })
20597    }
20598
20599    fn resolve_completions(
20600        &self,
20601        buffer: Entity<Buffer>,
20602        completion_indices: Vec<usize>,
20603        completions: Rc<RefCell<Box<[Completion]>>>,
20604        cx: &mut Context<Editor>,
20605    ) -> Task<Result<bool>> {
20606        self.update(cx, |project, cx| {
20607            project.lsp_store().update(cx, |lsp_store, cx| {
20608                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
20609            })
20610        })
20611    }
20612
20613    fn apply_additional_edits_for_completion(
20614        &self,
20615        buffer: Entity<Buffer>,
20616        completions: Rc<RefCell<Box<[Completion]>>>,
20617        completion_index: usize,
20618        push_to_history: bool,
20619        cx: &mut Context<Editor>,
20620    ) -> Task<Result<Option<language::Transaction>>> {
20621        self.update(cx, |project, cx| {
20622            project.lsp_store().update(cx, |lsp_store, cx| {
20623                lsp_store.apply_additional_edits_for_completion(
20624                    buffer,
20625                    completions,
20626                    completion_index,
20627                    push_to_history,
20628                    cx,
20629                )
20630            })
20631        })
20632    }
20633
20634    fn is_completion_trigger(
20635        &self,
20636        buffer: &Entity<Buffer>,
20637        position: language::Anchor,
20638        text: &str,
20639        trigger_in_words: bool,
20640        menu_is_open: bool,
20641        cx: &mut Context<Editor>,
20642    ) -> bool {
20643        let mut chars = text.chars();
20644        let char = if let Some(char) = chars.next() {
20645            char
20646        } else {
20647            return false;
20648        };
20649        if chars.next().is_some() {
20650            return false;
20651        }
20652
20653        let buffer = buffer.read(cx);
20654        let snapshot = buffer.snapshot();
20655        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
20656            return false;
20657        }
20658        let classifier = snapshot.char_classifier_at(position).for_completion(true);
20659        if trigger_in_words && classifier.is_word(char) {
20660            return true;
20661        }
20662
20663        buffer.completion_triggers().contains(text)
20664    }
20665}
20666
20667impl SemanticsProvider for Entity<Project> {
20668    fn hover(
20669        &self,
20670        buffer: &Entity<Buffer>,
20671        position: text::Anchor,
20672        cx: &mut App,
20673    ) -> Option<Task<Vec<project::Hover>>> {
20674        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
20675    }
20676
20677    fn document_highlights(
20678        &self,
20679        buffer: &Entity<Buffer>,
20680        position: text::Anchor,
20681        cx: &mut App,
20682    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
20683        Some(self.update(cx, |project, cx| {
20684            project.document_highlights(buffer, position, cx)
20685        }))
20686    }
20687
20688    fn definitions(
20689        &self,
20690        buffer: &Entity<Buffer>,
20691        position: text::Anchor,
20692        kind: GotoDefinitionKind,
20693        cx: &mut App,
20694    ) -> Option<Task<Result<Vec<LocationLink>>>> {
20695        Some(self.update(cx, |project, cx| match kind {
20696            GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
20697            GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
20698            GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
20699            GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
20700        }))
20701    }
20702
20703    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
20704        // TODO: make this work for remote projects
20705        self.update(cx, |project, cx| {
20706            if project
20707                .active_debug_session(cx)
20708                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
20709            {
20710                return true;
20711            }
20712
20713            buffer.update(cx, |buffer, cx| {
20714                project.any_language_server_supports_inlay_hints(buffer, cx)
20715            })
20716        })
20717    }
20718
20719    fn inline_values(
20720        &self,
20721        buffer_handle: Entity<Buffer>,
20722
20723        range: Range<text::Anchor>,
20724        cx: &mut App,
20725    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20726        self.update(cx, |project, cx| {
20727            let (session, active_stack_frame) = project.active_debug_session(cx)?;
20728
20729            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
20730        })
20731    }
20732
20733    fn inlay_hints(
20734        &self,
20735        buffer_handle: Entity<Buffer>,
20736        range: Range<text::Anchor>,
20737        cx: &mut App,
20738    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
20739        Some(self.update(cx, |project, cx| {
20740            project.inlay_hints(buffer_handle, range, cx)
20741        }))
20742    }
20743
20744    fn resolve_inlay_hint(
20745        &self,
20746        hint: InlayHint,
20747        buffer_handle: Entity<Buffer>,
20748        server_id: LanguageServerId,
20749        cx: &mut App,
20750    ) -> Option<Task<anyhow::Result<InlayHint>>> {
20751        Some(self.update(cx, |project, cx| {
20752            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
20753        }))
20754    }
20755
20756    fn range_for_rename(
20757        &self,
20758        buffer: &Entity<Buffer>,
20759        position: text::Anchor,
20760        cx: &mut App,
20761    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
20762        Some(self.update(cx, |project, cx| {
20763            let buffer = buffer.clone();
20764            let task = project.prepare_rename(buffer.clone(), position, cx);
20765            cx.spawn(async move |_, cx| {
20766                Ok(match task.await? {
20767                    PrepareRenameResponse::Success(range) => Some(range),
20768                    PrepareRenameResponse::InvalidPosition => None,
20769                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
20770                        // Fallback on using TreeSitter info to determine identifier range
20771                        buffer.read_with(cx, |buffer, _| {
20772                            let snapshot = buffer.snapshot();
20773                            let (range, kind) = snapshot.surrounding_word(position);
20774                            if kind != Some(CharKind::Word) {
20775                                return None;
20776                            }
20777                            Some(
20778                                snapshot.anchor_before(range.start)
20779                                    ..snapshot.anchor_after(range.end),
20780                            )
20781                        })?
20782                    }
20783                })
20784            })
20785        }))
20786    }
20787
20788    fn perform_rename(
20789        &self,
20790        buffer: &Entity<Buffer>,
20791        position: text::Anchor,
20792        new_name: String,
20793        cx: &mut App,
20794    ) -> Option<Task<Result<ProjectTransaction>>> {
20795        Some(self.update(cx, |project, cx| {
20796            project.perform_rename(buffer.clone(), position, new_name, cx)
20797        }))
20798    }
20799}
20800
20801fn inlay_hint_settings(
20802    location: Anchor,
20803    snapshot: &MultiBufferSnapshot,
20804    cx: &mut Context<Editor>,
20805) -> InlayHintSettings {
20806    let file = snapshot.file_at(location);
20807    let language = snapshot.language_at(location).map(|l| l.name());
20808    language_settings(language, file, cx).inlay_hints
20809}
20810
20811fn consume_contiguous_rows(
20812    contiguous_row_selections: &mut Vec<Selection<Point>>,
20813    selection: &Selection<Point>,
20814    display_map: &DisplaySnapshot,
20815    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
20816) -> (MultiBufferRow, MultiBufferRow) {
20817    contiguous_row_selections.push(selection.clone());
20818    let start_row = MultiBufferRow(selection.start.row);
20819    let mut end_row = ending_row(selection, display_map);
20820
20821    while let Some(next_selection) = selections.peek() {
20822        if next_selection.start.row <= end_row.0 {
20823            end_row = ending_row(next_selection, display_map);
20824            contiguous_row_selections.push(selections.next().unwrap().clone());
20825        } else {
20826            break;
20827        }
20828    }
20829    (start_row, end_row)
20830}
20831
20832fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
20833    if next_selection.end.column > 0 || next_selection.is_empty() {
20834        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
20835    } else {
20836        MultiBufferRow(next_selection.end.row)
20837    }
20838}
20839
20840impl EditorSnapshot {
20841    pub fn remote_selections_in_range<'a>(
20842        &'a self,
20843        range: &'a Range<Anchor>,
20844        collaboration_hub: &dyn CollaborationHub,
20845        cx: &'a App,
20846    ) -> impl 'a + Iterator<Item = RemoteSelection> {
20847        let participant_names = collaboration_hub.user_names(cx);
20848        let participant_indices = collaboration_hub.user_participant_indices(cx);
20849        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
20850        let collaborators_by_replica_id = collaborators_by_peer_id
20851            .values()
20852            .map(|collaborator| (collaborator.replica_id, collaborator))
20853            .collect::<HashMap<_, _>>();
20854        self.buffer_snapshot
20855            .selections_in_range(range, false)
20856            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
20857                if replica_id == AGENT_REPLICA_ID {
20858                    Some(RemoteSelection {
20859                        replica_id,
20860                        selection,
20861                        cursor_shape,
20862                        line_mode,
20863                        collaborator_id: CollaboratorId::Agent,
20864                        user_name: Some("Agent".into()),
20865                        color: cx.theme().players().agent(),
20866                    })
20867                } else {
20868                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
20869                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
20870                    let user_name = participant_names.get(&collaborator.user_id).cloned();
20871                    Some(RemoteSelection {
20872                        replica_id,
20873                        selection,
20874                        cursor_shape,
20875                        line_mode,
20876                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
20877                        user_name,
20878                        color: if let Some(index) = participant_index {
20879                            cx.theme().players().color_for_participant(index.0)
20880                        } else {
20881                            cx.theme().players().absent()
20882                        },
20883                    })
20884                }
20885            })
20886    }
20887
20888    pub fn hunks_for_ranges(
20889        &self,
20890        ranges: impl IntoIterator<Item = Range<Point>>,
20891    ) -> Vec<MultiBufferDiffHunk> {
20892        let mut hunks = Vec::new();
20893        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
20894            HashMap::default();
20895        for query_range in ranges {
20896            let query_rows =
20897                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
20898            for hunk in self.buffer_snapshot.diff_hunks_in_range(
20899                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
20900            ) {
20901                // Include deleted hunks that are adjacent to the query range, because
20902                // otherwise they would be missed.
20903                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
20904                if hunk.status().is_deleted() {
20905                    intersects_range |= hunk.row_range.start == query_rows.end;
20906                    intersects_range |= hunk.row_range.end == query_rows.start;
20907                }
20908                if intersects_range {
20909                    if !processed_buffer_rows
20910                        .entry(hunk.buffer_id)
20911                        .or_default()
20912                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
20913                    {
20914                        continue;
20915                    }
20916                    hunks.push(hunk);
20917                }
20918            }
20919        }
20920
20921        hunks
20922    }
20923
20924    fn display_diff_hunks_for_rows<'a>(
20925        &'a self,
20926        display_rows: Range<DisplayRow>,
20927        folded_buffers: &'a HashSet<BufferId>,
20928    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
20929        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
20930        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
20931
20932        self.buffer_snapshot
20933            .diff_hunks_in_range(buffer_start..buffer_end)
20934            .filter_map(|hunk| {
20935                if folded_buffers.contains(&hunk.buffer_id) {
20936                    return None;
20937                }
20938
20939                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
20940                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
20941
20942                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
20943                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
20944
20945                let display_hunk = if hunk_display_start.column() != 0 {
20946                    DisplayDiffHunk::Folded {
20947                        display_row: hunk_display_start.row(),
20948                    }
20949                } else {
20950                    let mut end_row = hunk_display_end.row();
20951                    if hunk_display_end.column() > 0 {
20952                        end_row.0 += 1;
20953                    }
20954                    let is_created_file = hunk.is_created_file();
20955                    DisplayDiffHunk::Unfolded {
20956                        status: hunk.status(),
20957                        diff_base_byte_range: hunk.diff_base_byte_range,
20958                        display_row_range: hunk_display_start.row()..end_row,
20959                        multi_buffer_range: Anchor::range_in_buffer(
20960                            hunk.excerpt_id,
20961                            hunk.buffer_id,
20962                            hunk.buffer_range,
20963                        ),
20964                        is_created_file,
20965                    }
20966                };
20967
20968                Some(display_hunk)
20969            })
20970    }
20971
20972    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
20973        self.display_snapshot.buffer_snapshot.language_at(position)
20974    }
20975
20976    pub fn is_focused(&self) -> bool {
20977        self.is_focused
20978    }
20979
20980    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
20981        self.placeholder_text.as_ref()
20982    }
20983
20984    pub fn scroll_position(&self) -> gpui::Point<f32> {
20985        self.scroll_anchor.scroll_position(&self.display_snapshot)
20986    }
20987
20988    fn gutter_dimensions(
20989        &self,
20990        font_id: FontId,
20991        font_size: Pixels,
20992        max_line_number_width: Pixels,
20993        cx: &App,
20994    ) -> Option<GutterDimensions> {
20995        if !self.show_gutter {
20996            return None;
20997        }
20998
20999        let em_width = cx.text_system().em_width(font_id, font_size).log_err()?;
21000        let em_advance = cx.text_system().em_advance(font_id, font_size).log_err()?;
21001
21002        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
21003            matches!(
21004                ProjectSettings::get_global(cx).git.git_gutter,
21005                Some(GitGutterSetting::TrackedFiles)
21006            )
21007        });
21008        let gutter_settings = EditorSettings::get_global(cx).gutter;
21009        let show_line_numbers = self
21010            .show_line_numbers
21011            .unwrap_or(gutter_settings.line_numbers);
21012        let line_gutter_width = if show_line_numbers {
21013            // Avoid flicker-like gutter resizes when the line number gains another digit and only resize the gutter on files with N*10^5 lines.
21014            let min_width_for_number_on_gutter = em_advance * MIN_LINE_NUMBER_DIGITS as f32;
21015            max_line_number_width.max(min_width_for_number_on_gutter)
21016        } else {
21017            0.0.into()
21018        };
21019
21020        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
21021        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
21022
21023        let git_blame_entries_width =
21024            self.git_blame_gutter_max_author_length
21025                .map(|max_author_length| {
21026                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
21027                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
21028
21029                    /// The number of characters to dedicate to gaps and margins.
21030                    const SPACING_WIDTH: usize = 4;
21031
21032                    let max_char_count = max_author_length.min(renderer.max_author_length())
21033                        + ::git::SHORT_SHA_LENGTH
21034                        + MAX_RELATIVE_TIMESTAMP.len()
21035                        + SPACING_WIDTH;
21036
21037                    em_advance * max_char_count
21038                });
21039
21040        let is_singleton = self.buffer_snapshot.is_singleton();
21041
21042        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
21043        left_padding += if !is_singleton {
21044            em_width * 4.0
21045        } else if show_runnables || show_breakpoints {
21046            em_width * 3.0
21047        } else if show_git_gutter && show_line_numbers {
21048            em_width * 2.0
21049        } else if show_git_gutter || show_line_numbers {
21050            em_width
21051        } else {
21052            px(0.)
21053        };
21054
21055        let shows_folds = is_singleton && gutter_settings.folds;
21056
21057        let right_padding = if shows_folds && show_line_numbers {
21058            em_width * 4.0
21059        } else if shows_folds || (!is_singleton && show_line_numbers) {
21060            em_width * 3.0
21061        } else if show_line_numbers {
21062            em_width
21063        } else {
21064            px(0.)
21065        };
21066
21067        Some(GutterDimensions {
21068            left_padding,
21069            right_padding,
21070            width: line_gutter_width + left_padding + right_padding,
21071            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
21072            git_blame_entries_width,
21073        })
21074    }
21075
21076    pub fn render_crease_toggle(
21077        &self,
21078        buffer_row: MultiBufferRow,
21079        row_contains_cursor: bool,
21080        editor: Entity<Editor>,
21081        window: &mut Window,
21082        cx: &mut App,
21083    ) -> Option<AnyElement> {
21084        let folded = self.is_line_folded(buffer_row);
21085        let mut is_foldable = false;
21086
21087        if let Some(crease) = self
21088            .crease_snapshot
21089            .query_row(buffer_row, &self.buffer_snapshot)
21090        {
21091            is_foldable = true;
21092            match crease {
21093                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
21094                    if let Some(render_toggle) = render_toggle {
21095                        let toggle_callback =
21096                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
21097                                if folded {
21098                                    editor.update(cx, |editor, cx| {
21099                                        editor.fold_at(buffer_row, window, cx)
21100                                    });
21101                                } else {
21102                                    editor.update(cx, |editor, cx| {
21103                                        editor.unfold_at(buffer_row, window, cx)
21104                                    });
21105                                }
21106                            });
21107                        return Some((render_toggle)(
21108                            buffer_row,
21109                            folded,
21110                            toggle_callback,
21111                            window,
21112                            cx,
21113                        ));
21114                    }
21115                }
21116            }
21117        }
21118
21119        is_foldable |= self.starts_indent(buffer_row);
21120
21121        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
21122            Some(
21123                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
21124                    .toggle_state(folded)
21125                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
21126                        if folded {
21127                            this.unfold_at(buffer_row, window, cx);
21128                        } else {
21129                            this.fold_at(buffer_row, window, cx);
21130                        }
21131                    }))
21132                    .into_any_element(),
21133            )
21134        } else {
21135            None
21136        }
21137    }
21138
21139    pub fn render_crease_trailer(
21140        &self,
21141        buffer_row: MultiBufferRow,
21142        window: &mut Window,
21143        cx: &mut App,
21144    ) -> Option<AnyElement> {
21145        let folded = self.is_line_folded(buffer_row);
21146        if let Crease::Inline { render_trailer, .. } = self
21147            .crease_snapshot
21148            .query_row(buffer_row, &self.buffer_snapshot)?
21149        {
21150            let render_trailer = render_trailer.as_ref()?;
21151            Some(render_trailer(buffer_row, folded, window, cx))
21152        } else {
21153            None
21154        }
21155    }
21156}
21157
21158impl Deref for EditorSnapshot {
21159    type Target = DisplaySnapshot;
21160
21161    fn deref(&self) -> &Self::Target {
21162        &self.display_snapshot
21163    }
21164}
21165
21166#[derive(Clone, Debug, PartialEq, Eq)]
21167pub enum EditorEvent {
21168    InputIgnored {
21169        text: Arc<str>,
21170    },
21171    InputHandled {
21172        utf16_range_to_replace: Option<Range<isize>>,
21173        text: Arc<str>,
21174    },
21175    ExcerptsAdded {
21176        buffer: Entity<Buffer>,
21177        predecessor: ExcerptId,
21178        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
21179    },
21180    ExcerptsRemoved {
21181        ids: Vec<ExcerptId>,
21182        removed_buffer_ids: Vec<BufferId>,
21183    },
21184    BufferFoldToggled {
21185        ids: Vec<ExcerptId>,
21186        folded: bool,
21187    },
21188    ExcerptsEdited {
21189        ids: Vec<ExcerptId>,
21190    },
21191    ExcerptsExpanded {
21192        ids: Vec<ExcerptId>,
21193    },
21194    BufferEdited,
21195    Edited {
21196        transaction_id: clock::Lamport,
21197    },
21198    Reparsed(BufferId),
21199    Focused,
21200    FocusedIn,
21201    Blurred,
21202    DirtyChanged,
21203    Saved,
21204    TitleChanged,
21205    DiffBaseChanged,
21206    SelectionsChanged {
21207        local: bool,
21208    },
21209    ScrollPositionChanged {
21210        local: bool,
21211        autoscroll: bool,
21212    },
21213    Closed,
21214    TransactionUndone {
21215        transaction_id: clock::Lamport,
21216    },
21217    TransactionBegun {
21218        transaction_id: clock::Lamport,
21219    },
21220    Reloaded,
21221    CursorShapeChanged,
21222    PushedToNavHistory {
21223        anchor: Anchor,
21224        is_deactivate: bool,
21225    },
21226}
21227
21228impl EventEmitter<EditorEvent> for Editor {}
21229
21230impl Focusable for Editor {
21231    fn focus_handle(&self, _cx: &App) -> FocusHandle {
21232        self.focus_handle.clone()
21233    }
21234}
21235
21236impl Render for Editor {
21237    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
21238        let settings = ThemeSettings::get_global(cx);
21239
21240        let mut text_style = match self.mode {
21241            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
21242                color: cx.theme().colors().editor_foreground,
21243                font_family: settings.ui_font.family.clone(),
21244                font_features: settings.ui_font.features.clone(),
21245                font_fallbacks: settings.ui_font.fallbacks.clone(),
21246                font_size: rems(0.875).into(),
21247                font_weight: settings.ui_font.weight,
21248                line_height: relative(settings.buffer_line_height.value()),
21249                ..Default::default()
21250            },
21251            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
21252                color: cx.theme().colors().editor_foreground,
21253                font_family: settings.buffer_font.family.clone(),
21254                font_features: settings.buffer_font.features.clone(),
21255                font_fallbacks: settings.buffer_font.fallbacks.clone(),
21256                font_size: settings.buffer_font_size(cx).into(),
21257                font_weight: settings.buffer_font.weight,
21258                line_height: relative(settings.buffer_line_height.value()),
21259                ..Default::default()
21260            },
21261        };
21262        if let Some(text_style_refinement) = &self.text_style_refinement {
21263            text_style.refine(text_style_refinement)
21264        }
21265
21266        let background = match self.mode {
21267            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
21268            EditorMode::AutoHeight { max_lines: _ } => cx.theme().system().transparent,
21269            EditorMode::Full { .. } => cx.theme().colors().editor_background,
21270            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
21271        };
21272
21273        EditorElement::new(
21274            &cx.entity(),
21275            EditorStyle {
21276                background,
21277                local_player: cx.theme().players().local(),
21278                text: text_style,
21279                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
21280                syntax: cx.theme().syntax().clone(),
21281                status: cx.theme().status().clone(),
21282                inlay_hints_style: make_inlay_hints_style(cx),
21283                inline_completion_styles: make_suggestion_styles(cx),
21284                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
21285                show_underlines: !self.mode.is_minimap(),
21286            },
21287        )
21288    }
21289}
21290
21291impl EntityInputHandler for Editor {
21292    fn text_for_range(
21293        &mut self,
21294        range_utf16: Range<usize>,
21295        adjusted_range: &mut Option<Range<usize>>,
21296        _: &mut Window,
21297        cx: &mut Context<Self>,
21298    ) -> Option<String> {
21299        let snapshot = self.buffer.read(cx).read(cx);
21300        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
21301        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
21302        if (start.0..end.0) != range_utf16 {
21303            adjusted_range.replace(start.0..end.0);
21304        }
21305        Some(snapshot.text_for_range(start..end).collect())
21306    }
21307
21308    fn selected_text_range(
21309        &mut self,
21310        ignore_disabled_input: bool,
21311        _: &mut Window,
21312        cx: &mut Context<Self>,
21313    ) -> Option<UTF16Selection> {
21314        // Prevent the IME menu from appearing when holding down an alphabetic key
21315        // while input is disabled.
21316        if !ignore_disabled_input && !self.input_enabled {
21317            return None;
21318        }
21319
21320        let selection = self.selections.newest::<OffsetUtf16>(cx);
21321        let range = selection.range();
21322
21323        Some(UTF16Selection {
21324            range: range.start.0..range.end.0,
21325            reversed: selection.reversed,
21326        })
21327    }
21328
21329    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
21330        let snapshot = self.buffer.read(cx).read(cx);
21331        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
21332        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
21333    }
21334
21335    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21336        self.clear_highlights::<InputComposition>(cx);
21337        self.ime_transaction.take();
21338    }
21339
21340    fn replace_text_in_range(
21341        &mut self,
21342        range_utf16: Option<Range<usize>>,
21343        text: &str,
21344        window: &mut Window,
21345        cx: &mut Context<Self>,
21346    ) {
21347        if !self.input_enabled {
21348            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21349            return;
21350        }
21351
21352        self.transact(window, cx, |this, window, cx| {
21353            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
21354                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21355                Some(this.selection_replacement_ranges(range_utf16, cx))
21356            } else {
21357                this.marked_text_ranges(cx)
21358            };
21359
21360            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
21361                let newest_selection_id = this.selections.newest_anchor().id;
21362                this.selections
21363                    .all::<OffsetUtf16>(cx)
21364                    .iter()
21365                    .zip(ranges_to_replace.iter())
21366                    .find_map(|(selection, range)| {
21367                        if selection.id == newest_selection_id {
21368                            Some(
21369                                (range.start.0 as isize - selection.head().0 as isize)
21370                                    ..(range.end.0 as isize - selection.head().0 as isize),
21371                            )
21372                        } else {
21373                            None
21374                        }
21375                    })
21376            });
21377
21378            cx.emit(EditorEvent::InputHandled {
21379                utf16_range_to_replace: range_to_replace,
21380                text: text.into(),
21381            });
21382
21383            if let Some(new_selected_ranges) = new_selected_ranges {
21384                this.change_selections(None, window, cx, |selections| {
21385                    selections.select_ranges(new_selected_ranges)
21386                });
21387                this.backspace(&Default::default(), window, cx);
21388            }
21389
21390            this.handle_input(text, window, cx);
21391        });
21392
21393        if let Some(transaction) = self.ime_transaction {
21394            self.buffer.update(cx, |buffer, cx| {
21395                buffer.group_until_transaction(transaction, cx);
21396            });
21397        }
21398
21399        self.unmark_text(window, cx);
21400    }
21401
21402    fn replace_and_mark_text_in_range(
21403        &mut self,
21404        range_utf16: Option<Range<usize>>,
21405        text: &str,
21406        new_selected_range_utf16: Option<Range<usize>>,
21407        window: &mut Window,
21408        cx: &mut Context<Self>,
21409    ) {
21410        if !self.input_enabled {
21411            return;
21412        }
21413
21414        let transaction = self.transact(window, cx, |this, window, cx| {
21415            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
21416                let snapshot = this.buffer.read(cx).read(cx);
21417                if let Some(relative_range_utf16) = range_utf16.as_ref() {
21418                    for marked_range in &mut marked_ranges {
21419                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
21420                        marked_range.start.0 += relative_range_utf16.start;
21421                        marked_range.start =
21422                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
21423                        marked_range.end =
21424                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
21425                    }
21426                }
21427                Some(marked_ranges)
21428            } else if let Some(range_utf16) = range_utf16 {
21429                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
21430                Some(this.selection_replacement_ranges(range_utf16, cx))
21431            } else {
21432                None
21433            };
21434
21435            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
21436                let newest_selection_id = this.selections.newest_anchor().id;
21437                this.selections
21438                    .all::<OffsetUtf16>(cx)
21439                    .iter()
21440                    .zip(ranges_to_replace.iter())
21441                    .find_map(|(selection, range)| {
21442                        if selection.id == newest_selection_id {
21443                            Some(
21444                                (range.start.0 as isize - selection.head().0 as isize)
21445                                    ..(range.end.0 as isize - selection.head().0 as isize),
21446                            )
21447                        } else {
21448                            None
21449                        }
21450                    })
21451            });
21452
21453            cx.emit(EditorEvent::InputHandled {
21454                utf16_range_to_replace: range_to_replace,
21455                text: text.into(),
21456            });
21457
21458            if let Some(ranges) = ranges_to_replace {
21459                this.change_selections(None, window, cx, |s| s.select_ranges(ranges));
21460            }
21461
21462            let marked_ranges = {
21463                let snapshot = this.buffer.read(cx).read(cx);
21464                this.selections
21465                    .disjoint_anchors()
21466                    .iter()
21467                    .map(|selection| {
21468                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
21469                    })
21470                    .collect::<Vec<_>>()
21471            };
21472
21473            if text.is_empty() {
21474                this.unmark_text(window, cx);
21475            } else {
21476                this.highlight_text::<InputComposition>(
21477                    marked_ranges.clone(),
21478                    HighlightStyle {
21479                        underline: Some(UnderlineStyle {
21480                            thickness: px(1.),
21481                            color: None,
21482                            wavy: false,
21483                        }),
21484                        ..Default::default()
21485                    },
21486                    cx,
21487                );
21488            }
21489
21490            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
21491            let use_autoclose = this.use_autoclose;
21492            let use_auto_surround = this.use_auto_surround;
21493            this.set_use_autoclose(false);
21494            this.set_use_auto_surround(false);
21495            this.handle_input(text, window, cx);
21496            this.set_use_autoclose(use_autoclose);
21497            this.set_use_auto_surround(use_auto_surround);
21498
21499            if let Some(new_selected_range) = new_selected_range_utf16 {
21500                let snapshot = this.buffer.read(cx).read(cx);
21501                let new_selected_ranges = marked_ranges
21502                    .into_iter()
21503                    .map(|marked_range| {
21504                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
21505                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
21506                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
21507                        snapshot.clip_offset_utf16(new_start, Bias::Left)
21508                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
21509                    })
21510                    .collect::<Vec<_>>();
21511
21512                drop(snapshot);
21513                this.change_selections(None, window, cx, |selections| {
21514                    selections.select_ranges(new_selected_ranges)
21515                });
21516            }
21517        });
21518
21519        self.ime_transaction = self.ime_transaction.or(transaction);
21520        if let Some(transaction) = self.ime_transaction {
21521            self.buffer.update(cx, |buffer, cx| {
21522                buffer.group_until_transaction(transaction, cx);
21523            });
21524        }
21525
21526        if self.text_highlights::<InputComposition>(cx).is_none() {
21527            self.ime_transaction.take();
21528        }
21529    }
21530
21531    fn bounds_for_range(
21532        &mut self,
21533        range_utf16: Range<usize>,
21534        element_bounds: gpui::Bounds<Pixels>,
21535        window: &mut Window,
21536        cx: &mut Context<Self>,
21537    ) -> Option<gpui::Bounds<Pixels>> {
21538        let text_layout_details = self.text_layout_details(window);
21539        let gpui::Size {
21540            width: em_width,
21541            height: line_height,
21542        } = self.character_size(window);
21543
21544        let snapshot = self.snapshot(window, cx);
21545        let scroll_position = snapshot.scroll_position();
21546        let scroll_left = scroll_position.x * em_width;
21547
21548        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
21549        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
21550            + self.gutter_dimensions.width
21551            + self.gutter_dimensions.margin;
21552        let y = line_height * (start.row().as_f32() - scroll_position.y);
21553
21554        Some(Bounds {
21555            origin: element_bounds.origin + point(x, y),
21556            size: size(em_width, line_height),
21557        })
21558    }
21559
21560    fn character_index_for_point(
21561        &mut self,
21562        point: gpui::Point<Pixels>,
21563        _window: &mut Window,
21564        _cx: &mut Context<Self>,
21565    ) -> Option<usize> {
21566        let position_map = self.last_position_map.as_ref()?;
21567        if !position_map.text_hitbox.contains(&point) {
21568            return None;
21569        }
21570        let display_point = position_map.point_for_position(point).previous_valid;
21571        let anchor = position_map
21572            .snapshot
21573            .display_point_to_anchor(display_point, Bias::Left);
21574        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
21575        Some(utf16_offset.0)
21576    }
21577}
21578
21579trait SelectionExt {
21580    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
21581    fn spanned_rows(
21582        &self,
21583        include_end_if_at_line_start: bool,
21584        map: &DisplaySnapshot,
21585    ) -> Range<MultiBufferRow>;
21586}
21587
21588impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
21589    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
21590        let start = self
21591            .start
21592            .to_point(&map.buffer_snapshot)
21593            .to_display_point(map);
21594        let end = self
21595            .end
21596            .to_point(&map.buffer_snapshot)
21597            .to_display_point(map);
21598        if self.reversed {
21599            end..start
21600        } else {
21601            start..end
21602        }
21603    }
21604
21605    fn spanned_rows(
21606        &self,
21607        include_end_if_at_line_start: bool,
21608        map: &DisplaySnapshot,
21609    ) -> Range<MultiBufferRow> {
21610        let start = self.start.to_point(&map.buffer_snapshot);
21611        let mut end = self.end.to_point(&map.buffer_snapshot);
21612        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
21613            end.row -= 1;
21614        }
21615
21616        let buffer_start = map.prev_line_boundary(start).0;
21617        let buffer_end = map.next_line_boundary(end).0;
21618        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
21619    }
21620}
21621
21622impl<T: InvalidationRegion> InvalidationStack<T> {
21623    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
21624    where
21625        S: Clone + ToOffset,
21626    {
21627        while let Some(region) = self.last() {
21628            let all_selections_inside_invalidation_ranges =
21629                if selections.len() == region.ranges().len() {
21630                    selections
21631                        .iter()
21632                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
21633                        .all(|(selection, invalidation_range)| {
21634                            let head = selection.head().to_offset(buffer);
21635                            invalidation_range.start <= head && invalidation_range.end >= head
21636                        })
21637                } else {
21638                    false
21639                };
21640
21641            if all_selections_inside_invalidation_ranges {
21642                break;
21643            } else {
21644                self.pop();
21645            }
21646        }
21647    }
21648}
21649
21650impl<T> Default for InvalidationStack<T> {
21651    fn default() -> Self {
21652        Self(Default::default())
21653    }
21654}
21655
21656impl<T> Deref for InvalidationStack<T> {
21657    type Target = Vec<T>;
21658
21659    fn deref(&self) -> &Self::Target {
21660        &self.0
21661    }
21662}
21663
21664impl<T> DerefMut for InvalidationStack<T> {
21665    fn deref_mut(&mut self) -> &mut Self::Target {
21666        &mut self.0
21667    }
21668}
21669
21670impl InvalidationRegion for SnippetState {
21671    fn ranges(&self) -> &[Range<Anchor>] {
21672        &self.ranges[self.active_index]
21673    }
21674}
21675
21676fn inline_completion_edit_text(
21677    current_snapshot: &BufferSnapshot,
21678    edits: &[(Range<Anchor>, String)],
21679    edit_preview: &EditPreview,
21680    include_deletions: bool,
21681    cx: &App,
21682) -> HighlightedText {
21683    let edits = edits
21684        .iter()
21685        .map(|(anchor, text)| {
21686            (
21687                anchor.start.text_anchor..anchor.end.text_anchor,
21688                text.clone(),
21689            )
21690        })
21691        .collect::<Vec<_>>();
21692
21693    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
21694}
21695
21696pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
21697    match severity {
21698        lsp::DiagnosticSeverity::ERROR => colors.error,
21699        lsp::DiagnosticSeverity::WARNING => colors.warning,
21700        lsp::DiagnosticSeverity::INFORMATION => colors.info,
21701        lsp::DiagnosticSeverity::HINT => colors.info,
21702        _ => colors.ignored,
21703    }
21704}
21705
21706pub fn styled_runs_for_code_label<'a>(
21707    label: &'a CodeLabel,
21708    syntax_theme: &'a theme::SyntaxTheme,
21709) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
21710    let fade_out = HighlightStyle {
21711        fade_out: Some(0.35),
21712        ..Default::default()
21713    };
21714
21715    let mut prev_end = label.filter_range.end;
21716    label
21717        .runs
21718        .iter()
21719        .enumerate()
21720        .flat_map(move |(ix, (range, highlight_id))| {
21721            let style = if let Some(style) = highlight_id.style(syntax_theme) {
21722                style
21723            } else {
21724                return Default::default();
21725            };
21726            let mut muted_style = style;
21727            muted_style.highlight(fade_out);
21728
21729            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
21730            if range.start >= label.filter_range.end {
21731                if range.start > prev_end {
21732                    runs.push((prev_end..range.start, fade_out));
21733                }
21734                runs.push((range.clone(), muted_style));
21735            } else if range.end <= label.filter_range.end {
21736                runs.push((range.clone(), style));
21737            } else {
21738                runs.push((range.start..label.filter_range.end, style));
21739                runs.push((label.filter_range.end..range.end, muted_style));
21740            }
21741            prev_end = cmp::max(prev_end, range.end);
21742
21743            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
21744                runs.push((prev_end..label.text.len(), fade_out));
21745            }
21746
21747            runs
21748        })
21749}
21750
21751pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
21752    let mut prev_index = 0;
21753    let mut prev_codepoint: Option<char> = None;
21754    text.char_indices()
21755        .chain([(text.len(), '\0')])
21756        .filter_map(move |(index, codepoint)| {
21757            let prev_codepoint = prev_codepoint.replace(codepoint)?;
21758            let is_boundary = index == text.len()
21759                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
21760                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
21761            if is_boundary {
21762                let chunk = &text[prev_index..index];
21763                prev_index = index;
21764                Some(chunk)
21765            } else {
21766                None
21767            }
21768        })
21769}
21770
21771pub trait RangeToAnchorExt: Sized {
21772    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
21773
21774    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
21775        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
21776        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
21777    }
21778}
21779
21780impl<T: ToOffset> RangeToAnchorExt for Range<T> {
21781    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
21782        let start_offset = self.start.to_offset(snapshot);
21783        let end_offset = self.end.to_offset(snapshot);
21784        if start_offset == end_offset {
21785            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
21786        } else {
21787            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
21788        }
21789    }
21790}
21791
21792pub trait RowExt {
21793    fn as_f32(&self) -> f32;
21794
21795    fn next_row(&self) -> Self;
21796
21797    fn previous_row(&self) -> Self;
21798
21799    fn minus(&self, other: Self) -> u32;
21800}
21801
21802impl RowExt for DisplayRow {
21803    fn as_f32(&self) -> f32 {
21804        self.0 as f32
21805    }
21806
21807    fn next_row(&self) -> Self {
21808        Self(self.0 + 1)
21809    }
21810
21811    fn previous_row(&self) -> Self {
21812        Self(self.0.saturating_sub(1))
21813    }
21814
21815    fn minus(&self, other: Self) -> u32 {
21816        self.0 - other.0
21817    }
21818}
21819
21820impl RowExt for MultiBufferRow {
21821    fn as_f32(&self) -> f32 {
21822        self.0 as f32
21823    }
21824
21825    fn next_row(&self) -> Self {
21826        Self(self.0 + 1)
21827    }
21828
21829    fn previous_row(&self) -> Self {
21830        Self(self.0.saturating_sub(1))
21831    }
21832
21833    fn minus(&self, other: Self) -> u32 {
21834        self.0 - other.0
21835    }
21836}
21837
21838trait RowRangeExt {
21839    type Row;
21840
21841    fn len(&self) -> usize;
21842
21843    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
21844}
21845
21846impl RowRangeExt for Range<MultiBufferRow> {
21847    type Row = MultiBufferRow;
21848
21849    fn len(&self) -> usize {
21850        (self.end.0 - self.start.0) as usize
21851    }
21852
21853    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
21854        (self.start.0..self.end.0).map(MultiBufferRow)
21855    }
21856}
21857
21858impl RowRangeExt for Range<DisplayRow> {
21859    type Row = DisplayRow;
21860
21861    fn len(&self) -> usize {
21862        (self.end.0 - self.start.0) as usize
21863    }
21864
21865    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
21866        (self.start.0..self.end.0).map(DisplayRow)
21867    }
21868}
21869
21870/// If select range has more than one line, we
21871/// just point the cursor to range.start.
21872fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
21873    if range.start.row == range.end.row {
21874        range
21875    } else {
21876        range.start..range.start
21877    }
21878}
21879pub struct KillRing(ClipboardItem);
21880impl Global for KillRing {}
21881
21882const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
21883
21884enum BreakpointPromptEditAction {
21885    Log,
21886    Condition,
21887    HitCondition,
21888}
21889
21890struct BreakpointPromptEditor {
21891    pub(crate) prompt: Entity<Editor>,
21892    editor: WeakEntity<Editor>,
21893    breakpoint_anchor: Anchor,
21894    breakpoint: Breakpoint,
21895    edit_action: BreakpointPromptEditAction,
21896    block_ids: HashSet<CustomBlockId>,
21897    editor_margins: Arc<Mutex<EditorMargins>>,
21898    _subscriptions: Vec<Subscription>,
21899}
21900
21901impl BreakpointPromptEditor {
21902    const MAX_LINES: u8 = 4;
21903
21904    fn new(
21905        editor: WeakEntity<Editor>,
21906        breakpoint_anchor: Anchor,
21907        breakpoint: Breakpoint,
21908        edit_action: BreakpointPromptEditAction,
21909        window: &mut Window,
21910        cx: &mut Context<Self>,
21911    ) -> Self {
21912        let base_text = match edit_action {
21913            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
21914            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
21915            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
21916        }
21917        .map(|msg| msg.to_string())
21918        .unwrap_or_default();
21919
21920        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
21921        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
21922
21923        let prompt = cx.new(|cx| {
21924            let mut prompt = Editor::new(
21925                EditorMode::AutoHeight {
21926                    max_lines: Self::MAX_LINES as usize,
21927                },
21928                buffer,
21929                None,
21930                window,
21931                cx,
21932            );
21933            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
21934            prompt.set_show_cursor_when_unfocused(false, cx);
21935            prompt.set_placeholder_text(
21936                match edit_action {
21937                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
21938                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
21939                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
21940                },
21941                cx,
21942            );
21943
21944            prompt
21945        });
21946
21947        Self {
21948            prompt,
21949            editor,
21950            breakpoint_anchor,
21951            breakpoint,
21952            edit_action,
21953            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
21954            block_ids: Default::default(),
21955            _subscriptions: vec![],
21956        }
21957    }
21958
21959    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
21960        self.block_ids.extend(block_ids)
21961    }
21962
21963    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
21964        if let Some(editor) = self.editor.upgrade() {
21965            let message = self
21966                .prompt
21967                .read(cx)
21968                .buffer
21969                .read(cx)
21970                .as_singleton()
21971                .expect("A multi buffer in breakpoint prompt isn't possible")
21972                .read(cx)
21973                .as_rope()
21974                .to_string();
21975
21976            editor.update(cx, |editor, cx| {
21977                editor.edit_breakpoint_at_anchor(
21978                    self.breakpoint_anchor,
21979                    self.breakpoint.clone(),
21980                    match self.edit_action {
21981                        BreakpointPromptEditAction::Log => {
21982                            BreakpointEditAction::EditLogMessage(message.into())
21983                        }
21984                        BreakpointPromptEditAction::Condition => {
21985                            BreakpointEditAction::EditCondition(message.into())
21986                        }
21987                        BreakpointPromptEditAction::HitCondition => {
21988                            BreakpointEditAction::EditHitCondition(message.into())
21989                        }
21990                    },
21991                    cx,
21992                );
21993
21994                editor.remove_blocks(self.block_ids.clone(), None, cx);
21995                cx.focus_self(window);
21996            });
21997        }
21998    }
21999
22000    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
22001        self.editor
22002            .update(cx, |editor, cx| {
22003                editor.remove_blocks(self.block_ids.clone(), None, cx);
22004                window.focus(&editor.focus_handle);
22005            })
22006            .log_err();
22007    }
22008
22009    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
22010        let settings = ThemeSettings::get_global(cx);
22011        let text_style = TextStyle {
22012            color: if self.prompt.read(cx).read_only(cx) {
22013                cx.theme().colors().text_disabled
22014            } else {
22015                cx.theme().colors().text
22016            },
22017            font_family: settings.buffer_font.family.clone(),
22018            font_fallbacks: settings.buffer_font.fallbacks.clone(),
22019            font_size: settings.buffer_font_size(cx).into(),
22020            font_weight: settings.buffer_font.weight,
22021            line_height: relative(settings.buffer_line_height.value()),
22022            ..Default::default()
22023        };
22024        EditorElement::new(
22025            &self.prompt,
22026            EditorStyle {
22027                background: cx.theme().colors().editor_background,
22028                local_player: cx.theme().players().local(),
22029                text: text_style,
22030                ..Default::default()
22031            },
22032        )
22033    }
22034}
22035
22036impl Render for BreakpointPromptEditor {
22037    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22038        let editor_margins = *self.editor_margins.lock();
22039        let gutter_dimensions = editor_margins.gutter;
22040        h_flex()
22041            .key_context("Editor")
22042            .bg(cx.theme().colors().editor_background)
22043            .border_y_1()
22044            .border_color(cx.theme().status().info_border)
22045            .size_full()
22046            .py(window.line_height() / 2.5)
22047            .on_action(cx.listener(Self::confirm))
22048            .on_action(cx.listener(Self::cancel))
22049            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
22050            .child(div().flex_1().child(self.render_prompt_editor(cx)))
22051    }
22052}
22053
22054impl Focusable for BreakpointPromptEditor {
22055    fn focus_handle(&self, cx: &App) -> FocusHandle {
22056        self.prompt.focus_handle(cx)
22057    }
22058}
22059
22060fn all_edits_insertions_or_deletions(
22061    edits: &Vec<(Range<Anchor>, String)>,
22062    snapshot: &MultiBufferSnapshot,
22063) -> bool {
22064    let mut all_insertions = true;
22065    let mut all_deletions = true;
22066
22067    for (range, new_text) in edits.iter() {
22068        let range_is_empty = range.to_offset(&snapshot).is_empty();
22069        let text_is_empty = new_text.is_empty();
22070
22071        if range_is_empty != text_is_empty {
22072            if range_is_empty {
22073                all_deletions = false;
22074            } else {
22075                all_insertions = false;
22076            }
22077        } else {
22078            return false;
22079        }
22080
22081        if !all_insertions && !all_deletions {
22082            return false;
22083        }
22084    }
22085    all_insertions || all_deletions
22086}
22087
22088struct MissingEditPredictionKeybindingTooltip;
22089
22090impl Render for MissingEditPredictionKeybindingTooltip {
22091    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22092        ui::tooltip_container(window, cx, |container, _, cx| {
22093            container
22094                .flex_shrink_0()
22095                .max_w_80()
22096                .min_h(rems_from_px(124.))
22097                .justify_between()
22098                .child(
22099                    v_flex()
22100                        .flex_1()
22101                        .text_ui_sm(cx)
22102                        .child(Label::new("Conflict with Accept Keybinding"))
22103                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
22104                )
22105                .child(
22106                    h_flex()
22107                        .pb_1()
22108                        .gap_1()
22109                        .items_end()
22110                        .w_full()
22111                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
22112                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
22113                        }))
22114                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
22115                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
22116                        })),
22117                )
22118        })
22119    }
22120}
22121
22122#[derive(Debug, Clone, Copy, PartialEq)]
22123pub struct LineHighlight {
22124    pub background: Background,
22125    pub border: Option<gpui::Hsla>,
22126    pub include_gutter: bool,
22127    pub type_id: Option<TypeId>,
22128}
22129
22130fn render_diff_hunk_controls(
22131    row: u32,
22132    status: &DiffHunkStatus,
22133    hunk_range: Range<Anchor>,
22134    is_created_file: bool,
22135    line_height: Pixels,
22136    editor: &Entity<Editor>,
22137    _window: &mut Window,
22138    cx: &mut App,
22139) -> AnyElement {
22140    h_flex()
22141        .h(line_height)
22142        .mr_1()
22143        .gap_1()
22144        .px_0p5()
22145        .pb_1()
22146        .border_x_1()
22147        .border_b_1()
22148        .border_color(cx.theme().colors().border_variant)
22149        .rounded_b_lg()
22150        .bg(cx.theme().colors().editor_background)
22151        .gap_1()
22152        .block_mouse_except_scroll()
22153        .shadow_md()
22154        .child(if status.has_secondary_hunk() {
22155            Button::new(("stage", row as u64), "Stage")
22156                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22157                .tooltip({
22158                    let focus_handle = editor.focus_handle(cx);
22159                    move |window, cx| {
22160                        Tooltip::for_action_in(
22161                            "Stage Hunk",
22162                            &::git::ToggleStaged,
22163                            &focus_handle,
22164                            window,
22165                            cx,
22166                        )
22167                    }
22168                })
22169                .on_click({
22170                    let editor = editor.clone();
22171                    move |_event, _window, cx| {
22172                        editor.update(cx, |editor, cx| {
22173                            editor.stage_or_unstage_diff_hunks(
22174                                true,
22175                                vec![hunk_range.start..hunk_range.start],
22176                                cx,
22177                            );
22178                        });
22179                    }
22180                })
22181        } else {
22182            Button::new(("unstage", row as u64), "Unstage")
22183                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
22184                .tooltip({
22185                    let focus_handle = editor.focus_handle(cx);
22186                    move |window, cx| {
22187                        Tooltip::for_action_in(
22188                            "Unstage Hunk",
22189                            &::git::ToggleStaged,
22190                            &focus_handle,
22191                            window,
22192                            cx,
22193                        )
22194                    }
22195                })
22196                .on_click({
22197                    let editor = editor.clone();
22198                    move |_event, _window, cx| {
22199                        editor.update(cx, |editor, cx| {
22200                            editor.stage_or_unstage_diff_hunks(
22201                                false,
22202                                vec![hunk_range.start..hunk_range.start],
22203                                cx,
22204                            );
22205                        });
22206                    }
22207                })
22208        })
22209        .child(
22210            Button::new(("restore", row as u64), "Restore")
22211                .tooltip({
22212                    let focus_handle = editor.focus_handle(cx);
22213                    move |window, cx| {
22214                        Tooltip::for_action_in(
22215                            "Restore Hunk",
22216                            &::git::Restore,
22217                            &focus_handle,
22218                            window,
22219                            cx,
22220                        )
22221                    }
22222                })
22223                .on_click({
22224                    let editor = editor.clone();
22225                    move |_event, window, cx| {
22226                        editor.update(cx, |editor, cx| {
22227                            let snapshot = editor.snapshot(window, cx);
22228                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
22229                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
22230                        });
22231                    }
22232                })
22233                .disabled(is_created_file),
22234        )
22235        .when(
22236            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
22237            |el| {
22238                el.child(
22239                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
22240                        .shape(IconButtonShape::Square)
22241                        .icon_size(IconSize::Small)
22242                        // .disabled(!has_multiple_hunks)
22243                        .tooltip({
22244                            let focus_handle = editor.focus_handle(cx);
22245                            move |window, cx| {
22246                                Tooltip::for_action_in(
22247                                    "Next Hunk",
22248                                    &GoToHunk,
22249                                    &focus_handle,
22250                                    window,
22251                                    cx,
22252                                )
22253                            }
22254                        })
22255                        .on_click({
22256                            let editor = editor.clone();
22257                            move |_event, window, cx| {
22258                                editor.update(cx, |editor, cx| {
22259                                    let snapshot = editor.snapshot(window, cx);
22260                                    let position =
22261                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
22262                                    editor.go_to_hunk_before_or_after_position(
22263                                        &snapshot,
22264                                        position,
22265                                        Direction::Next,
22266                                        window,
22267                                        cx,
22268                                    );
22269                                    editor.expand_selected_diff_hunks(cx);
22270                                });
22271                            }
22272                        }),
22273                )
22274                .child(
22275                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
22276                        .shape(IconButtonShape::Square)
22277                        .icon_size(IconSize::Small)
22278                        // .disabled(!has_multiple_hunks)
22279                        .tooltip({
22280                            let focus_handle = editor.focus_handle(cx);
22281                            move |window, cx| {
22282                                Tooltip::for_action_in(
22283                                    "Previous Hunk",
22284                                    &GoToPreviousHunk,
22285                                    &focus_handle,
22286                                    window,
22287                                    cx,
22288                                )
22289                            }
22290                        })
22291                        .on_click({
22292                            let editor = editor.clone();
22293                            move |_event, window, cx| {
22294                                editor.update(cx, |editor, cx| {
22295                                    let snapshot = editor.snapshot(window, cx);
22296                                    let point =
22297                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
22298                                    editor.go_to_hunk_before_or_after_position(
22299                                        &snapshot,
22300                                        point,
22301                                        Direction::Prev,
22302                                        window,
22303                                        cx,
22304                                    );
22305                                    editor.expand_selected_diff_hunks(cx);
22306                                });
22307                            }
22308                        }),
22309                )
22310            },
22311        )
22312        .into_any_element()
22313}