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_colors;
   33mod lsp_ext;
   34mod mouse_context_menu;
   35pub mod movement;
   36mod persistence;
   37mod proposed_changes_editor;
   38mod rust_analyzer_ext;
   39pub mod scroll;
   40mod selections_collection;
   41pub mod tasks;
   42
   43#[cfg(test)]
   44mod code_completion_tests;
   45#[cfg(test)]
   46mod edit_prediction_tests;
   47#[cfg(test)]
   48mod editor_tests;
   49mod signature_help;
   50#[cfg(any(test, feature = "test-support"))]
   51pub mod test;
   52
   53pub(crate) use actions::*;
   54pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   55pub use edit_prediction::Direction;
   56pub use editor_settings::{
   57    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   58    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap, ShowScrollbar,
   59};
   60pub use editor_settings_controls::*;
   61pub use element::{
   62    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   63};
   64pub use git::blame::BlameRenderer;
   65pub use hover_popover::hover_markdown_style;
   66pub use items::MAX_TAB_TITLE_LEN;
   67pub use lsp::CompletionContext;
   68pub use lsp_ext::lsp_tasks;
   69pub use multi_buffer::{
   70    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   71    RowInfo, ToOffset, ToPoint,
   72};
   73pub use proposed_changes_editor::{
   74    ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
   75};
   76pub use text::Bias;
   77
   78use ::git::{
   79    Restore,
   80    blame::{BlameEntry, ParsedCommitMessage},
   81};
   82use aho_corasick::AhoCorasick;
   83use anyhow::{Context as _, Result, anyhow};
   84use blink_manager::BlinkManager;
   85use buffer_diff::DiffHunkStatus;
   86use client::{Collaborator, ParticipantIndex};
   87use clock::{AGENT_REPLICA_ID, ReplicaId};
   88use code_context_menus::{
   89    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   90    CompletionsMenu, ContextMenuOrigin,
   91};
   92use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   93use convert_case::{Case, Casing};
   94use dap::TelemetrySpawnLocation;
   95use display_map::*;
   96use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   97use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   98use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   99use futures::{
  100    FutureExt, StreamExt as _,
  101    future::{self, Shared, join},
  102    stream::FuturesUnordered,
  103};
  104use fuzzy::{StringMatch, StringMatchCandidate};
  105use git::blame::{GitBlame, GlobalBlameRenderer};
  106use gpui::{
  107    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  108    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  109    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  110    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  111    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  112    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  113    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  114    div, point, prelude::*, pulsating_between, px, relative, size,
  115};
  116use highlight_matching_bracket::refresh_matching_bracket_highlights;
  117use hover_links::{HoverLink, HoveredLinkState, InlayHighlight, find_file};
  118use hover_popover::{HoverState, hide_hover};
  119use indent_guides::ActiveIndentGuidesState;
  120use inlay_hint_cache::{InlayHintCache, InlaySplice, InvalidationStrategy};
  121use itertools::{Either, Itertools};
  122use language::{
  123    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  124    BufferSnapshot, Capability, CharClassifier, CharKind, CodeLabel, CursorShape, DiagnosticEntry,
  125    DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind, IndentSize,
  126    Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal, TextObject,
  127    TransactionId, TreeSitterOptions, WordsQuery,
  128    language_settings::{
  129        self, InlayHintSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  130        all_language_settings, language_settings,
  131    },
  132    point_from_lsp, point_to_lsp, text_diff_with_options,
  133};
  134use linked_editing_ranges::refresh_linked_ranges;
  135use lsp::{
  136    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  137    LanguageServerId,
  138};
  139use lsp_colors::LspColorData;
  140use markdown::Markdown;
  141use mouse_context_menu::MouseContextMenu;
  142use movement::TextLayoutDetails;
  143use multi_buffer::{
  144    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  145    MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionIntent, CompletionResponse,
  151    CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, Location, LocationLink,
  152    PrepareRenameResponse, Project, ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
  153    debugger::breakpoint_store::Breakpoint,
  154    debugger::{
  155        breakpoint_store::{
  156            BreakpointEditAction, BreakpointSessionState, BreakpointState, BreakpointStore,
  157            BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::{GitStoreEvent, RepositoryEvent},
  162    lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
  163    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter},
  164    project_settings::{GitGutterSetting, ProjectSettings},
  165};
  166use rand::{seq::SliceRandom, thread_rng};
  167use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  168use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, ScrollbarAutoHide};
  169use selections_collection::{
  170    MutableSelectionsCollection, SelectionsCollection, resolve_selections,
  171};
  172use serde::{Deserialize, Serialize};
  173use settings::{Settings, SettingsLocation, SettingsStore, update_settings_file};
  174use smallvec::{SmallVec, smallvec};
  175use snippet::Snippet;
  176use std::{
  177    any::TypeId,
  178    borrow::Cow,
  179    cell::OnceCell,
  180    cell::RefCell,
  181    cmp::{self, Ordering, Reverse},
  182    iter::Peekable,
  183    mem,
  184    num::NonZeroU32,
  185    ops::Not,
  186    ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
  187    path::{Path, PathBuf},
  188    rc::Rc,
  189    sync::Arc,
  190    time::{Duration, Instant},
  191};
  192use sum_tree::TreeMap;
  193use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  194use text::{BufferId, FromAnchor, OffsetUtf16, Rope};
  195use theme::{
  196    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  197    observe_buffer_font_size_adjustment,
  198};
  199use ui::{
  200    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  201    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*,
  202};
  203use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  204use workspace::{
  205    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  206    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  207    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  208    item::{ItemHandle, PreviewTabsSettings, SaveOptions},
  209    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  210    searchable::SearchEvent,
  211};
  212
  213use crate::{
  214    code_context_menus::CompletionsMenuSource,
  215    editor_settings::MultiCursorModifier,
  216    hover_links::{find_url, find_url_from_range},
  217    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  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 MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  239
  240pub type RenderDiffHunkControlsFn = Arc<
  241    dyn Fn(
  242        u32,
  243        &DiffHunkStatus,
  244        Range<Anchor>,
  245        bool,
  246        Pixels,
  247        &Entity<Editor>,
  248        &mut Window,
  249        &mut App,
  250    ) -> AnyElement,
  251>;
  252
  253enum ReportEditorEvent {
  254    Saved { auto_saved: bool },
  255    EditorOpened,
  256    ZetaTosClicked,
  257    Closed,
  258}
  259
  260impl ReportEditorEvent {
  261    pub fn event_type(&self) -> &'static str {
  262        match self {
  263            Self::Saved { .. } => "Editor Saved",
  264            Self::EditorOpened => "Editor Opened",
  265            Self::ZetaTosClicked => "Edit Prediction Provider ToS Clicked",
  266            Self::Closed => "Editor Closed",
  267        }
  268    }
  269}
  270
  271struct InlineValueCache {
  272    enabled: bool,
  273    inlays: Vec<InlayId>,
  274    refresh_task: Task<Option<()>>,
  275}
  276
  277impl InlineValueCache {
  278    fn new(enabled: bool) -> Self {
  279        Self {
  280            enabled,
  281            inlays: Vec::new(),
  282            refresh_task: Task::ready(None),
  283        }
  284    }
  285}
  286
  287#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  288pub enum InlayId {
  289    EditPrediction(usize),
  290    DebuggerValue(usize),
  291    // LSP
  292    Hint(usize),
  293    Color(usize),
  294}
  295
  296impl InlayId {
  297    fn id(&self) -> usize {
  298        match self {
  299            Self::EditPrediction(id) => *id,
  300            Self::DebuggerValue(id) => *id,
  301            Self::Hint(id) => *id,
  302            Self::Color(id) => *id,
  303        }
  304    }
  305}
  306
  307pub enum ActiveDebugLine {}
  308pub enum DebugStackFrameLine {}
  309enum DocumentHighlightRead {}
  310enum DocumentHighlightWrite {}
  311enum InputComposition {}
  312pub enum PendingInput {}
  313enum SelectedTextHighlight {}
  314
  315pub enum ConflictsOuter {}
  316pub enum ConflictsOurs {}
  317pub enum ConflictsTheirs {}
  318pub enum ConflictsOursMarker {}
  319pub enum ConflictsTheirsMarker {}
  320
  321#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  322pub enum Navigated {
  323    Yes,
  324    No,
  325}
  326
  327impl Navigated {
  328    pub fn from_bool(yes: bool) -> Navigated {
  329        if yes { Navigated::Yes } else { Navigated::No }
  330    }
  331}
  332
  333#[derive(Debug, Clone, PartialEq, Eq)]
  334enum DisplayDiffHunk {
  335    Folded {
  336        display_row: DisplayRow,
  337    },
  338    Unfolded {
  339        is_created_file: bool,
  340        diff_base_byte_range: Range<usize>,
  341        display_row_range: Range<DisplayRow>,
  342        multi_buffer_range: Range<Anchor>,
  343        status: DiffHunkStatus,
  344    },
  345}
  346
  347pub enum HideMouseCursorOrigin {
  348    TypingAction,
  349    MovementAction,
  350}
  351
  352pub fn init_settings(cx: &mut App) {
  353    EditorSettings::register(cx);
  354}
  355
  356pub fn init(cx: &mut App) {
  357    init_settings(cx);
  358
  359    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  360
  361    workspace::register_project_item::<Editor>(cx);
  362    workspace::FollowableViewRegistry::register::<Editor>(cx);
  363    workspace::register_serializable_item::<Editor>(cx);
  364
  365    cx.observe_new(
  366        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  367            workspace.register_action(Editor::new_file);
  368            workspace.register_action(Editor::new_file_vertical);
  369            workspace.register_action(Editor::new_file_horizontal);
  370            workspace.register_action(Editor::cancel_language_server_work);
  371            workspace.register_action(Editor::toggle_focus);
  372        },
  373    )
  374    .detach();
  375
  376    cx.on_action(move |_: &workspace::NewFile, 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                    Editor::new_file(workspace, &Default::default(), window, cx)
  385                },
  386            )
  387            .detach();
  388        }
  389    });
  390    cx.on_action(move |_: &workspace::NewWindow, cx| {
  391        let app_state = workspace::AppState::global(cx);
  392        if let Some(app_state) = app_state.upgrade() {
  393            workspace::open_new(
  394                Default::default(),
  395                app_state,
  396                cx,
  397                |workspace, window, cx| {
  398                    cx.activate(true);
  399                    Editor::new_file(workspace, &Default::default(), window, cx)
  400                },
  401            )
  402            .detach();
  403        }
  404    });
  405}
  406
  407pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  408    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  409}
  410
  411pub trait DiagnosticRenderer {
  412    fn render_group(
  413        &self,
  414        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  415        buffer_id: BufferId,
  416        snapshot: EditorSnapshot,
  417        editor: WeakEntity<Editor>,
  418        cx: &mut App,
  419    ) -> Vec<BlockProperties<Anchor>>;
  420
  421    fn render_hover(
  422        &self,
  423        diagnostic_group: Vec<DiagnosticEntry<Point>>,
  424        range: Range<Point>,
  425        buffer_id: BufferId,
  426        cx: &mut App,
  427    ) -> Option<Entity<markdown::Markdown>>;
  428
  429    fn open_link(
  430        &self,
  431        editor: &mut Editor,
  432        link: SharedString,
  433        window: &mut Window,
  434        cx: &mut Context<Editor>,
  435    );
  436}
  437
  438pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  439
  440impl GlobalDiagnosticRenderer {
  441    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  442        cx.try_global::<Self>().map(|g| g.0.clone())
  443    }
  444}
  445
  446impl gpui::Global for GlobalDiagnosticRenderer {}
  447pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  448    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  449}
  450
  451pub struct SearchWithinRange;
  452
  453trait InvalidationRegion {
  454    fn ranges(&self) -> &[Range<Anchor>];
  455}
  456
  457#[derive(Clone, Debug, PartialEq)]
  458pub enum SelectPhase {
  459    Begin {
  460        position: DisplayPoint,
  461        add: bool,
  462        click_count: usize,
  463    },
  464    BeginColumnar {
  465        position: DisplayPoint,
  466        reset: bool,
  467        mode: ColumnarMode,
  468        goal_column: u32,
  469    },
  470    Extend {
  471        position: DisplayPoint,
  472        click_count: usize,
  473    },
  474    Update {
  475        position: DisplayPoint,
  476        goal_column: u32,
  477        scroll_delta: gpui::Point<f32>,
  478    },
  479    End,
  480}
  481
  482#[derive(Clone, Debug, PartialEq)]
  483pub enum ColumnarMode {
  484    FromMouse,
  485    FromSelection,
  486}
  487
  488#[derive(Clone, Debug)]
  489pub enum SelectMode {
  490    Character,
  491    Word(Range<Anchor>),
  492    Line(Range<Anchor>),
  493    All,
  494}
  495
  496#[derive(Clone, PartialEq, Eq, Debug)]
  497pub enum EditorMode {
  498    SingleLine,
  499    AutoHeight {
  500        min_lines: usize,
  501        max_lines: Option<usize>,
  502    },
  503    Full {
  504        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  505        scale_ui_elements_with_buffer_font_size: bool,
  506        /// When set to `true`, the editor will render a background for the active line.
  507        show_active_line_background: bool,
  508        /// When set to `true`, the editor's height will be determined by its content.
  509        sized_by_content: bool,
  510    },
  511    Minimap {
  512        parent: WeakEntity<Editor>,
  513    },
  514}
  515
  516impl EditorMode {
  517    pub fn full() -> Self {
  518        Self::Full {
  519            scale_ui_elements_with_buffer_font_size: true,
  520            show_active_line_background: true,
  521            sized_by_content: false,
  522        }
  523    }
  524
  525    #[inline]
  526    pub fn is_full(&self) -> bool {
  527        matches!(self, Self::Full { .. })
  528    }
  529
  530    #[inline]
  531    pub fn is_single_line(&self) -> bool {
  532        matches!(self, Self::SingleLine { .. })
  533    }
  534
  535    #[inline]
  536    fn is_minimap(&self) -> bool {
  537        matches!(self, Self::Minimap { .. })
  538    }
  539}
  540
  541#[derive(Copy, Clone, Debug)]
  542pub enum SoftWrap {
  543    /// Prefer not to wrap at all.
  544    ///
  545    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  546    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  547    GitDiff,
  548    /// Prefer a single line generally, unless an overly long line is encountered.
  549    None,
  550    /// Soft wrap lines that exceed the editor width.
  551    EditorWidth,
  552    /// Soft wrap lines at the preferred line length.
  553    Column(u32),
  554    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  555    Bounded(u32),
  556}
  557
  558#[derive(Clone)]
  559pub struct EditorStyle {
  560    pub background: Hsla,
  561    pub border: Hsla,
  562    pub local_player: PlayerColor,
  563    pub text: TextStyle,
  564    pub scrollbar_width: Pixels,
  565    pub syntax: Arc<SyntaxTheme>,
  566    pub status: StatusColors,
  567    pub inlay_hints_style: HighlightStyle,
  568    pub edit_prediction_styles: EditPredictionStyles,
  569    pub unnecessary_code_fade: f32,
  570    pub show_underlines: bool,
  571}
  572
  573impl Default for EditorStyle {
  574    fn default() -> Self {
  575        Self {
  576            background: Hsla::default(),
  577            border: Hsla::default(),
  578            local_player: PlayerColor::default(),
  579            text: TextStyle::default(),
  580            scrollbar_width: Pixels::default(),
  581            syntax: Default::default(),
  582            // HACK: Status colors don't have a real default.
  583            // We should look into removing the status colors from the editor
  584            // style and retrieve them directly from the theme.
  585            status: StatusColors::dark(),
  586            inlay_hints_style: HighlightStyle::default(),
  587            edit_prediction_styles: EditPredictionStyles {
  588                insertion: HighlightStyle::default(),
  589                whitespace: HighlightStyle::default(),
  590            },
  591            unnecessary_code_fade: Default::default(),
  592            show_underlines: true,
  593        }
  594    }
  595}
  596
  597pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  598    let show_background = language_settings::language_settings(None, None, cx)
  599        .inlay_hints
  600        .show_background;
  601
  602    HighlightStyle {
  603        color: Some(cx.theme().status().hint),
  604        background_color: show_background.then(|| cx.theme().status().hint_background),
  605        ..HighlightStyle::default()
  606    }
  607}
  608
  609pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  610    EditPredictionStyles {
  611        insertion: HighlightStyle {
  612            color: Some(cx.theme().status().predictive),
  613            ..HighlightStyle::default()
  614        },
  615        whitespace: HighlightStyle {
  616            background_color: Some(cx.theme().status().created_background),
  617            ..HighlightStyle::default()
  618        },
  619    }
  620}
  621
  622type CompletionId = usize;
  623
  624pub(crate) enum EditDisplayMode {
  625    TabAccept,
  626    DiffPopover,
  627    Inline,
  628}
  629
  630enum EditPrediction {
  631    Edit {
  632        edits: Vec<(Range<Anchor>, String)>,
  633        edit_preview: Option<EditPreview>,
  634        display_mode: EditDisplayMode,
  635        snapshot: BufferSnapshot,
  636    },
  637    Move {
  638        target: Anchor,
  639        snapshot: BufferSnapshot,
  640    },
  641}
  642
  643struct EditPredictionState {
  644    inlay_ids: Vec<InlayId>,
  645    completion: EditPrediction,
  646    completion_id: Option<SharedString>,
  647    invalidation_range: Range<Anchor>,
  648}
  649
  650enum EditPredictionSettings {
  651    Disabled,
  652    Enabled {
  653        show_in_menu: bool,
  654        preview_requires_modifier: bool,
  655    },
  656}
  657
  658enum EditPredictionHighlight {}
  659
  660#[derive(Debug, Clone)]
  661struct InlineDiagnostic {
  662    message: SharedString,
  663    group_id: usize,
  664    is_primary: bool,
  665    start: Point,
  666    severity: lsp::DiagnosticSeverity,
  667}
  668
  669pub enum MenuEditPredictionsPolicy {
  670    Never,
  671    ByProvider,
  672}
  673
  674pub enum EditPredictionPreview {
  675    /// Modifier is not pressed
  676    Inactive { released_too_fast: bool },
  677    /// Modifier pressed
  678    Active {
  679        since: Instant,
  680        previous_scroll_position: Option<ScrollAnchor>,
  681    },
  682}
  683
  684impl EditPredictionPreview {
  685    pub fn released_too_fast(&self) -> bool {
  686        match self {
  687            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  688            EditPredictionPreview::Active { .. } => false,
  689        }
  690    }
  691
  692    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  693        if let EditPredictionPreview::Active {
  694            previous_scroll_position,
  695            ..
  696        } = self
  697        {
  698            *previous_scroll_position = scroll_position;
  699        }
  700    }
  701}
  702
  703pub struct ContextMenuOptions {
  704    pub min_entries_visible: usize,
  705    pub max_entries_visible: usize,
  706    pub placement: Option<ContextMenuPlacement>,
  707}
  708
  709#[derive(Debug, Clone, PartialEq, Eq)]
  710pub enum ContextMenuPlacement {
  711    Above,
  712    Below,
  713}
  714
  715#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  716struct EditorActionId(usize);
  717
  718impl EditorActionId {
  719    pub fn post_inc(&mut self) -> Self {
  720        let answer = self.0;
  721
  722        *self = Self(answer + 1);
  723
  724        Self(answer)
  725    }
  726}
  727
  728// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  729// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  730
  731type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  732type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  733
  734#[derive(Default)]
  735struct ScrollbarMarkerState {
  736    scrollbar_size: Size<Pixels>,
  737    dirty: bool,
  738    markers: Arc<[PaintQuad]>,
  739    pending_refresh: Option<Task<Result<()>>>,
  740}
  741
  742impl ScrollbarMarkerState {
  743    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  744        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  745    }
  746}
  747
  748#[derive(Clone, Copy, PartialEq, Eq)]
  749pub enum MinimapVisibility {
  750    Disabled,
  751    Enabled {
  752        /// The configuration currently present in the users settings.
  753        setting_configuration: bool,
  754        /// Whether to override the currently set visibility from the users setting.
  755        toggle_override: bool,
  756    },
  757}
  758
  759impl MinimapVisibility {
  760    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  761        if mode.is_full() {
  762            Self::Enabled {
  763                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  764                toggle_override: false,
  765            }
  766        } else {
  767            Self::Disabled
  768        }
  769    }
  770
  771    fn hidden(&self) -> Self {
  772        match *self {
  773            Self::Enabled {
  774                setting_configuration,
  775                ..
  776            } => Self::Enabled {
  777                setting_configuration,
  778                toggle_override: setting_configuration,
  779            },
  780            Self::Disabled => Self::Disabled,
  781        }
  782    }
  783
  784    fn disabled(&self) -> bool {
  785        match *self {
  786            Self::Disabled => true,
  787            _ => false,
  788        }
  789    }
  790
  791    fn settings_visibility(&self) -> bool {
  792        match *self {
  793            Self::Enabled {
  794                setting_configuration,
  795                ..
  796            } => setting_configuration,
  797            _ => false,
  798        }
  799    }
  800
  801    fn visible(&self) -> bool {
  802        match *self {
  803            Self::Enabled {
  804                setting_configuration,
  805                toggle_override,
  806            } => setting_configuration ^ toggle_override,
  807            _ => false,
  808        }
  809    }
  810
  811    fn toggle_visibility(&self) -> Self {
  812        match *self {
  813            Self::Enabled {
  814                toggle_override,
  815                setting_configuration,
  816            } => Self::Enabled {
  817                setting_configuration,
  818                toggle_override: !toggle_override,
  819            },
  820            Self::Disabled => Self::Disabled,
  821        }
  822    }
  823}
  824
  825#[derive(Clone, Debug)]
  826struct RunnableTasks {
  827    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  828    offset: multi_buffer::Anchor,
  829    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  830    column: u32,
  831    // Values of all named captures, including those starting with '_'
  832    extra_variables: HashMap<String, String>,
  833    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  834    context_range: Range<BufferOffset>,
  835}
  836
  837impl RunnableTasks {
  838    fn resolve<'a>(
  839        &'a self,
  840        cx: &'a task::TaskContext,
  841    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  842        self.templates.iter().filter_map(|(kind, template)| {
  843            template
  844                .resolve_task(&kind.to_id_base(), cx)
  845                .map(|task| (kind.clone(), task))
  846        })
  847    }
  848}
  849
  850#[derive(Clone)]
  851pub struct ResolvedTasks {
  852    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  853    position: Anchor,
  854}
  855
  856#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  857struct BufferOffset(usize);
  858
  859// Addons allow storing per-editor state in other crates (e.g. Vim)
  860pub trait Addon: 'static {
  861    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  862
  863    fn render_buffer_header_controls(
  864        &self,
  865        _: &ExcerptInfo,
  866        _: &Window,
  867        _: &App,
  868    ) -> Option<AnyElement> {
  869        None
  870    }
  871
  872    fn to_any(&self) -> &dyn std::any::Any;
  873
  874    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  875        None
  876    }
  877}
  878
  879struct ChangeLocation {
  880    current: Option<Vec<Anchor>>,
  881    original: Vec<Anchor>,
  882}
  883impl ChangeLocation {
  884    fn locations(&self) -> &[Anchor] {
  885        self.current.as_ref().unwrap_or(&self.original)
  886    }
  887}
  888
  889/// A set of caret positions, registered when the editor was edited.
  890pub struct ChangeList {
  891    changes: Vec<ChangeLocation>,
  892    /// Currently "selected" change.
  893    position: Option<usize>,
  894}
  895
  896impl ChangeList {
  897    pub fn new() -> Self {
  898        Self {
  899            changes: Vec::new(),
  900            position: None,
  901        }
  902    }
  903
  904    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  905    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  906    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  907        if self.changes.is_empty() {
  908            return None;
  909        }
  910
  911        let prev = self.position.unwrap_or(self.changes.len());
  912        let next = if direction == Direction::Prev {
  913            prev.saturating_sub(count)
  914        } else {
  915            (prev + count).min(self.changes.len() - 1)
  916        };
  917        self.position = Some(next);
  918        self.changes.get(next).map(|change| change.locations())
  919    }
  920
  921    /// Adds a new change to the list, resetting the change list position.
  922    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  923        self.position.take();
  924        if let Some(last) = self.changes.last_mut()
  925            && group
  926        {
  927            last.current = Some(new_positions)
  928        } else {
  929            self.changes.push(ChangeLocation {
  930                original: new_positions,
  931                current: None,
  932            });
  933        }
  934    }
  935
  936    pub fn last(&self) -> Option<&[Anchor]> {
  937        self.changes.last().map(|change| change.locations())
  938    }
  939
  940    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  941        self.changes.last().map(|change| change.original.as_slice())
  942    }
  943
  944    pub fn invert_last_group(&mut self) {
  945        if let Some(last) = self.changes.last_mut() {
  946            if let Some(current) = last.current.as_mut() {
  947                mem::swap(&mut last.original, current);
  948            }
  949        }
  950    }
  951}
  952
  953#[derive(Clone)]
  954struct InlineBlamePopoverState {
  955    scroll_handle: ScrollHandle,
  956    commit_message: Option<ParsedCommitMessage>,
  957    markdown: Entity<Markdown>,
  958}
  959
  960struct InlineBlamePopover {
  961    position: gpui::Point<Pixels>,
  962    hide_task: Option<Task<()>>,
  963    popover_bounds: Option<Bounds<Pixels>>,
  964    popover_state: InlineBlamePopoverState,
  965    keyboard_grace: bool,
  966}
  967
  968enum SelectionDragState {
  969    /// State when no drag related activity is detected.
  970    None,
  971    /// State when the mouse is down on a selection that is about to be dragged.
  972    ReadyToDrag {
  973        selection: Selection<Anchor>,
  974        click_position: gpui::Point<Pixels>,
  975        mouse_down_time: Instant,
  976    },
  977    /// State when the mouse is dragging the selection in the editor.
  978    Dragging {
  979        selection: Selection<Anchor>,
  980        drop_cursor: Selection<Anchor>,
  981        hide_drop_cursor: bool,
  982    },
  983}
  984
  985enum ColumnarSelectionState {
  986    FromMouse {
  987        selection_tail: Anchor,
  988        display_point: Option<DisplayPoint>,
  989    },
  990    FromSelection {
  991        selection_tail: Anchor,
  992    },
  993}
  994
  995/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  996/// a breakpoint on them.
  997#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  998struct PhantomBreakpointIndicator {
  999    display_row: DisplayRow,
 1000    /// There's a small debounce between hovering over the line and showing the indicator.
 1001    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1002    is_active: bool,
 1003    collides_with_existing_breakpoint: bool,
 1004}
 1005
 1006/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1007///
 1008/// See the [module level documentation](self) for more information.
 1009pub struct Editor {
 1010    focus_handle: FocusHandle,
 1011    last_focused_descendant: Option<WeakFocusHandle>,
 1012    /// The text buffer being edited
 1013    buffer: Entity<MultiBuffer>,
 1014    /// Map of how text in the buffer should be displayed.
 1015    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1016    pub display_map: Entity<DisplayMap>,
 1017    pub selections: SelectionsCollection,
 1018    pub scroll_manager: ScrollManager,
 1019    /// When inline assist editors are linked, they all render cursors because
 1020    /// typing enters text into each of them, even the ones that aren't focused.
 1021    pub(crate) show_cursor_when_unfocused: bool,
 1022    columnar_selection_state: Option<ColumnarSelectionState>,
 1023    add_selections_state: Option<AddSelectionsState>,
 1024    select_next_state: Option<SelectNextState>,
 1025    select_prev_state: Option<SelectNextState>,
 1026    selection_history: SelectionHistory,
 1027    defer_selection_effects: bool,
 1028    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1029    autoclose_regions: Vec<AutocloseRegion>,
 1030    snippet_stack: InvalidationStack<SnippetState>,
 1031    select_syntax_node_history: SelectSyntaxNodeHistory,
 1032    ime_transaction: Option<TransactionId>,
 1033    pub diagnostics_max_severity: DiagnosticSeverity,
 1034    active_diagnostics: ActiveDiagnostic,
 1035    show_inline_diagnostics: bool,
 1036    inline_diagnostics_update: Task<()>,
 1037    inline_diagnostics_enabled: bool,
 1038    diagnostics_enabled: bool,
 1039    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1040    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1041    hard_wrap: Option<usize>,
 1042
 1043    // TODO: make this a access method
 1044    pub project: Option<Entity<Project>>,
 1045    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1046    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1047    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1048    blink_manager: Entity<BlinkManager>,
 1049    show_cursor_names: bool,
 1050    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1051    pub show_local_selections: bool,
 1052    mode: EditorMode,
 1053    show_breadcrumbs: bool,
 1054    show_gutter: bool,
 1055    show_scrollbars: ScrollbarAxes,
 1056    minimap_visibility: MinimapVisibility,
 1057    offset_content: bool,
 1058    disable_expand_excerpt_buttons: bool,
 1059    show_line_numbers: Option<bool>,
 1060    use_relative_line_numbers: Option<bool>,
 1061    show_git_diff_gutter: Option<bool>,
 1062    show_code_actions: Option<bool>,
 1063    show_runnables: Option<bool>,
 1064    show_breakpoints: Option<bool>,
 1065    show_wrap_guides: Option<bool>,
 1066    show_indent_guides: Option<bool>,
 1067    placeholder_text: Option<Arc<str>>,
 1068    highlight_order: usize,
 1069    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1070    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1071    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1072    scrollbar_marker_state: ScrollbarMarkerState,
 1073    active_indent_guides_state: ActiveIndentGuidesState,
 1074    nav_history: Option<ItemNavHistory>,
 1075    context_menu: RefCell<Option<CodeContextMenu>>,
 1076    context_menu_options: Option<ContextMenuOptions>,
 1077    mouse_context_menu: Option<MouseContextMenu>,
 1078    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1079    inline_blame_popover: Option<InlineBlamePopover>,
 1080    inline_blame_popover_show_task: Option<Task<()>>,
 1081    signature_help_state: SignatureHelpState,
 1082    auto_signature_help: Option<bool>,
 1083    find_all_references_task_sources: Vec<Anchor>,
 1084    next_completion_id: CompletionId,
 1085    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1086    code_actions_task: Option<Task<Result<()>>>,
 1087    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1088    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1089    document_highlights_task: Option<Task<()>>,
 1090    linked_editing_range_task: Option<Task<Option<()>>>,
 1091    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1092    pending_rename: Option<RenameState>,
 1093    searchable: bool,
 1094    cursor_shape: CursorShape,
 1095    current_line_highlight: Option<CurrentLineHighlight>,
 1096    collapse_matches: bool,
 1097    autoindent_mode: Option<AutoindentMode>,
 1098    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1099    input_enabled: bool,
 1100    use_modal_editing: bool,
 1101    read_only: bool,
 1102    leader_id: Option<CollaboratorId>,
 1103    remote_id: Option<ViewId>,
 1104    pub hover_state: HoverState,
 1105    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1106    gutter_hovered: bool,
 1107    hovered_link_state: Option<HoveredLinkState>,
 1108    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1109    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1110    active_edit_prediction: Option<EditPredictionState>,
 1111    /// Used to prevent flickering as the user types while the menu is open
 1112    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1113    edit_prediction_settings: EditPredictionSettings,
 1114    edit_predictions_hidden_for_vim_mode: bool,
 1115    show_edit_predictions_override: Option<bool>,
 1116    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1117    edit_prediction_preview: EditPredictionPreview,
 1118    edit_prediction_indent_conflict: bool,
 1119    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1120    inlay_hint_cache: InlayHintCache,
 1121    next_inlay_id: usize,
 1122    _subscriptions: Vec<Subscription>,
 1123    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1124    gutter_dimensions: GutterDimensions,
 1125    style: Option<EditorStyle>,
 1126    text_style_refinement: Option<TextStyleRefinement>,
 1127    next_editor_action_id: EditorActionId,
 1128    editor_actions: Rc<
 1129        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1130    >,
 1131    use_autoclose: bool,
 1132    use_auto_surround: bool,
 1133    auto_replace_emoji_shortcode: bool,
 1134    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1135    show_git_blame_gutter: bool,
 1136    show_git_blame_inline: bool,
 1137    show_git_blame_inline_delay_task: Option<Task<()>>,
 1138    git_blame_inline_enabled: bool,
 1139    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1140    serialize_dirty_buffers: bool,
 1141    show_selection_menu: Option<bool>,
 1142    blame: Option<Entity<GitBlame>>,
 1143    blame_subscription: Option<Subscription>,
 1144    custom_context_menu: Option<
 1145        Box<
 1146            dyn 'static
 1147                + Fn(
 1148                    &mut Self,
 1149                    DisplayPoint,
 1150                    &mut Window,
 1151                    &mut Context<Self>,
 1152                ) -> Option<Entity<ui::ContextMenu>>,
 1153        >,
 1154    >,
 1155    last_bounds: Option<Bounds<Pixels>>,
 1156    last_position_map: Option<Rc<PositionMap>>,
 1157    expect_bounds_change: Option<Bounds<Pixels>>,
 1158    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1159    tasks_update_task: Option<Task<()>>,
 1160    breakpoint_store: Option<Entity<BreakpointStore>>,
 1161    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1162    hovered_diff_hunk_row: Option<DisplayRow>,
 1163    pull_diagnostics_task: Task<()>,
 1164    in_project_search: bool,
 1165    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1166    breadcrumb_header: Option<String>,
 1167    focused_block: Option<FocusedBlock>,
 1168    next_scroll_position: NextScrollCursorCenterTopBottom,
 1169    addons: HashMap<TypeId, Box<dyn Addon>>,
 1170    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1171    load_diff_task: Option<Shared<Task<()>>>,
 1172    /// Whether we are temporarily displaying a diff other than git's
 1173    temporary_diff_override: bool,
 1174    selection_mark_mode: bool,
 1175    toggle_fold_multiple_buffers: Task<()>,
 1176    _scroll_cursor_center_top_bottom_task: Task<()>,
 1177    serialize_selections: Task<()>,
 1178    serialize_folds: Task<()>,
 1179    mouse_cursor_hidden: bool,
 1180    minimap: Option<Entity<Self>>,
 1181    hide_mouse_mode: HideMouseMode,
 1182    pub change_list: ChangeList,
 1183    inline_value_cache: InlineValueCache,
 1184    selection_drag_state: SelectionDragState,
 1185    next_color_inlay_id: usize,
 1186    colors: Option<LspColorData>,
 1187    folding_newlines: Task<()>,
 1188}
 1189
 1190#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1191enum NextScrollCursorCenterTopBottom {
 1192    #[default]
 1193    Center,
 1194    Top,
 1195    Bottom,
 1196}
 1197
 1198impl NextScrollCursorCenterTopBottom {
 1199    fn next(&self) -> Self {
 1200        match self {
 1201            Self::Center => Self::Top,
 1202            Self::Top => Self::Bottom,
 1203            Self::Bottom => Self::Center,
 1204        }
 1205    }
 1206}
 1207
 1208#[derive(Clone)]
 1209pub struct EditorSnapshot {
 1210    pub mode: EditorMode,
 1211    show_gutter: bool,
 1212    show_line_numbers: Option<bool>,
 1213    show_git_diff_gutter: Option<bool>,
 1214    show_code_actions: Option<bool>,
 1215    show_runnables: Option<bool>,
 1216    show_breakpoints: Option<bool>,
 1217    git_blame_gutter_max_author_length: Option<usize>,
 1218    pub display_snapshot: DisplaySnapshot,
 1219    pub placeholder_text: Option<Arc<str>>,
 1220    is_focused: bool,
 1221    scroll_anchor: ScrollAnchor,
 1222    ongoing_scroll: OngoingScroll,
 1223    current_line_highlight: CurrentLineHighlight,
 1224    gutter_hovered: bool,
 1225}
 1226
 1227#[derive(Default, Debug, Clone, Copy)]
 1228pub struct GutterDimensions {
 1229    pub left_padding: Pixels,
 1230    pub right_padding: Pixels,
 1231    pub width: Pixels,
 1232    pub margin: Pixels,
 1233    pub git_blame_entries_width: Option<Pixels>,
 1234}
 1235
 1236impl GutterDimensions {
 1237    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1238        Self {
 1239            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1240            ..Default::default()
 1241        }
 1242    }
 1243
 1244    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1245        -cx.text_system().descent(font_id, font_size)
 1246    }
 1247    /// The full width of the space taken up by the gutter.
 1248    pub fn full_width(&self) -> Pixels {
 1249        self.margin + self.width
 1250    }
 1251
 1252    /// The width of the space reserved for the fold indicators,
 1253    /// use alongside 'justify_end' and `gutter_width` to
 1254    /// right align content with the line numbers
 1255    pub fn fold_area_width(&self) -> Pixels {
 1256        self.margin + self.right_padding
 1257    }
 1258}
 1259
 1260struct CharacterDimensions {
 1261    em_width: Pixels,
 1262    em_advance: Pixels,
 1263    line_height: Pixels,
 1264}
 1265
 1266#[derive(Debug)]
 1267pub struct RemoteSelection {
 1268    pub replica_id: ReplicaId,
 1269    pub selection: Selection<Anchor>,
 1270    pub cursor_shape: CursorShape,
 1271    pub collaborator_id: CollaboratorId,
 1272    pub line_mode: bool,
 1273    pub user_name: Option<SharedString>,
 1274    pub color: PlayerColor,
 1275}
 1276
 1277#[derive(Clone, Debug)]
 1278struct SelectionHistoryEntry {
 1279    selections: Arc<[Selection<Anchor>]>,
 1280    select_next_state: Option<SelectNextState>,
 1281    select_prev_state: Option<SelectNextState>,
 1282    add_selections_state: Option<AddSelectionsState>,
 1283}
 1284
 1285#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1286enum SelectionHistoryMode {
 1287    Normal,
 1288    Undoing,
 1289    Redoing,
 1290    Skipping,
 1291}
 1292
 1293#[derive(Clone, PartialEq, Eq, Hash)]
 1294struct HoveredCursor {
 1295    replica_id: u16,
 1296    selection_id: usize,
 1297}
 1298
 1299impl Default for SelectionHistoryMode {
 1300    fn default() -> Self {
 1301        Self::Normal
 1302    }
 1303}
 1304
 1305#[derive(Debug)]
 1306/// SelectionEffects controls the side-effects of updating the selection.
 1307///
 1308/// The default behaviour does "what you mostly want":
 1309/// - it pushes to the nav history if the cursor moved by >10 lines
 1310/// - it re-triggers completion requests
 1311/// - it scrolls to fit
 1312///
 1313/// You might want to modify these behaviours. For example when doing a "jump"
 1314/// like go to definition, we always want to add to nav history; but when scrolling
 1315/// in vim mode we never do.
 1316///
 1317/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1318/// move.
 1319#[derive(Clone)]
 1320pub struct SelectionEffects {
 1321    nav_history: Option<bool>,
 1322    completions: bool,
 1323    scroll: Option<Autoscroll>,
 1324}
 1325
 1326impl Default for SelectionEffects {
 1327    fn default() -> Self {
 1328        Self {
 1329            nav_history: None,
 1330            completions: true,
 1331            scroll: Some(Autoscroll::fit()),
 1332        }
 1333    }
 1334}
 1335impl SelectionEffects {
 1336    pub fn scroll(scroll: Autoscroll) -> Self {
 1337        Self {
 1338            scroll: Some(scroll),
 1339            ..Default::default()
 1340        }
 1341    }
 1342
 1343    pub fn no_scroll() -> Self {
 1344        Self {
 1345            scroll: None,
 1346            ..Default::default()
 1347        }
 1348    }
 1349
 1350    pub fn completions(self, completions: bool) -> Self {
 1351        Self {
 1352            completions,
 1353            ..self
 1354        }
 1355    }
 1356
 1357    pub fn nav_history(self, nav_history: bool) -> Self {
 1358        Self {
 1359            nav_history: Some(nav_history),
 1360            ..self
 1361        }
 1362    }
 1363}
 1364
 1365struct DeferredSelectionEffectsState {
 1366    changed: bool,
 1367    effects: SelectionEffects,
 1368    old_cursor_position: Anchor,
 1369    history_entry: SelectionHistoryEntry,
 1370}
 1371
 1372#[derive(Default)]
 1373struct SelectionHistory {
 1374    #[allow(clippy::type_complexity)]
 1375    selections_by_transaction:
 1376        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1377    mode: SelectionHistoryMode,
 1378    undo_stack: VecDeque<SelectionHistoryEntry>,
 1379    redo_stack: VecDeque<SelectionHistoryEntry>,
 1380}
 1381
 1382impl SelectionHistory {
 1383    #[track_caller]
 1384    fn insert_transaction(
 1385        &mut self,
 1386        transaction_id: TransactionId,
 1387        selections: Arc<[Selection<Anchor>]>,
 1388    ) {
 1389        if selections.is_empty() {
 1390            log::error!(
 1391                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1392                std::panic::Location::caller()
 1393            );
 1394            return;
 1395        }
 1396        self.selections_by_transaction
 1397            .insert(transaction_id, (selections, None));
 1398    }
 1399
 1400    #[allow(clippy::type_complexity)]
 1401    fn transaction(
 1402        &self,
 1403        transaction_id: TransactionId,
 1404    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1405        self.selections_by_transaction.get(&transaction_id)
 1406    }
 1407
 1408    #[allow(clippy::type_complexity)]
 1409    fn transaction_mut(
 1410        &mut self,
 1411        transaction_id: TransactionId,
 1412    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1413        self.selections_by_transaction.get_mut(&transaction_id)
 1414    }
 1415
 1416    fn push(&mut self, entry: SelectionHistoryEntry) {
 1417        if !entry.selections.is_empty() {
 1418            match self.mode {
 1419                SelectionHistoryMode::Normal => {
 1420                    self.push_undo(entry);
 1421                    self.redo_stack.clear();
 1422                }
 1423                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1424                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1425                SelectionHistoryMode::Skipping => {}
 1426            }
 1427        }
 1428    }
 1429
 1430    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1431        if self
 1432            .undo_stack
 1433            .back()
 1434            .map_or(true, |e| e.selections != entry.selections)
 1435        {
 1436            self.undo_stack.push_back(entry);
 1437            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1438                self.undo_stack.pop_front();
 1439            }
 1440        }
 1441    }
 1442
 1443    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1444        if self
 1445            .redo_stack
 1446            .back()
 1447            .map_or(true, |e| e.selections != entry.selections)
 1448        {
 1449            self.redo_stack.push_back(entry);
 1450            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1451                self.redo_stack.pop_front();
 1452            }
 1453        }
 1454    }
 1455}
 1456
 1457#[derive(Clone, Copy)]
 1458pub struct RowHighlightOptions {
 1459    pub autoscroll: bool,
 1460    pub include_gutter: bool,
 1461}
 1462
 1463impl Default for RowHighlightOptions {
 1464    fn default() -> Self {
 1465        Self {
 1466            autoscroll: Default::default(),
 1467            include_gutter: true,
 1468        }
 1469    }
 1470}
 1471
 1472struct RowHighlight {
 1473    index: usize,
 1474    range: Range<Anchor>,
 1475    color: Hsla,
 1476    options: RowHighlightOptions,
 1477    type_id: TypeId,
 1478}
 1479
 1480#[derive(Clone, Debug)]
 1481struct AddSelectionsState {
 1482    groups: Vec<AddSelectionsGroup>,
 1483}
 1484
 1485#[derive(Clone, Debug)]
 1486struct AddSelectionsGroup {
 1487    above: bool,
 1488    stack: Vec<usize>,
 1489}
 1490
 1491#[derive(Clone)]
 1492struct SelectNextState {
 1493    query: AhoCorasick,
 1494    wordwise: bool,
 1495    done: bool,
 1496}
 1497
 1498impl std::fmt::Debug for SelectNextState {
 1499    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1500        f.debug_struct(std::any::type_name::<Self>())
 1501            .field("wordwise", &self.wordwise)
 1502            .field("done", &self.done)
 1503            .finish()
 1504    }
 1505}
 1506
 1507#[derive(Debug)]
 1508struct AutocloseRegion {
 1509    selection_id: usize,
 1510    range: Range<Anchor>,
 1511    pair: BracketPair,
 1512}
 1513
 1514#[derive(Debug)]
 1515struct SnippetState {
 1516    ranges: Vec<Vec<Range<Anchor>>>,
 1517    active_index: usize,
 1518    choices: Vec<Option<Vec<String>>>,
 1519}
 1520
 1521#[doc(hidden)]
 1522pub struct RenameState {
 1523    pub range: Range<Anchor>,
 1524    pub old_name: Arc<str>,
 1525    pub editor: Entity<Editor>,
 1526    block_id: CustomBlockId,
 1527}
 1528
 1529struct InvalidationStack<T>(Vec<T>);
 1530
 1531struct RegisteredEditPredictionProvider {
 1532    provider: Arc<dyn EditPredictionProviderHandle>,
 1533    _subscription: Subscription,
 1534}
 1535
 1536#[derive(Debug, PartialEq, Eq)]
 1537pub struct ActiveDiagnosticGroup {
 1538    pub active_range: Range<Anchor>,
 1539    pub active_message: String,
 1540    pub group_id: usize,
 1541    pub blocks: HashSet<CustomBlockId>,
 1542}
 1543
 1544#[derive(Debug, PartialEq, Eq)]
 1545
 1546pub(crate) enum ActiveDiagnostic {
 1547    None,
 1548    All,
 1549    Group(ActiveDiagnosticGroup),
 1550}
 1551
 1552#[derive(Serialize, Deserialize, Clone, Debug)]
 1553pub struct ClipboardSelection {
 1554    /// The number of bytes in this selection.
 1555    pub len: usize,
 1556    /// Whether this was a full-line selection.
 1557    pub is_entire_line: bool,
 1558    /// The indentation of the first line when this content was originally copied.
 1559    pub first_line_indent: u32,
 1560}
 1561
 1562// selections, scroll behavior, was newest selection reversed
 1563type SelectSyntaxNodeHistoryState = (
 1564    Box<[Selection<usize>]>,
 1565    SelectSyntaxNodeScrollBehavior,
 1566    bool,
 1567);
 1568
 1569#[derive(Default)]
 1570struct SelectSyntaxNodeHistory {
 1571    stack: Vec<SelectSyntaxNodeHistoryState>,
 1572    // disable temporarily to allow changing selections without losing the stack
 1573    pub disable_clearing: bool,
 1574}
 1575
 1576impl SelectSyntaxNodeHistory {
 1577    pub fn try_clear(&mut self) {
 1578        if !self.disable_clearing {
 1579            self.stack.clear();
 1580        }
 1581    }
 1582
 1583    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1584        self.stack.push(selection);
 1585    }
 1586
 1587    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1588        self.stack.pop()
 1589    }
 1590}
 1591
 1592enum SelectSyntaxNodeScrollBehavior {
 1593    CursorTop,
 1594    FitSelection,
 1595    CursorBottom,
 1596}
 1597
 1598#[derive(Debug)]
 1599pub(crate) struct NavigationData {
 1600    cursor_anchor: Anchor,
 1601    cursor_position: Point,
 1602    scroll_anchor: ScrollAnchor,
 1603    scroll_top_row: u32,
 1604}
 1605
 1606#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1607pub enum GotoDefinitionKind {
 1608    Symbol,
 1609    Declaration,
 1610    Type,
 1611    Implementation,
 1612}
 1613
 1614#[derive(Debug, Clone)]
 1615enum InlayHintRefreshReason {
 1616    ModifiersChanged(bool),
 1617    Toggle(bool),
 1618    SettingsChange(InlayHintSettings),
 1619    NewLinesShown,
 1620    BufferEdited(HashSet<Arc<Language>>),
 1621    RefreshRequested,
 1622    ExcerptsRemoved(Vec<ExcerptId>),
 1623}
 1624
 1625impl InlayHintRefreshReason {
 1626    fn description(&self) -> &'static str {
 1627        match self {
 1628            Self::ModifiersChanged(_) => "modifiers changed",
 1629            Self::Toggle(_) => "toggle",
 1630            Self::SettingsChange(_) => "settings change",
 1631            Self::NewLinesShown => "new lines shown",
 1632            Self::BufferEdited(_) => "buffer edited",
 1633            Self::RefreshRequested => "refresh requested",
 1634            Self::ExcerptsRemoved(_) => "excerpts removed",
 1635        }
 1636    }
 1637}
 1638
 1639pub enum FormatTarget {
 1640    Buffers(HashSet<Entity<Buffer>>),
 1641    Ranges(Vec<Range<MultiBufferPoint>>),
 1642}
 1643
 1644pub(crate) struct FocusedBlock {
 1645    id: BlockId,
 1646    focus_handle: WeakFocusHandle,
 1647}
 1648
 1649#[derive(Clone)]
 1650enum JumpData {
 1651    MultiBufferRow {
 1652        row: MultiBufferRow,
 1653        line_offset_from_top: u32,
 1654    },
 1655    MultiBufferPoint {
 1656        excerpt_id: ExcerptId,
 1657        position: Point,
 1658        anchor: text::Anchor,
 1659        line_offset_from_top: u32,
 1660    },
 1661}
 1662
 1663pub enum MultibufferSelectionMode {
 1664    First,
 1665    All,
 1666}
 1667
 1668#[derive(Clone, Copy, Debug, Default)]
 1669pub struct RewrapOptions {
 1670    pub override_language_settings: bool,
 1671    pub preserve_existing_whitespace: bool,
 1672}
 1673
 1674impl Editor {
 1675    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1676        let buffer = cx.new(|cx| Buffer::local("", cx));
 1677        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1678        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1679    }
 1680
 1681    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1682        let buffer = cx.new(|cx| Buffer::local("", cx));
 1683        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1684        Self::new(EditorMode::full(), buffer, None, window, cx)
 1685    }
 1686
 1687    pub fn auto_height(
 1688        min_lines: usize,
 1689        max_lines: usize,
 1690        window: &mut Window,
 1691        cx: &mut Context<Self>,
 1692    ) -> Self {
 1693        let buffer = cx.new(|cx| Buffer::local("", cx));
 1694        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1695        Self::new(
 1696            EditorMode::AutoHeight {
 1697                min_lines,
 1698                max_lines: Some(max_lines),
 1699            },
 1700            buffer,
 1701            None,
 1702            window,
 1703            cx,
 1704        )
 1705    }
 1706
 1707    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1708    /// The editor grows as tall as needed to fit its content.
 1709    pub fn auto_height_unbounded(
 1710        min_lines: usize,
 1711        window: &mut Window,
 1712        cx: &mut Context<Self>,
 1713    ) -> Self {
 1714        let buffer = cx.new(|cx| Buffer::local("", cx));
 1715        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1716        Self::new(
 1717            EditorMode::AutoHeight {
 1718                min_lines,
 1719                max_lines: None,
 1720            },
 1721            buffer,
 1722            None,
 1723            window,
 1724            cx,
 1725        )
 1726    }
 1727
 1728    pub fn for_buffer(
 1729        buffer: Entity<Buffer>,
 1730        project: Option<Entity<Project>>,
 1731        window: &mut Window,
 1732        cx: &mut Context<Self>,
 1733    ) -> Self {
 1734        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1735        Self::new(EditorMode::full(), buffer, project, window, cx)
 1736    }
 1737
 1738    pub fn for_multibuffer(
 1739        buffer: Entity<MultiBuffer>,
 1740        project: Option<Entity<Project>>,
 1741        window: &mut Window,
 1742        cx: &mut Context<Self>,
 1743    ) -> Self {
 1744        Self::new(EditorMode::full(), buffer, project, window, cx)
 1745    }
 1746
 1747    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1748        let mut clone = Self::new(
 1749            self.mode.clone(),
 1750            self.buffer.clone(),
 1751            self.project.clone(),
 1752            window,
 1753            cx,
 1754        );
 1755        self.display_map.update(cx, |display_map, cx| {
 1756            let snapshot = display_map.snapshot(cx);
 1757            clone.display_map.update(cx, |display_map, cx| {
 1758                display_map.set_state(&snapshot, cx);
 1759            });
 1760        });
 1761        clone.folds_did_change(cx);
 1762        clone.selections.clone_state(&self.selections);
 1763        clone.scroll_manager.clone_state(&self.scroll_manager);
 1764        clone.searchable = self.searchable;
 1765        clone.read_only = self.read_only;
 1766        clone
 1767    }
 1768
 1769    pub fn new(
 1770        mode: EditorMode,
 1771        buffer: Entity<MultiBuffer>,
 1772        project: Option<Entity<Project>>,
 1773        window: &mut Window,
 1774        cx: &mut Context<Self>,
 1775    ) -> Self {
 1776        Editor::new_internal(mode, buffer, project, None, window, cx)
 1777    }
 1778
 1779    fn new_internal(
 1780        mode: EditorMode,
 1781        buffer: Entity<MultiBuffer>,
 1782        project: Option<Entity<Project>>,
 1783        display_map: Option<Entity<DisplayMap>>,
 1784        window: &mut Window,
 1785        cx: &mut Context<Self>,
 1786    ) -> Self {
 1787        debug_assert!(
 1788            display_map.is_none() || mode.is_minimap(),
 1789            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1790        );
 1791
 1792        let full_mode = mode.is_full();
 1793        let is_minimap = mode.is_minimap();
 1794        let diagnostics_max_severity = if full_mode {
 1795            EditorSettings::get_global(cx)
 1796                .diagnostics_max_severity
 1797                .unwrap_or(DiagnosticSeverity::Hint)
 1798        } else {
 1799            DiagnosticSeverity::Off
 1800        };
 1801        let style = window.text_style();
 1802        let font_size = style.font_size.to_pixels(window.rem_size());
 1803        let editor = cx.entity().downgrade();
 1804        let fold_placeholder = FoldPlaceholder {
 1805            constrain_width: true,
 1806            render: Arc::new(move |fold_id, fold_range, cx| {
 1807                let editor = editor.clone();
 1808                div()
 1809                    .id(fold_id)
 1810                    .bg(cx.theme().colors().ghost_element_background)
 1811                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1812                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1813                    .rounded_xs()
 1814                    .size_full()
 1815                    .cursor_pointer()
 1816                    .child("")
 1817                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1818                    .on_click(move |_, _window, cx| {
 1819                        editor
 1820                            .update(cx, |editor, cx| {
 1821                                editor.unfold_ranges(
 1822                                    &[fold_range.start..fold_range.end],
 1823                                    true,
 1824                                    false,
 1825                                    cx,
 1826                                );
 1827                                cx.stop_propagation();
 1828                            })
 1829                            .ok();
 1830                    })
 1831                    .into_any()
 1832            }),
 1833            merge_adjacent: true,
 1834            ..FoldPlaceholder::default()
 1835        };
 1836        let display_map = display_map.unwrap_or_else(|| {
 1837            cx.new(|cx| {
 1838                DisplayMap::new(
 1839                    buffer.clone(),
 1840                    style.font(),
 1841                    font_size,
 1842                    None,
 1843                    FILE_HEADER_HEIGHT,
 1844                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1845                    fold_placeholder,
 1846                    diagnostics_max_severity,
 1847                    cx,
 1848                )
 1849            })
 1850        });
 1851
 1852        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1853
 1854        let blink_manager = cx.new(|cx| {
 1855            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1856            if is_minimap {
 1857                blink_manager.disable(cx);
 1858            }
 1859            blink_manager
 1860        });
 1861
 1862        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1863            .then(|| language_settings::SoftWrap::None);
 1864
 1865        let mut project_subscriptions = Vec::new();
 1866        if full_mode {
 1867            if let Some(project) = project.as_ref() {
 1868                project_subscriptions.push(cx.subscribe_in(
 1869                    project,
 1870                    window,
 1871                    |editor, _, event, window, cx| match event {
 1872                        project::Event::RefreshCodeLens => {
 1873                            // we always query lens with actions, without storing them, always refreshing them
 1874                        }
 1875                        project::Event::RefreshInlayHints => {
 1876                            editor
 1877                                .refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1878                        }
 1879                        project::Event::LanguageServerAdded(..)
 1880                        | project::Event::LanguageServerRemoved(..) => {
 1881                            if editor.tasks_update_task.is_none() {
 1882                                editor.tasks_update_task =
 1883                                    Some(editor.refresh_runnables(window, cx));
 1884                            }
 1885                        }
 1886                        project::Event::SnippetEdit(id, snippet_edits) => {
 1887                            if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1888                                let focus_handle = editor.focus_handle(cx);
 1889                                if focus_handle.is_focused(window) {
 1890                                    let snapshot = buffer.read(cx).snapshot();
 1891                                    for (range, snippet) in snippet_edits {
 1892                                        let editor_range =
 1893                                            language::range_from_lsp(*range).to_offset(&snapshot);
 1894                                        editor
 1895                                            .insert_snippet(
 1896                                                &[editor_range],
 1897                                                snippet.clone(),
 1898                                                window,
 1899                                                cx,
 1900                                            )
 1901                                            .ok();
 1902                                    }
 1903                                }
 1904                            }
 1905                        }
 1906                        project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1907                            if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1908                                editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1909                            }
 1910                        }
 1911                        _ => {}
 1912                    },
 1913                ));
 1914                if let Some(task_inventory) = project
 1915                    .read(cx)
 1916                    .task_store()
 1917                    .read(cx)
 1918                    .task_inventory()
 1919                    .cloned()
 1920                {
 1921                    project_subscriptions.push(cx.observe_in(
 1922                        &task_inventory,
 1923                        window,
 1924                        |editor, _, window, cx| {
 1925                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1926                        },
 1927                    ));
 1928                };
 1929
 1930                project_subscriptions.push(cx.subscribe_in(
 1931                    &project.read(cx).breakpoint_store(),
 1932                    window,
 1933                    |editor, _, event, window, cx| match event {
 1934                        BreakpointStoreEvent::ClearDebugLines => {
 1935                            editor.clear_row_highlights::<ActiveDebugLine>();
 1936                            editor.refresh_inline_values(cx);
 1937                        }
 1938                        BreakpointStoreEvent::SetDebugLine => {
 1939                            if editor.go_to_active_debug_line(window, cx) {
 1940                                cx.stop_propagation();
 1941                            }
 1942
 1943                            editor.refresh_inline_values(cx);
 1944                        }
 1945                        _ => {}
 1946                    },
 1947                ));
 1948                let git_store = project.read(cx).git_store().clone();
 1949                let project = project.clone();
 1950                project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1951                    match event {
 1952                        GitStoreEvent::RepositoryUpdated(
 1953                            _,
 1954                            RepositoryEvent::Updated {
 1955                                new_instance: true, ..
 1956                            },
 1957                            _,
 1958                        ) => {
 1959                            this.load_diff_task = Some(
 1960                                update_uncommitted_diff_for_buffer(
 1961                                    cx.entity(),
 1962                                    &project,
 1963                                    this.buffer.read(cx).all_buffers(),
 1964                                    this.buffer.clone(),
 1965                                    cx,
 1966                                )
 1967                                .shared(),
 1968                            );
 1969                        }
 1970                        _ => {}
 1971                    }
 1972                }));
 1973            }
 1974        }
 1975
 1976        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1977
 1978        let inlay_hint_settings =
 1979            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1980        let focus_handle = cx.focus_handle();
 1981        if !is_minimap {
 1982            cx.on_focus(&focus_handle, window, Self::handle_focus)
 1983                .detach();
 1984            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1985                .detach();
 1986            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1987                .detach();
 1988            cx.on_blur(&focus_handle, window, Self::handle_blur)
 1989                .detach();
 1990            cx.observe_pending_input(window, Self::observe_pending_input)
 1991                .detach();
 1992        }
 1993
 1994        let show_indent_guides = if matches!(
 1995            mode,
 1996            EditorMode::SingleLine { .. } | EditorMode::Minimap { .. }
 1997        ) {
 1998            Some(false)
 1999        } else {
 2000            None
 2001        };
 2002
 2003        let breakpoint_store = match (&mode, project.as_ref()) {
 2004            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2005            _ => None,
 2006        };
 2007
 2008        let mut code_action_providers = Vec::new();
 2009        let mut load_uncommitted_diff = None;
 2010        if let Some(project) = project.clone() {
 2011            load_uncommitted_diff = Some(
 2012                update_uncommitted_diff_for_buffer(
 2013                    cx.entity(),
 2014                    &project,
 2015                    buffer.read(cx).all_buffers(),
 2016                    buffer.clone(),
 2017                    cx,
 2018                )
 2019                .shared(),
 2020            );
 2021            code_action_providers.push(Rc::new(project) as Rc<_>);
 2022        }
 2023
 2024        let mut editor = Self {
 2025            focus_handle,
 2026            show_cursor_when_unfocused: false,
 2027            last_focused_descendant: None,
 2028            buffer: buffer.clone(),
 2029            display_map: display_map.clone(),
 2030            selections,
 2031            scroll_manager: ScrollManager::new(cx),
 2032            columnar_selection_state: None,
 2033            add_selections_state: None,
 2034            select_next_state: None,
 2035            select_prev_state: None,
 2036            selection_history: SelectionHistory::default(),
 2037            defer_selection_effects: false,
 2038            deferred_selection_effects_state: None,
 2039            autoclose_regions: Vec::new(),
 2040            snippet_stack: InvalidationStack::default(),
 2041            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2042            ime_transaction: None,
 2043            active_diagnostics: ActiveDiagnostic::None,
 2044            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2045            inline_diagnostics_update: Task::ready(()),
 2046            inline_diagnostics: Vec::new(),
 2047            soft_wrap_mode_override,
 2048            diagnostics_max_severity,
 2049            hard_wrap: None,
 2050            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2051            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2052            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2053            project,
 2054            blink_manager: blink_manager.clone(),
 2055            show_local_selections: true,
 2056            show_scrollbars: ScrollbarAxes {
 2057                horizontal: full_mode,
 2058                vertical: full_mode,
 2059            },
 2060            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2061            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2062            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2063            show_gutter: full_mode,
 2064            show_line_numbers: (!full_mode).then_some(false),
 2065            use_relative_line_numbers: None,
 2066            disable_expand_excerpt_buttons: !full_mode,
 2067            show_git_diff_gutter: None,
 2068            show_code_actions: None,
 2069            show_runnables: None,
 2070            show_breakpoints: None,
 2071            show_wrap_guides: None,
 2072            show_indent_guides,
 2073            placeholder_text: None,
 2074            highlight_order: 0,
 2075            highlighted_rows: HashMap::default(),
 2076            background_highlights: TreeMap::default(),
 2077            gutter_highlights: TreeMap::default(),
 2078            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2079            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2080            nav_history: None,
 2081            context_menu: RefCell::new(None),
 2082            context_menu_options: None,
 2083            mouse_context_menu: None,
 2084            completion_tasks: Vec::new(),
 2085            inline_blame_popover: None,
 2086            inline_blame_popover_show_task: None,
 2087            signature_help_state: SignatureHelpState::default(),
 2088            auto_signature_help: None,
 2089            find_all_references_task_sources: Vec::new(),
 2090            next_completion_id: 0,
 2091            next_inlay_id: 0,
 2092            code_action_providers,
 2093            available_code_actions: None,
 2094            code_actions_task: None,
 2095            quick_selection_highlight_task: None,
 2096            debounced_selection_highlight_task: None,
 2097            document_highlights_task: None,
 2098            linked_editing_range_task: None,
 2099            pending_rename: None,
 2100            searchable: !is_minimap,
 2101            cursor_shape: EditorSettings::get_global(cx)
 2102                .cursor_shape
 2103                .unwrap_or_default(),
 2104            current_line_highlight: None,
 2105            autoindent_mode: Some(AutoindentMode::EachLine),
 2106            collapse_matches: false,
 2107            workspace: None,
 2108            input_enabled: !is_minimap,
 2109            use_modal_editing: full_mode,
 2110            read_only: is_minimap,
 2111            use_autoclose: true,
 2112            use_auto_surround: true,
 2113            auto_replace_emoji_shortcode: false,
 2114            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2115            leader_id: None,
 2116            remote_id: None,
 2117            hover_state: HoverState::default(),
 2118            pending_mouse_down: None,
 2119            hovered_link_state: None,
 2120            edit_prediction_provider: None,
 2121            active_edit_prediction: None,
 2122            stale_edit_prediction_in_menu: None,
 2123            edit_prediction_preview: EditPredictionPreview::Inactive {
 2124                released_too_fast: false,
 2125            },
 2126            inline_diagnostics_enabled: full_mode,
 2127            diagnostics_enabled: full_mode,
 2128            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2129            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2130            gutter_hovered: false,
 2131            pixel_position_of_newest_cursor: None,
 2132            last_bounds: None,
 2133            last_position_map: None,
 2134            expect_bounds_change: None,
 2135            gutter_dimensions: GutterDimensions::default(),
 2136            style: None,
 2137            show_cursor_names: false,
 2138            hovered_cursors: HashMap::default(),
 2139            next_editor_action_id: EditorActionId::default(),
 2140            editor_actions: Rc::default(),
 2141            edit_predictions_hidden_for_vim_mode: false,
 2142            show_edit_predictions_override: None,
 2143            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2144            edit_prediction_settings: EditPredictionSettings::Disabled,
 2145            edit_prediction_indent_conflict: false,
 2146            edit_prediction_requires_modifier_in_indent_conflict: true,
 2147            custom_context_menu: None,
 2148            show_git_blame_gutter: false,
 2149            show_git_blame_inline: false,
 2150            show_selection_menu: None,
 2151            show_git_blame_inline_delay_task: None,
 2152            git_blame_inline_enabled: full_mode
 2153                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2154            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2155            serialize_dirty_buffers: !is_minimap
 2156                && ProjectSettings::get_global(cx)
 2157                    .session
 2158                    .restore_unsaved_buffers,
 2159            blame: None,
 2160            blame_subscription: None,
 2161            tasks: BTreeMap::default(),
 2162
 2163            breakpoint_store,
 2164            gutter_breakpoint_indicator: (None, None),
 2165            hovered_diff_hunk_row: None,
 2166            _subscriptions: (!is_minimap)
 2167                .then(|| {
 2168                    vec![
 2169                        cx.observe(&buffer, Self::on_buffer_changed),
 2170                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2171                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2172                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2173                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2174                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2175                        cx.observe_window_activation(window, |editor, window, cx| {
 2176                            let active = window.is_window_active();
 2177                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2178                                if active {
 2179                                    blink_manager.enable(cx);
 2180                                } else {
 2181                                    blink_manager.disable(cx);
 2182                                }
 2183                            });
 2184                            if active {
 2185                                editor.show_mouse_cursor(cx);
 2186                            }
 2187                        }),
 2188                    ]
 2189                })
 2190                .unwrap_or_default(),
 2191            tasks_update_task: None,
 2192            pull_diagnostics_task: Task::ready(()),
 2193            colors: None,
 2194            next_color_inlay_id: 0,
 2195            linked_edit_ranges: Default::default(),
 2196            in_project_search: false,
 2197            previous_search_ranges: None,
 2198            breadcrumb_header: None,
 2199            focused_block: None,
 2200            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2201            addons: HashMap::default(),
 2202            registered_buffers: HashMap::default(),
 2203            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2204            selection_mark_mode: false,
 2205            toggle_fold_multiple_buffers: Task::ready(()),
 2206            serialize_selections: Task::ready(()),
 2207            serialize_folds: Task::ready(()),
 2208            text_style_refinement: None,
 2209            load_diff_task: load_uncommitted_diff,
 2210            temporary_diff_override: false,
 2211            mouse_cursor_hidden: false,
 2212            minimap: None,
 2213            hide_mouse_mode: EditorSettings::get_global(cx)
 2214                .hide_mouse
 2215                .unwrap_or_default(),
 2216            change_list: ChangeList::new(),
 2217            mode,
 2218            selection_drag_state: SelectionDragState::None,
 2219            folding_newlines: Task::ready(()),
 2220        };
 2221
 2222        if is_minimap {
 2223            return editor;
 2224        }
 2225
 2226        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2227            editor
 2228                ._subscriptions
 2229                .push(cx.observe(breakpoints, |_, _, cx| {
 2230                    cx.notify();
 2231                }));
 2232        }
 2233        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2234        editor._subscriptions.extend(project_subscriptions);
 2235
 2236        editor._subscriptions.push(cx.subscribe_in(
 2237            &cx.entity(),
 2238            window,
 2239            |editor, _, e: &EditorEvent, window, cx| match e {
 2240                EditorEvent::ScrollPositionChanged { local, .. } => {
 2241                    if *local {
 2242                        let new_anchor = editor.scroll_manager.anchor();
 2243                        let snapshot = editor.snapshot(window, cx);
 2244                        editor.update_restoration_data(cx, move |data| {
 2245                            data.scroll_position = (
 2246                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2247                                new_anchor.offset,
 2248                            );
 2249                        });
 2250                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2251                        editor.inline_blame_popover.take();
 2252                    }
 2253                }
 2254                EditorEvent::Edited { .. } => {
 2255                    if !vim_enabled(cx) {
 2256                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2257                        let pop_state = editor
 2258                            .change_list
 2259                            .last()
 2260                            .map(|previous| {
 2261                                previous.len() == selections.len()
 2262                                    && previous.iter().enumerate().all(|(ix, p)| {
 2263                                        p.to_display_point(&map).row()
 2264                                            == selections[ix].head().row()
 2265                                    })
 2266                            })
 2267                            .unwrap_or(false);
 2268                        let new_positions = selections
 2269                            .into_iter()
 2270                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2271                            .collect();
 2272                        editor
 2273                            .change_list
 2274                            .push_to_change_list(pop_state, new_positions);
 2275                    }
 2276                }
 2277                _ => (),
 2278            },
 2279        ));
 2280
 2281        if let Some(dap_store) = editor
 2282            .project
 2283            .as_ref()
 2284            .map(|project| project.read(cx).dap_store())
 2285        {
 2286            let weak_editor = cx.weak_entity();
 2287
 2288            editor
 2289                ._subscriptions
 2290                .push(
 2291                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2292                        let session_entity = cx.entity();
 2293                        weak_editor
 2294                            .update(cx, |editor, cx| {
 2295                                editor._subscriptions.push(
 2296                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2297                                );
 2298                            })
 2299                            .ok();
 2300                    }),
 2301                );
 2302
 2303            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2304                editor
 2305                    ._subscriptions
 2306                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2307            }
 2308        }
 2309
 2310        // skip adding the initial selection to selection history
 2311        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2312        editor.end_selection(window, cx);
 2313        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2314
 2315        editor.scroll_manager.show_scrollbars(window, cx);
 2316        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2317
 2318        if full_mode {
 2319            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2320            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2321
 2322            if editor.git_blame_inline_enabled {
 2323                editor.start_git_blame_inline(false, window, cx);
 2324            }
 2325
 2326            editor.go_to_active_debug_line(window, cx);
 2327
 2328            if let Some(buffer) = buffer.read(cx).as_singleton() {
 2329                if let Some(project) = editor.project.as_ref() {
 2330                    let handle = project.update(cx, |project, cx| {
 2331                        project.register_buffer_with_language_servers(&buffer, cx)
 2332                    });
 2333                    editor
 2334                        .registered_buffers
 2335                        .insert(buffer.read(cx).remote_id(), handle);
 2336                }
 2337            }
 2338
 2339            editor.minimap =
 2340                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2341            editor.colors = Some(LspColorData::new(cx));
 2342            editor.update_lsp_data(false, None, window, cx);
 2343        }
 2344
 2345        if editor.mode.is_full() {
 2346            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2347        }
 2348
 2349        editor
 2350    }
 2351
 2352    pub fn deploy_mouse_context_menu(
 2353        &mut self,
 2354        position: gpui::Point<Pixels>,
 2355        context_menu: Entity<ContextMenu>,
 2356        window: &mut Window,
 2357        cx: &mut Context<Self>,
 2358    ) {
 2359        self.mouse_context_menu = Some(MouseContextMenu::new(
 2360            self,
 2361            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2362            context_menu,
 2363            window,
 2364            cx,
 2365        ));
 2366    }
 2367
 2368    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2369        self.mouse_context_menu
 2370            .as_ref()
 2371            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2372    }
 2373
 2374    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2375        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2376    }
 2377
 2378    fn key_context_internal(
 2379        &self,
 2380        has_active_edit_prediction: bool,
 2381        window: &Window,
 2382        cx: &App,
 2383    ) -> KeyContext {
 2384        let mut key_context = KeyContext::new_with_defaults();
 2385        key_context.add("Editor");
 2386        let mode = match self.mode {
 2387            EditorMode::SingleLine { .. } => "single_line",
 2388            EditorMode::AutoHeight { .. } => "auto_height",
 2389            EditorMode::Minimap { .. } => "minimap",
 2390            EditorMode::Full { .. } => "full",
 2391        };
 2392
 2393        if EditorSettings::jupyter_enabled(cx) {
 2394            key_context.add("jupyter");
 2395        }
 2396
 2397        key_context.set("mode", mode);
 2398        if self.pending_rename.is_some() {
 2399            key_context.add("renaming");
 2400        }
 2401
 2402        match self.context_menu.borrow().as_ref() {
 2403            Some(CodeContextMenu::Completions(menu)) => {
 2404                if menu.visible() {
 2405                    key_context.add("menu");
 2406                    key_context.add("showing_completions");
 2407                }
 2408            }
 2409            Some(CodeContextMenu::CodeActions(menu)) => {
 2410                if menu.visible() {
 2411                    key_context.add("menu");
 2412                    key_context.add("showing_code_actions")
 2413                }
 2414            }
 2415            None => {}
 2416        }
 2417
 2418        if self.signature_help_state.has_multiple_signatures() {
 2419            key_context.add("showing_signature_help");
 2420        }
 2421
 2422        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2423        if !self.focus_handle(cx).contains_focused(window, cx)
 2424            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2425        {
 2426            for addon in self.addons.values() {
 2427                addon.extend_key_context(&mut key_context, cx)
 2428            }
 2429        }
 2430
 2431        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2432            if let Some(extension) = singleton_buffer
 2433                .read(cx)
 2434                .file()
 2435                .and_then(|file| file.path().extension()?.to_str())
 2436            {
 2437                key_context.set("extension", extension.to_string());
 2438            }
 2439        } else {
 2440            key_context.add("multibuffer");
 2441        }
 2442
 2443        if has_active_edit_prediction {
 2444            if self.edit_prediction_in_conflict() {
 2445                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2446            } else {
 2447                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2448                key_context.add("copilot_suggestion");
 2449            }
 2450        }
 2451
 2452        if self.selection_mark_mode {
 2453            key_context.add("selection_mode");
 2454        }
 2455
 2456        key_context
 2457    }
 2458
 2459    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2460        if self.mouse_cursor_hidden {
 2461            self.mouse_cursor_hidden = false;
 2462            cx.notify();
 2463        }
 2464    }
 2465
 2466    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2467        let hide_mouse_cursor = match origin {
 2468            HideMouseCursorOrigin::TypingAction => {
 2469                matches!(
 2470                    self.hide_mouse_mode,
 2471                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2472                )
 2473            }
 2474            HideMouseCursorOrigin::MovementAction => {
 2475                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2476            }
 2477        };
 2478        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2479            self.mouse_cursor_hidden = hide_mouse_cursor;
 2480            cx.notify();
 2481        }
 2482    }
 2483
 2484    pub fn edit_prediction_in_conflict(&self) -> bool {
 2485        if !self.show_edit_predictions_in_menu() {
 2486            return false;
 2487        }
 2488
 2489        let showing_completions = self
 2490            .context_menu
 2491            .borrow()
 2492            .as_ref()
 2493            .map_or(false, |context| {
 2494                matches!(context, CodeContextMenu::Completions(_))
 2495            });
 2496
 2497        showing_completions
 2498            || self.edit_prediction_requires_modifier()
 2499            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2500            // bindings to insert tab characters.
 2501            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2502    }
 2503
 2504    pub fn accept_edit_prediction_keybind(
 2505        &self,
 2506        accept_partial: bool,
 2507        window: &Window,
 2508        cx: &App,
 2509    ) -> AcceptEditPredictionBinding {
 2510        let key_context = self.key_context_internal(true, window, cx);
 2511        let in_conflict = self.edit_prediction_in_conflict();
 2512
 2513        let bindings = if accept_partial {
 2514            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2515        } else {
 2516            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2517        };
 2518
 2519        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2520        // just the first one.
 2521        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2522            !in_conflict
 2523                || binding
 2524                    .keystrokes()
 2525                    .first()
 2526                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2527        }))
 2528    }
 2529
 2530    pub fn new_file(
 2531        workspace: &mut Workspace,
 2532        _: &workspace::NewFile,
 2533        window: &mut Window,
 2534        cx: &mut Context<Workspace>,
 2535    ) {
 2536        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2537            "Failed to create buffer",
 2538            window,
 2539            cx,
 2540            |e, _, _| match e.error_code() {
 2541                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2542                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2543                e.error_tag("required").unwrap_or("the latest version")
 2544            )),
 2545                _ => None,
 2546            },
 2547        );
 2548    }
 2549
 2550    pub fn new_in_workspace(
 2551        workspace: &mut Workspace,
 2552        window: &mut Window,
 2553        cx: &mut Context<Workspace>,
 2554    ) -> Task<Result<Entity<Editor>>> {
 2555        let project = workspace.project().clone();
 2556        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2557
 2558        cx.spawn_in(window, async move |workspace, cx| {
 2559            let buffer = create.await?;
 2560            workspace.update_in(cx, |workspace, window, cx| {
 2561                let editor =
 2562                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2563                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2564                editor
 2565            })
 2566        })
 2567    }
 2568
 2569    fn new_file_vertical(
 2570        workspace: &mut Workspace,
 2571        _: &workspace::NewFileSplitVertical,
 2572        window: &mut Window,
 2573        cx: &mut Context<Workspace>,
 2574    ) {
 2575        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2576    }
 2577
 2578    fn new_file_horizontal(
 2579        workspace: &mut Workspace,
 2580        _: &workspace::NewFileSplitHorizontal,
 2581        window: &mut Window,
 2582        cx: &mut Context<Workspace>,
 2583    ) {
 2584        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2585    }
 2586
 2587    fn new_file_in_direction(
 2588        workspace: &mut Workspace,
 2589        direction: SplitDirection,
 2590        window: &mut Window,
 2591        cx: &mut Context<Workspace>,
 2592    ) {
 2593        let project = workspace.project().clone();
 2594        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2595
 2596        cx.spawn_in(window, async move |workspace, cx| {
 2597            let buffer = create.await?;
 2598            workspace.update_in(cx, move |workspace, window, cx| {
 2599                workspace.split_item(
 2600                    direction,
 2601                    Box::new(
 2602                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2603                    ),
 2604                    window,
 2605                    cx,
 2606                )
 2607            })?;
 2608            anyhow::Ok(())
 2609        })
 2610        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2611            match e.error_code() {
 2612                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2613                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2614                e.error_tag("required").unwrap_or("the latest version")
 2615            )),
 2616                _ => None,
 2617            }
 2618        });
 2619    }
 2620
 2621    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2622        self.leader_id
 2623    }
 2624
 2625    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2626        &self.buffer
 2627    }
 2628
 2629    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2630        self.workspace.as_ref()?.0.upgrade()
 2631    }
 2632
 2633    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2634        self.buffer().read(cx).title(cx)
 2635    }
 2636
 2637    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2638        let git_blame_gutter_max_author_length = self
 2639            .render_git_blame_gutter(cx)
 2640            .then(|| {
 2641                if let Some(blame) = self.blame.as_ref() {
 2642                    let max_author_length =
 2643                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2644                    Some(max_author_length)
 2645                } else {
 2646                    None
 2647                }
 2648            })
 2649            .flatten();
 2650
 2651        EditorSnapshot {
 2652            mode: self.mode.clone(),
 2653            show_gutter: self.show_gutter,
 2654            show_line_numbers: self.show_line_numbers,
 2655            show_git_diff_gutter: self.show_git_diff_gutter,
 2656            show_code_actions: self.show_code_actions,
 2657            show_runnables: self.show_runnables,
 2658            show_breakpoints: self.show_breakpoints,
 2659            git_blame_gutter_max_author_length,
 2660            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2661            scroll_anchor: self.scroll_manager.anchor(),
 2662            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2663            placeholder_text: self.placeholder_text.clone(),
 2664            is_focused: self.focus_handle.is_focused(window),
 2665            current_line_highlight: self
 2666                .current_line_highlight
 2667                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2668            gutter_hovered: self.gutter_hovered,
 2669        }
 2670    }
 2671
 2672    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2673        self.buffer.read(cx).language_at(point, cx)
 2674    }
 2675
 2676    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2677        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2678    }
 2679
 2680    pub fn active_excerpt(
 2681        &self,
 2682        cx: &App,
 2683    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2684        self.buffer
 2685            .read(cx)
 2686            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2687    }
 2688
 2689    pub fn mode(&self) -> &EditorMode {
 2690        &self.mode
 2691    }
 2692
 2693    pub fn set_mode(&mut self, mode: EditorMode) {
 2694        self.mode = mode;
 2695    }
 2696
 2697    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2698        self.collaboration_hub.as_deref()
 2699    }
 2700
 2701    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2702        self.collaboration_hub = Some(hub);
 2703    }
 2704
 2705    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2706        self.in_project_search = in_project_search;
 2707    }
 2708
 2709    pub fn set_custom_context_menu(
 2710        &mut self,
 2711        f: impl 'static
 2712        + Fn(
 2713            &mut Self,
 2714            DisplayPoint,
 2715            &mut Window,
 2716            &mut Context<Self>,
 2717        ) -> Option<Entity<ui::ContextMenu>>,
 2718    ) {
 2719        self.custom_context_menu = Some(Box::new(f))
 2720    }
 2721
 2722    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2723        self.completion_provider = provider;
 2724    }
 2725
 2726    #[cfg(any(test, feature = "test-support"))]
 2727    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2728        self.completion_provider.clone()
 2729    }
 2730
 2731    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2732        self.semantics_provider.clone()
 2733    }
 2734
 2735    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2736        self.semantics_provider = provider;
 2737    }
 2738
 2739    pub fn set_edit_prediction_provider<T>(
 2740        &mut self,
 2741        provider: Option<Entity<T>>,
 2742        window: &mut Window,
 2743        cx: &mut Context<Self>,
 2744    ) where
 2745        T: EditPredictionProvider,
 2746    {
 2747        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2748            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2749                if this.focus_handle.is_focused(window) {
 2750                    this.update_visible_edit_prediction(window, cx);
 2751                }
 2752            }),
 2753            provider: Arc::new(provider),
 2754        });
 2755        self.update_edit_prediction_settings(cx);
 2756        self.refresh_edit_prediction(false, false, window, cx);
 2757    }
 2758
 2759    pub fn placeholder_text(&self) -> Option<&str> {
 2760        self.placeholder_text.as_deref()
 2761    }
 2762
 2763    pub fn set_placeholder_text(
 2764        &mut self,
 2765        placeholder_text: impl Into<Arc<str>>,
 2766        cx: &mut Context<Self>,
 2767    ) {
 2768        let placeholder_text = Some(placeholder_text.into());
 2769        if self.placeholder_text != placeholder_text {
 2770            self.placeholder_text = placeholder_text;
 2771            cx.notify();
 2772        }
 2773    }
 2774
 2775    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2776        self.cursor_shape = cursor_shape;
 2777
 2778        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2779        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2780
 2781        cx.notify();
 2782    }
 2783
 2784    pub fn set_current_line_highlight(
 2785        &mut self,
 2786        current_line_highlight: Option<CurrentLineHighlight>,
 2787    ) {
 2788        self.current_line_highlight = current_line_highlight;
 2789    }
 2790
 2791    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2792        self.collapse_matches = collapse_matches;
 2793    }
 2794
 2795    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2796        let buffers = self.buffer.read(cx).all_buffers();
 2797        let Some(project) = self.project.as_ref() else {
 2798            return;
 2799        };
 2800        project.update(cx, |project, cx| {
 2801            for buffer in buffers {
 2802                self.registered_buffers
 2803                    .entry(buffer.read(cx).remote_id())
 2804                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2805            }
 2806        })
 2807    }
 2808
 2809    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2810        if self.collapse_matches {
 2811            return range.start..range.start;
 2812        }
 2813        range.clone()
 2814    }
 2815
 2816    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2817        if self.display_map.read(cx).clip_at_line_ends != clip {
 2818            self.display_map
 2819                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2820        }
 2821    }
 2822
 2823    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2824        self.input_enabled = input_enabled;
 2825    }
 2826
 2827    pub fn set_edit_predictions_hidden_for_vim_mode(
 2828        &mut self,
 2829        hidden: bool,
 2830        window: &mut Window,
 2831        cx: &mut Context<Self>,
 2832    ) {
 2833        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2834            self.edit_predictions_hidden_for_vim_mode = hidden;
 2835            if hidden {
 2836                self.update_visible_edit_prediction(window, cx);
 2837            } else {
 2838                self.refresh_edit_prediction(true, false, window, cx);
 2839            }
 2840        }
 2841    }
 2842
 2843    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2844        self.menu_edit_predictions_policy = value;
 2845    }
 2846
 2847    pub fn set_autoindent(&mut self, autoindent: bool) {
 2848        if autoindent {
 2849            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2850        } else {
 2851            self.autoindent_mode = None;
 2852        }
 2853    }
 2854
 2855    pub fn read_only(&self, cx: &App) -> bool {
 2856        self.read_only || self.buffer.read(cx).read_only()
 2857    }
 2858
 2859    pub fn set_read_only(&mut self, read_only: bool) {
 2860        self.read_only = read_only;
 2861    }
 2862
 2863    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2864        self.use_autoclose = autoclose;
 2865    }
 2866
 2867    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2868        self.use_auto_surround = auto_surround;
 2869    }
 2870
 2871    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2872        self.auto_replace_emoji_shortcode = auto_replace;
 2873    }
 2874
 2875    pub fn toggle_edit_predictions(
 2876        &mut self,
 2877        _: &ToggleEditPrediction,
 2878        window: &mut Window,
 2879        cx: &mut Context<Self>,
 2880    ) {
 2881        if self.show_edit_predictions_override.is_some() {
 2882            self.set_show_edit_predictions(None, window, cx);
 2883        } else {
 2884            let show_edit_predictions = !self.edit_predictions_enabled();
 2885            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2886        }
 2887    }
 2888
 2889    pub fn set_show_edit_predictions(
 2890        &mut self,
 2891        show_edit_predictions: Option<bool>,
 2892        window: &mut Window,
 2893        cx: &mut Context<Self>,
 2894    ) {
 2895        self.show_edit_predictions_override = show_edit_predictions;
 2896        self.update_edit_prediction_settings(cx);
 2897
 2898        if let Some(false) = show_edit_predictions {
 2899            self.discard_edit_prediction(false, cx);
 2900        } else {
 2901            self.refresh_edit_prediction(false, true, window, cx);
 2902        }
 2903    }
 2904
 2905    fn edit_predictions_disabled_in_scope(
 2906        &self,
 2907        buffer: &Entity<Buffer>,
 2908        buffer_position: language::Anchor,
 2909        cx: &App,
 2910    ) -> bool {
 2911        let snapshot = buffer.read(cx).snapshot();
 2912        let settings = snapshot.settings_at(buffer_position, cx);
 2913
 2914        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2915            return false;
 2916        };
 2917
 2918        scope.override_name().map_or(false, |scope_name| {
 2919            settings
 2920                .edit_predictions_disabled_in
 2921                .iter()
 2922                .any(|s| s == scope_name)
 2923        })
 2924    }
 2925
 2926    pub fn set_use_modal_editing(&mut self, to: bool) {
 2927        self.use_modal_editing = to;
 2928    }
 2929
 2930    pub fn use_modal_editing(&self) -> bool {
 2931        self.use_modal_editing
 2932    }
 2933
 2934    fn selections_did_change(
 2935        &mut self,
 2936        local: bool,
 2937        old_cursor_position: &Anchor,
 2938        effects: SelectionEffects,
 2939        window: &mut Window,
 2940        cx: &mut Context<Self>,
 2941    ) {
 2942        window.invalidate_character_coordinates();
 2943
 2944        // Copy selections to primary selection buffer
 2945        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2946        if local {
 2947            let selections = self.selections.all::<usize>(cx);
 2948            let buffer_handle = self.buffer.read(cx).read(cx);
 2949
 2950            let mut text = String::new();
 2951            for (index, selection) in selections.iter().enumerate() {
 2952                let text_for_selection = buffer_handle
 2953                    .text_for_range(selection.start..selection.end)
 2954                    .collect::<String>();
 2955
 2956                text.push_str(&text_for_selection);
 2957                if index != selections.len() - 1 {
 2958                    text.push('\n');
 2959                }
 2960            }
 2961
 2962            if !text.is_empty() {
 2963                cx.write_to_primary(ClipboardItem::new_string(text));
 2964            }
 2965        }
 2966
 2967        let selection_anchors = self.selections.disjoint_anchors();
 2968
 2969        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2970            self.buffer.update(cx, |buffer, cx| {
 2971                buffer.set_active_selections(
 2972                    &selection_anchors,
 2973                    self.selections.line_mode,
 2974                    self.cursor_shape,
 2975                    cx,
 2976                )
 2977            });
 2978        }
 2979        let display_map = self
 2980            .display_map
 2981            .update(cx, |display_map, cx| display_map.snapshot(cx));
 2982        let buffer = &display_map.buffer_snapshot;
 2983        if self.selections.count() == 1 {
 2984            self.add_selections_state = None;
 2985        }
 2986        self.select_next_state = None;
 2987        self.select_prev_state = None;
 2988        self.select_syntax_node_history.try_clear();
 2989        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 2990        self.snippet_stack.invalidate(&selection_anchors, buffer);
 2991        self.take_rename(false, window, cx);
 2992
 2993        let newest_selection = self.selections.newest_anchor();
 2994        let new_cursor_position = newest_selection.head();
 2995        let selection_start = newest_selection.start;
 2996
 2997        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 2998            self.push_to_nav_history(
 2999                *old_cursor_position,
 3000                Some(new_cursor_position.to_point(buffer)),
 3001                false,
 3002                effects.nav_history == Some(true),
 3003                cx,
 3004            );
 3005        }
 3006
 3007        if local {
 3008            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3009                if !self.registered_buffers.contains_key(&buffer_id) {
 3010                    if let Some(project) = self.project.as_ref() {
 3011                        project.update(cx, |project, cx| {
 3012                            let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3013                                return;
 3014                            };
 3015                            self.registered_buffers.insert(
 3016                                buffer_id,
 3017                                project.register_buffer_with_language_servers(&buffer, cx),
 3018                            );
 3019                        })
 3020                    }
 3021                }
 3022            }
 3023
 3024            let mut context_menu = self.context_menu.borrow_mut();
 3025            let completion_menu = match context_menu.as_ref() {
 3026                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3027                Some(CodeContextMenu::CodeActions(_)) => {
 3028                    *context_menu = None;
 3029                    None
 3030                }
 3031                None => None,
 3032            };
 3033            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3034            drop(context_menu);
 3035
 3036            if effects.completions {
 3037                if let Some(completion_position) = completion_position {
 3038                    let start_offset = selection_start.to_offset(buffer);
 3039                    let position_matches = start_offset == completion_position.to_offset(buffer);
 3040                    let continue_showing = if position_matches {
 3041                        if self.snippet_stack.is_empty() {
 3042                            buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3043                        } else {
 3044                            // Snippet choices can be shown even when the cursor is in whitespace.
 3045                            // Dismissing the menu with actions like backspace is handled by
 3046                            // invalidation regions.
 3047                            true
 3048                        }
 3049                    } else {
 3050                        false
 3051                    };
 3052
 3053                    if continue_showing {
 3054                        self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3055                    } else {
 3056                        self.hide_context_menu(window, cx);
 3057                    }
 3058                }
 3059            }
 3060
 3061            hide_hover(self, cx);
 3062
 3063            if old_cursor_position.to_display_point(&display_map).row()
 3064                != new_cursor_position.to_display_point(&display_map).row()
 3065            {
 3066                self.available_code_actions.take();
 3067            }
 3068            self.refresh_code_actions(window, cx);
 3069            self.refresh_document_highlights(cx);
 3070            self.refresh_selected_text_highlights(false, window, cx);
 3071            refresh_matching_bracket_highlights(self, window, cx);
 3072            self.update_visible_edit_prediction(window, cx);
 3073            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3074            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3075            self.inline_blame_popover.take();
 3076            if self.git_blame_inline_enabled {
 3077                self.start_inline_blame_timer(window, cx);
 3078            }
 3079        }
 3080
 3081        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3082        cx.emit(EditorEvent::SelectionsChanged { local });
 3083
 3084        let selections = &self.selections.disjoint;
 3085        if selections.len() == 1 {
 3086            cx.emit(SearchEvent::ActiveMatchChanged)
 3087        }
 3088        if local {
 3089            if let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3090                let inmemory_selections = selections
 3091                    .iter()
 3092                    .map(|s| {
 3093                        text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3094                            ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3095                    })
 3096                    .collect();
 3097                self.update_restoration_data(cx, |data| {
 3098                    data.selections = inmemory_selections;
 3099                });
 3100
 3101                if WorkspaceSettings::get(None, cx).restore_on_startup
 3102                    != RestoreOnStartupBehavior::None
 3103                {
 3104                    if let Some(workspace_id) =
 3105                        self.workspace.as_ref().and_then(|workspace| workspace.1)
 3106                    {
 3107                        let snapshot = self.buffer().read(cx).snapshot(cx);
 3108                        let selections = selections.clone();
 3109                        let background_executor = cx.background_executor().clone();
 3110                        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3111                        self.serialize_selections = cx.background_spawn(async move {
 3112                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3113                            let db_selections = selections
 3114                                .iter()
 3115                                .map(|selection| {
 3116                                    (
 3117                                        selection.start.to_offset(&snapshot),
 3118                                        selection.end.to_offset(&snapshot),
 3119                                    )
 3120                                })
 3121                                .collect();
 3122
 3123                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3124                                .await
 3125                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3126                                .log_err();
 3127                        });
 3128                    }
 3129                }
 3130            }
 3131        }
 3132
 3133        cx.notify();
 3134    }
 3135
 3136    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3137        use text::ToOffset as _;
 3138        use text::ToPoint as _;
 3139
 3140        if self.mode.is_minimap()
 3141            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3142        {
 3143            return;
 3144        }
 3145
 3146        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3147            return;
 3148        };
 3149
 3150        let snapshot = singleton.read(cx).snapshot();
 3151        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3152            let display_snapshot = display_map.snapshot(cx);
 3153
 3154            display_snapshot
 3155                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3156                .map(|fold| {
 3157                    fold.range.start.text_anchor.to_point(&snapshot)
 3158                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3159                })
 3160                .collect()
 3161        });
 3162        self.update_restoration_data(cx, |data| {
 3163            data.folds = inmemory_folds;
 3164        });
 3165
 3166        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3167            return;
 3168        };
 3169        let background_executor = cx.background_executor().clone();
 3170        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3171        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3172            display_map
 3173                .snapshot(cx)
 3174                .folds_in_range(0..snapshot.len())
 3175                .map(|fold| {
 3176                    (
 3177                        fold.range.start.text_anchor.to_offset(&snapshot),
 3178                        fold.range.end.text_anchor.to_offset(&snapshot),
 3179                    )
 3180                })
 3181                .collect()
 3182        });
 3183        self.serialize_folds = cx.background_spawn(async move {
 3184            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3185            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3186                .await
 3187                .with_context(|| {
 3188                    format!(
 3189                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3190                    )
 3191                })
 3192                .log_err();
 3193        });
 3194    }
 3195
 3196    pub fn sync_selections(
 3197        &mut self,
 3198        other: Entity<Editor>,
 3199        cx: &mut Context<Self>,
 3200    ) -> gpui::Subscription {
 3201        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3202        self.selections.change_with(cx, |selections| {
 3203            selections.select_anchors(other_selections);
 3204        });
 3205
 3206        let other_subscription =
 3207            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3208                EditorEvent::SelectionsChanged { local: true } => {
 3209                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3210                    if other_selections.is_empty() {
 3211                        return;
 3212                    }
 3213                    this.selections.change_with(cx, |selections| {
 3214                        selections.select_anchors(other_selections);
 3215                    });
 3216                }
 3217                _ => {}
 3218            });
 3219
 3220        let this_subscription =
 3221            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3222                EditorEvent::SelectionsChanged { local: true } => {
 3223                    let these_selections = this.selections.disjoint.to_vec();
 3224                    if these_selections.is_empty() {
 3225                        return;
 3226                    }
 3227                    other.update(cx, |other_editor, cx| {
 3228                        other_editor.selections.change_with(cx, |selections| {
 3229                            selections.select_anchors(these_selections);
 3230                        })
 3231                    });
 3232                }
 3233                _ => {}
 3234            });
 3235
 3236        Subscription::join(other_subscription, this_subscription)
 3237    }
 3238
 3239    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3240    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3241    /// effects of selection change occur at the end of the transaction.
 3242    pub fn change_selections<R>(
 3243        &mut self,
 3244        effects: SelectionEffects,
 3245        window: &mut Window,
 3246        cx: &mut Context<Self>,
 3247        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3248    ) -> R {
 3249        if let Some(state) = &mut self.deferred_selection_effects_state {
 3250            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3251            state.effects.completions = effects.completions;
 3252            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3253            let (changed, result) = self.selections.change_with(cx, change);
 3254            state.changed |= changed;
 3255            return result;
 3256        }
 3257        let mut state = DeferredSelectionEffectsState {
 3258            changed: false,
 3259            effects,
 3260            old_cursor_position: self.selections.newest_anchor().head(),
 3261            history_entry: SelectionHistoryEntry {
 3262                selections: self.selections.disjoint_anchors(),
 3263                select_next_state: self.select_next_state.clone(),
 3264                select_prev_state: self.select_prev_state.clone(),
 3265                add_selections_state: self.add_selections_state.clone(),
 3266            },
 3267        };
 3268        let (changed, result) = self.selections.change_with(cx, change);
 3269        state.changed = state.changed || changed;
 3270        if self.defer_selection_effects {
 3271            self.deferred_selection_effects_state = Some(state);
 3272        } else {
 3273            self.apply_selection_effects(state, window, cx);
 3274        }
 3275        result
 3276    }
 3277
 3278    /// Defers the effects of selection change, so that the effects of multiple calls to
 3279    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3280    /// to selection history and the state of popovers based on selection position aren't
 3281    /// erroneously updated.
 3282    pub fn with_selection_effects_deferred<R>(
 3283        &mut self,
 3284        window: &mut Window,
 3285        cx: &mut Context<Self>,
 3286        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3287    ) -> R {
 3288        let already_deferred = self.defer_selection_effects;
 3289        self.defer_selection_effects = true;
 3290        let result = update(self, window, cx);
 3291        if !already_deferred {
 3292            self.defer_selection_effects = false;
 3293            if let Some(state) = self.deferred_selection_effects_state.take() {
 3294                self.apply_selection_effects(state, window, cx);
 3295            }
 3296        }
 3297        result
 3298    }
 3299
 3300    fn apply_selection_effects(
 3301        &mut self,
 3302        state: DeferredSelectionEffectsState,
 3303        window: &mut Window,
 3304        cx: &mut Context<Self>,
 3305    ) {
 3306        if state.changed {
 3307            self.selection_history.push(state.history_entry);
 3308
 3309            if let Some(autoscroll) = state.effects.scroll {
 3310                self.request_autoscroll(autoscroll, cx);
 3311            }
 3312
 3313            let old_cursor_position = &state.old_cursor_position;
 3314
 3315            self.selections_did_change(true, &old_cursor_position, state.effects, window, cx);
 3316
 3317            if self.should_open_signature_help_automatically(&old_cursor_position, cx) {
 3318                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3319            }
 3320        }
 3321    }
 3322
 3323    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3324    where
 3325        I: IntoIterator<Item = (Range<S>, T)>,
 3326        S: ToOffset,
 3327        T: Into<Arc<str>>,
 3328    {
 3329        if self.read_only(cx) {
 3330            return;
 3331        }
 3332
 3333        self.buffer
 3334            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3335    }
 3336
 3337    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3338    where
 3339        I: IntoIterator<Item = (Range<S>, T)>,
 3340        S: ToOffset,
 3341        T: Into<Arc<str>>,
 3342    {
 3343        if self.read_only(cx) {
 3344            return;
 3345        }
 3346
 3347        self.buffer.update(cx, |buffer, cx| {
 3348            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3349        });
 3350    }
 3351
 3352    pub fn edit_with_block_indent<I, S, T>(
 3353        &mut self,
 3354        edits: I,
 3355        original_indent_columns: Vec<Option<u32>>,
 3356        cx: &mut Context<Self>,
 3357    ) where
 3358        I: IntoIterator<Item = (Range<S>, T)>,
 3359        S: ToOffset,
 3360        T: Into<Arc<str>>,
 3361    {
 3362        if self.read_only(cx) {
 3363            return;
 3364        }
 3365
 3366        self.buffer.update(cx, |buffer, cx| {
 3367            buffer.edit(
 3368                edits,
 3369                Some(AutoindentMode::Block {
 3370                    original_indent_columns,
 3371                }),
 3372                cx,
 3373            )
 3374        });
 3375    }
 3376
 3377    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3378        self.hide_context_menu(window, cx);
 3379
 3380        match phase {
 3381            SelectPhase::Begin {
 3382                position,
 3383                add,
 3384                click_count,
 3385            } => self.begin_selection(position, add, click_count, window, cx),
 3386            SelectPhase::BeginColumnar {
 3387                position,
 3388                goal_column,
 3389                reset,
 3390                mode,
 3391            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3392            SelectPhase::Extend {
 3393                position,
 3394                click_count,
 3395            } => self.extend_selection(position, click_count, window, cx),
 3396            SelectPhase::Update {
 3397                position,
 3398                goal_column,
 3399                scroll_delta,
 3400            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3401            SelectPhase::End => self.end_selection(window, cx),
 3402        }
 3403    }
 3404
 3405    fn extend_selection(
 3406        &mut self,
 3407        position: DisplayPoint,
 3408        click_count: usize,
 3409        window: &mut Window,
 3410        cx: &mut Context<Self>,
 3411    ) {
 3412        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3413        let tail = self.selections.newest::<usize>(cx).tail();
 3414        self.begin_selection(position, false, click_count, window, cx);
 3415
 3416        let position = position.to_offset(&display_map, Bias::Left);
 3417        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3418
 3419        let mut pending_selection = self
 3420            .selections
 3421            .pending_anchor()
 3422            .expect("extend_selection not called with pending selection");
 3423        if position >= tail {
 3424            pending_selection.start = tail_anchor;
 3425        } else {
 3426            pending_selection.end = tail_anchor;
 3427            pending_selection.reversed = true;
 3428        }
 3429
 3430        let mut pending_mode = self.selections.pending_mode().unwrap();
 3431        match &mut pending_mode {
 3432            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3433            _ => {}
 3434        }
 3435
 3436        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3437            SelectionEffects::scroll(Autoscroll::fit())
 3438        } else {
 3439            SelectionEffects::no_scroll()
 3440        };
 3441
 3442        self.change_selections(effects, window, cx, |s| {
 3443            s.set_pending(pending_selection, pending_mode)
 3444        });
 3445    }
 3446
 3447    fn begin_selection(
 3448        &mut self,
 3449        position: DisplayPoint,
 3450        add: bool,
 3451        click_count: usize,
 3452        window: &mut Window,
 3453        cx: &mut Context<Self>,
 3454    ) {
 3455        if !self.focus_handle.is_focused(window) {
 3456            self.last_focused_descendant = None;
 3457            window.focus(&self.focus_handle);
 3458        }
 3459
 3460        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3461        let buffer = &display_map.buffer_snapshot;
 3462        let position = display_map.clip_point(position, Bias::Left);
 3463
 3464        let start;
 3465        let end;
 3466        let mode;
 3467        let mut auto_scroll;
 3468        match click_count {
 3469            1 => {
 3470                start = buffer.anchor_before(position.to_point(&display_map));
 3471                end = start;
 3472                mode = SelectMode::Character;
 3473                auto_scroll = true;
 3474            }
 3475            2 => {
 3476                let position = display_map
 3477                    .clip_point(position, Bias::Left)
 3478                    .to_offset(&display_map, Bias::Left);
 3479                let (range, _) = buffer.surrounding_word(position, false);
 3480                start = buffer.anchor_before(range.start);
 3481                end = buffer.anchor_before(range.end);
 3482                mode = SelectMode::Word(start..end);
 3483                auto_scroll = true;
 3484            }
 3485            3 => {
 3486                let position = display_map
 3487                    .clip_point(position, Bias::Left)
 3488                    .to_point(&display_map);
 3489                let line_start = display_map.prev_line_boundary(position).0;
 3490                let next_line_start = buffer.clip_point(
 3491                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3492                    Bias::Left,
 3493                );
 3494                start = buffer.anchor_before(line_start);
 3495                end = buffer.anchor_before(next_line_start);
 3496                mode = SelectMode::Line(start..end);
 3497                auto_scroll = true;
 3498            }
 3499            _ => {
 3500                start = buffer.anchor_before(0);
 3501                end = buffer.anchor_before(buffer.len());
 3502                mode = SelectMode::All;
 3503                auto_scroll = false;
 3504            }
 3505        }
 3506        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3507
 3508        let point_to_delete: Option<usize> = {
 3509            let selected_points: Vec<Selection<Point>> =
 3510                self.selections.disjoint_in_range(start..end, cx);
 3511
 3512            if !add || click_count > 1 {
 3513                None
 3514            } else if !selected_points.is_empty() {
 3515                Some(selected_points[0].id)
 3516            } else {
 3517                let clicked_point_already_selected =
 3518                    self.selections.disjoint.iter().find(|selection| {
 3519                        selection.start.to_point(buffer) == start.to_point(buffer)
 3520                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3521                    });
 3522
 3523                clicked_point_already_selected.map(|selection| selection.id)
 3524            }
 3525        };
 3526
 3527        let selections_count = self.selections.count();
 3528        let effects = if auto_scroll {
 3529            SelectionEffects::default()
 3530        } else {
 3531            SelectionEffects::no_scroll()
 3532        };
 3533
 3534        self.change_selections(effects, window, cx, |s| {
 3535            if let Some(point_to_delete) = point_to_delete {
 3536                s.delete(point_to_delete);
 3537
 3538                if selections_count == 1 {
 3539                    s.set_pending_anchor_range(start..end, mode);
 3540                }
 3541            } else {
 3542                if !add {
 3543                    s.clear_disjoint();
 3544                }
 3545
 3546                s.set_pending_anchor_range(start..end, mode);
 3547            }
 3548        });
 3549    }
 3550
 3551    fn begin_columnar_selection(
 3552        &mut self,
 3553        position: DisplayPoint,
 3554        goal_column: u32,
 3555        reset: bool,
 3556        mode: ColumnarMode,
 3557        window: &mut Window,
 3558        cx: &mut Context<Self>,
 3559    ) {
 3560        if !self.focus_handle.is_focused(window) {
 3561            self.last_focused_descendant = None;
 3562            window.focus(&self.focus_handle);
 3563        }
 3564
 3565        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3566
 3567        if reset {
 3568            let pointer_position = display_map
 3569                .buffer_snapshot
 3570                .anchor_before(position.to_point(&display_map));
 3571
 3572            self.change_selections(
 3573                SelectionEffects::scroll(Autoscroll::newest()),
 3574                window,
 3575                cx,
 3576                |s| {
 3577                    s.clear_disjoint();
 3578                    s.set_pending_anchor_range(
 3579                        pointer_position..pointer_position,
 3580                        SelectMode::Character,
 3581                    );
 3582                },
 3583            );
 3584        };
 3585
 3586        let tail = self.selections.newest::<Point>(cx).tail();
 3587        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3588        self.columnar_selection_state = match mode {
 3589            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3590                selection_tail: selection_anchor,
 3591                display_point: if reset {
 3592                    if position.column() != goal_column {
 3593                        Some(DisplayPoint::new(position.row(), goal_column))
 3594                    } else {
 3595                        None
 3596                    }
 3597                } else {
 3598                    None
 3599                },
 3600            }),
 3601            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3602                selection_tail: selection_anchor,
 3603            }),
 3604        };
 3605
 3606        if !reset {
 3607            self.select_columns(position, goal_column, &display_map, window, cx);
 3608        }
 3609    }
 3610
 3611    fn update_selection(
 3612        &mut self,
 3613        position: DisplayPoint,
 3614        goal_column: u32,
 3615        scroll_delta: gpui::Point<f32>,
 3616        window: &mut Window,
 3617        cx: &mut Context<Self>,
 3618    ) {
 3619        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3620
 3621        if self.columnar_selection_state.is_some() {
 3622            self.select_columns(position, goal_column, &display_map, window, cx);
 3623        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3624            let buffer = &display_map.buffer_snapshot;
 3625            let head;
 3626            let tail;
 3627            let mode = self.selections.pending_mode().unwrap();
 3628            match &mode {
 3629                SelectMode::Character => {
 3630                    head = position.to_point(&display_map);
 3631                    tail = pending.tail().to_point(buffer);
 3632                }
 3633                SelectMode::Word(original_range) => {
 3634                    let offset = display_map
 3635                        .clip_point(position, Bias::Left)
 3636                        .to_offset(&display_map, Bias::Left);
 3637                    let original_range = original_range.to_offset(buffer);
 3638
 3639                    let head_offset = if buffer.is_inside_word(offset, false)
 3640                        || original_range.contains(&offset)
 3641                    {
 3642                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3643                        if word_range.start < original_range.start {
 3644                            word_range.start
 3645                        } else {
 3646                            word_range.end
 3647                        }
 3648                    } else {
 3649                        offset
 3650                    };
 3651
 3652                    head = head_offset.to_point(buffer);
 3653                    if head_offset <= original_range.start {
 3654                        tail = original_range.end.to_point(buffer);
 3655                    } else {
 3656                        tail = original_range.start.to_point(buffer);
 3657                    }
 3658                }
 3659                SelectMode::Line(original_range) => {
 3660                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3661
 3662                    let position = display_map
 3663                        .clip_point(position, Bias::Left)
 3664                        .to_point(&display_map);
 3665                    let line_start = display_map.prev_line_boundary(position).0;
 3666                    let next_line_start = buffer.clip_point(
 3667                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3668                        Bias::Left,
 3669                    );
 3670
 3671                    if line_start < original_range.start {
 3672                        head = line_start
 3673                    } else {
 3674                        head = next_line_start
 3675                    }
 3676
 3677                    if head <= original_range.start {
 3678                        tail = original_range.end;
 3679                    } else {
 3680                        tail = original_range.start;
 3681                    }
 3682                }
 3683                SelectMode::All => {
 3684                    return;
 3685                }
 3686            };
 3687
 3688            if head < tail {
 3689                pending.start = buffer.anchor_before(head);
 3690                pending.end = buffer.anchor_before(tail);
 3691                pending.reversed = true;
 3692            } else {
 3693                pending.start = buffer.anchor_before(tail);
 3694                pending.end = buffer.anchor_before(head);
 3695                pending.reversed = false;
 3696            }
 3697
 3698            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3699                s.set_pending(pending, mode);
 3700            });
 3701        } else {
 3702            log::error!("update_selection dispatched with no pending selection");
 3703            return;
 3704        }
 3705
 3706        self.apply_scroll_delta(scroll_delta, window, cx);
 3707        cx.notify();
 3708    }
 3709
 3710    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3711        self.columnar_selection_state.take();
 3712        if self.selections.pending_anchor().is_some() {
 3713            let selections = self.selections.all::<usize>(cx);
 3714            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3715                s.select(selections);
 3716                s.clear_pending();
 3717            });
 3718        }
 3719    }
 3720
 3721    fn select_columns(
 3722        &mut self,
 3723        head: DisplayPoint,
 3724        goal_column: u32,
 3725        display_map: &DisplaySnapshot,
 3726        window: &mut Window,
 3727        cx: &mut Context<Self>,
 3728    ) {
 3729        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3730            return;
 3731        };
 3732
 3733        let tail = match columnar_state {
 3734            ColumnarSelectionState::FromMouse {
 3735                selection_tail,
 3736                display_point,
 3737            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(&display_map)),
 3738            ColumnarSelectionState::FromSelection { selection_tail } => {
 3739                selection_tail.to_display_point(&display_map)
 3740            }
 3741        };
 3742
 3743        let start_row = cmp::min(tail.row(), head.row());
 3744        let end_row = cmp::max(tail.row(), head.row());
 3745        let start_column = cmp::min(tail.column(), goal_column);
 3746        let end_column = cmp::max(tail.column(), goal_column);
 3747        let reversed = start_column < tail.column();
 3748
 3749        let selection_ranges = (start_row.0..=end_row.0)
 3750            .map(DisplayRow)
 3751            .filter_map(|row| {
 3752                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3753                    || start_column <= display_map.line_len(row))
 3754                    && !display_map.is_block_line(row)
 3755                {
 3756                    let start = display_map
 3757                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3758                        .to_point(display_map);
 3759                    let end = display_map
 3760                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3761                        .to_point(display_map);
 3762                    if reversed {
 3763                        Some(end..start)
 3764                    } else {
 3765                        Some(start..end)
 3766                    }
 3767                } else {
 3768                    None
 3769                }
 3770            })
 3771            .collect::<Vec<_>>();
 3772
 3773        let ranges = match columnar_state {
 3774            ColumnarSelectionState::FromMouse { .. } => {
 3775                let mut non_empty_ranges = selection_ranges
 3776                    .iter()
 3777                    .filter(|selection_range| selection_range.start != selection_range.end)
 3778                    .peekable();
 3779                if non_empty_ranges.peek().is_some() {
 3780                    non_empty_ranges.cloned().collect()
 3781                } else {
 3782                    selection_ranges
 3783                }
 3784            }
 3785            _ => selection_ranges,
 3786        };
 3787
 3788        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3789            s.select_ranges(ranges);
 3790        });
 3791        cx.notify();
 3792    }
 3793
 3794    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3795        self.selections
 3796            .all_adjusted(cx)
 3797            .iter()
 3798            .any(|selection| !selection.is_empty())
 3799    }
 3800
 3801    pub fn has_pending_nonempty_selection(&self) -> bool {
 3802        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3803            Some(Selection { start, end, .. }) => start != end,
 3804            None => false,
 3805        };
 3806
 3807        pending_nonempty_selection
 3808            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3809    }
 3810
 3811    pub fn has_pending_selection(&self) -> bool {
 3812        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3813    }
 3814
 3815    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3816        self.selection_mark_mode = false;
 3817        self.selection_drag_state = SelectionDragState::None;
 3818
 3819        if self.clear_expanded_diff_hunks(cx) {
 3820            cx.notify();
 3821            return;
 3822        }
 3823        if self.dismiss_menus_and_popups(true, window, cx) {
 3824            return;
 3825        }
 3826
 3827        if self.mode.is_full()
 3828            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3829        {
 3830            return;
 3831        }
 3832
 3833        cx.propagate();
 3834    }
 3835
 3836    pub fn dismiss_menus_and_popups(
 3837        &mut self,
 3838        is_user_requested: bool,
 3839        window: &mut Window,
 3840        cx: &mut Context<Self>,
 3841    ) -> bool {
 3842        if self.take_rename(false, window, cx).is_some() {
 3843            return true;
 3844        }
 3845
 3846        if hide_hover(self, cx) {
 3847            return true;
 3848        }
 3849
 3850        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3851            return true;
 3852        }
 3853
 3854        if self.hide_context_menu(window, cx).is_some() {
 3855            return true;
 3856        }
 3857
 3858        if self.mouse_context_menu.take().is_some() {
 3859            return true;
 3860        }
 3861
 3862        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3863            return true;
 3864        }
 3865
 3866        if self.snippet_stack.pop().is_some() {
 3867            return true;
 3868        }
 3869
 3870        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3871            self.dismiss_diagnostics(cx);
 3872            return true;
 3873        }
 3874
 3875        false
 3876    }
 3877
 3878    fn linked_editing_ranges_for(
 3879        &self,
 3880        selection: Range<text::Anchor>,
 3881        cx: &App,
 3882    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3883        if self.linked_edit_ranges.is_empty() {
 3884            return None;
 3885        }
 3886        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3887            selection.end.buffer_id.and_then(|end_buffer_id| {
 3888                if selection.start.buffer_id != Some(end_buffer_id) {
 3889                    return None;
 3890                }
 3891                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3892                let snapshot = buffer.read(cx).snapshot();
 3893                self.linked_edit_ranges
 3894                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3895                    .map(|ranges| (ranges, snapshot, buffer))
 3896            })?;
 3897        use text::ToOffset as TO;
 3898        // find offset from the start of current range to current cursor position
 3899        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3900
 3901        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3902        let start_difference = start_offset - start_byte_offset;
 3903        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3904        let end_difference = end_offset - start_byte_offset;
 3905        // Current range has associated linked ranges.
 3906        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3907        for range in linked_ranges.iter() {
 3908            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3909            let end_offset = start_offset + end_difference;
 3910            let start_offset = start_offset + start_difference;
 3911            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3912                continue;
 3913            }
 3914            if self.selections.disjoint_anchor_ranges().any(|s| {
 3915                if s.start.buffer_id != selection.start.buffer_id
 3916                    || s.end.buffer_id != selection.end.buffer_id
 3917                {
 3918                    return false;
 3919                }
 3920                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3921                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3922            }) {
 3923                continue;
 3924            }
 3925            let start = buffer_snapshot.anchor_after(start_offset);
 3926            let end = buffer_snapshot.anchor_after(end_offset);
 3927            linked_edits
 3928                .entry(buffer.clone())
 3929                .or_default()
 3930                .push(start..end);
 3931        }
 3932        Some(linked_edits)
 3933    }
 3934
 3935    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3936        let text: Arc<str> = text.into();
 3937
 3938        if self.read_only(cx) {
 3939            return;
 3940        }
 3941
 3942        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3943
 3944        let selections = self.selections.all_adjusted(cx);
 3945        let mut bracket_inserted = false;
 3946        let mut edits = Vec::new();
 3947        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3948        let mut new_selections = Vec::with_capacity(selections.len());
 3949        let mut new_autoclose_regions = Vec::new();
 3950        let snapshot = self.buffer.read(cx).read(cx);
 3951        let mut clear_linked_edit_ranges = false;
 3952
 3953        for (selection, autoclose_region) in
 3954            self.selections_with_autoclose_regions(selections, &snapshot)
 3955        {
 3956            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3957                // Determine if the inserted text matches the opening or closing
 3958                // bracket of any of this language's bracket pairs.
 3959                let mut bracket_pair = None;
 3960                let mut is_bracket_pair_start = false;
 3961                let mut is_bracket_pair_end = false;
 3962                if !text.is_empty() {
 3963                    let mut bracket_pair_matching_end = None;
 3964                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3965                    //  and they are removing the character that triggered IME popup.
 3966                    for (pair, enabled) in scope.brackets() {
 3967                        if !pair.close && !pair.surround {
 3968                            continue;
 3969                        }
 3970
 3971                        if enabled && pair.start.ends_with(text.as_ref()) {
 3972                            let prefix_len = pair.start.len() - text.len();
 3973                            let preceding_text_matches_prefix = prefix_len == 0
 3974                                || (selection.start.column >= (prefix_len as u32)
 3975                                    && snapshot.contains_str_at(
 3976                                        Point::new(
 3977                                            selection.start.row,
 3978                                            selection.start.column - (prefix_len as u32),
 3979                                        ),
 3980                                        &pair.start[..prefix_len],
 3981                                    ));
 3982                            if preceding_text_matches_prefix {
 3983                                bracket_pair = Some(pair.clone());
 3984                                is_bracket_pair_start = true;
 3985                                break;
 3986                            }
 3987                        }
 3988                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 3989                        {
 3990                            // take first bracket pair matching end, but don't break in case a later bracket
 3991                            // pair matches start
 3992                            bracket_pair_matching_end = Some(pair.clone());
 3993                        }
 3994                    }
 3995                    if let Some(end) = bracket_pair_matching_end
 3996                        && bracket_pair.is_none()
 3997                    {
 3998                        bracket_pair = Some(end);
 3999                        is_bracket_pair_end = true;
 4000                    }
 4001                }
 4002
 4003                if let Some(bracket_pair) = bracket_pair {
 4004                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4005                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4006                    let auto_surround =
 4007                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4008                    if selection.is_empty() {
 4009                        if is_bracket_pair_start {
 4010                            // If the inserted text is a suffix of an opening bracket and the
 4011                            // selection is preceded by the rest of the opening bracket, then
 4012                            // insert the closing bracket.
 4013                            let following_text_allows_autoclose = snapshot
 4014                                .chars_at(selection.start)
 4015                                .next()
 4016                                .map_or(true, |c| scope.should_autoclose_before(c));
 4017
 4018                            let preceding_text_allows_autoclose = selection.start.column == 0
 4019                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 4020                                    true,
 4021                                    |c| {
 4022                                        bracket_pair.start != bracket_pair.end
 4023                                            || !snapshot
 4024                                                .char_classifier_at(selection.start)
 4025                                                .is_word(c)
 4026                                    },
 4027                                );
 4028
 4029                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4030                                && bracket_pair.start.len() == 1
 4031                            {
 4032                                let target = bracket_pair.start.chars().next().unwrap();
 4033                                let current_line_count = snapshot
 4034                                    .reversed_chars_at(selection.start)
 4035                                    .take_while(|&c| c != '\n')
 4036                                    .filter(|&c| c == target)
 4037                                    .count();
 4038                                current_line_count % 2 == 1
 4039                            } else {
 4040                                false
 4041                            };
 4042
 4043                            if autoclose
 4044                                && bracket_pair.close
 4045                                && following_text_allows_autoclose
 4046                                && preceding_text_allows_autoclose
 4047                                && !is_closing_quote
 4048                            {
 4049                                let anchor = snapshot.anchor_before(selection.end);
 4050                                new_selections.push((selection.map(|_| anchor), text.len()));
 4051                                new_autoclose_regions.push((
 4052                                    anchor,
 4053                                    text.len(),
 4054                                    selection.id,
 4055                                    bracket_pair.clone(),
 4056                                ));
 4057                                edits.push((
 4058                                    selection.range(),
 4059                                    format!("{}{}", text, bracket_pair.end).into(),
 4060                                ));
 4061                                bracket_inserted = true;
 4062                                continue;
 4063                            }
 4064                        }
 4065
 4066                        if let Some(region) = autoclose_region {
 4067                            // If the selection is followed by an auto-inserted closing bracket,
 4068                            // then don't insert that closing bracket again; just move the selection
 4069                            // past the closing bracket.
 4070                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4071                                && text.as_ref() == region.pair.end.as_str()
 4072                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4073                            if should_skip {
 4074                                let anchor = snapshot.anchor_after(selection.end);
 4075                                new_selections
 4076                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4077                                continue;
 4078                            }
 4079                        }
 4080
 4081                        let always_treat_brackets_as_autoclosed = snapshot
 4082                            .language_settings_at(selection.start, cx)
 4083                            .always_treat_brackets_as_autoclosed;
 4084                        if always_treat_brackets_as_autoclosed
 4085                            && is_bracket_pair_end
 4086                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4087                        {
 4088                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4089                            // and the inserted text is a closing bracket and the selection is followed
 4090                            // by the closing bracket then move the selection past the closing bracket.
 4091                            let anchor = snapshot.anchor_after(selection.end);
 4092                            new_selections.push((selection.map(|_| anchor), text.len()));
 4093                            continue;
 4094                        }
 4095                    }
 4096                    // If an opening bracket is 1 character long and is typed while
 4097                    // text is selected, then surround that text with the bracket pair.
 4098                    else if auto_surround
 4099                        && bracket_pair.surround
 4100                        && is_bracket_pair_start
 4101                        && bracket_pair.start.chars().count() == 1
 4102                    {
 4103                        edits.push((selection.start..selection.start, text.clone()));
 4104                        edits.push((
 4105                            selection.end..selection.end,
 4106                            bracket_pair.end.as_str().into(),
 4107                        ));
 4108                        bracket_inserted = true;
 4109                        new_selections.push((
 4110                            Selection {
 4111                                id: selection.id,
 4112                                start: snapshot.anchor_after(selection.start),
 4113                                end: snapshot.anchor_before(selection.end),
 4114                                reversed: selection.reversed,
 4115                                goal: selection.goal,
 4116                            },
 4117                            0,
 4118                        ));
 4119                        continue;
 4120                    }
 4121                }
 4122            }
 4123
 4124            if self.auto_replace_emoji_shortcode
 4125                && selection.is_empty()
 4126                && text.as_ref().ends_with(':')
 4127            {
 4128                if let Some(possible_emoji_short_code) =
 4129                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4130                {
 4131                    if !possible_emoji_short_code.is_empty() {
 4132                        if let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code) {
 4133                            let emoji_shortcode_start = Point::new(
 4134                                selection.start.row,
 4135                                selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4136                            );
 4137
 4138                            // Remove shortcode from buffer
 4139                            edits.push((
 4140                                emoji_shortcode_start..selection.start,
 4141                                "".to_string().into(),
 4142                            ));
 4143                            new_selections.push((
 4144                                Selection {
 4145                                    id: selection.id,
 4146                                    start: snapshot.anchor_after(emoji_shortcode_start),
 4147                                    end: snapshot.anchor_before(selection.start),
 4148                                    reversed: selection.reversed,
 4149                                    goal: selection.goal,
 4150                                },
 4151                                0,
 4152                            ));
 4153
 4154                            // Insert emoji
 4155                            let selection_start_anchor = snapshot.anchor_after(selection.start);
 4156                            new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4157                            edits.push((selection.start..selection.end, emoji.to_string().into()));
 4158
 4159                            continue;
 4160                        }
 4161                    }
 4162                }
 4163            }
 4164
 4165            // If not handling any auto-close operation, then just replace the selected
 4166            // text with the given input and move the selection to the end of the
 4167            // newly inserted text.
 4168            let anchor = snapshot.anchor_after(selection.end);
 4169            if !self.linked_edit_ranges.is_empty() {
 4170                let start_anchor = snapshot.anchor_before(selection.start);
 4171
 4172                let is_word_char = text.chars().next().map_or(true, |char| {
 4173                    let classifier = snapshot
 4174                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4175                        .ignore_punctuation(true);
 4176                    classifier.is_word(char)
 4177                });
 4178
 4179                if is_word_char {
 4180                    if let Some(ranges) = self
 4181                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4182                    {
 4183                        for (buffer, edits) in ranges {
 4184                            linked_edits
 4185                                .entry(buffer.clone())
 4186                                .or_default()
 4187                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4188                        }
 4189                    }
 4190                } else {
 4191                    clear_linked_edit_ranges = true;
 4192                }
 4193            }
 4194
 4195            new_selections.push((selection.map(|_| anchor), 0));
 4196            edits.push((selection.start..selection.end, text.clone()));
 4197        }
 4198
 4199        drop(snapshot);
 4200
 4201        self.transact(window, cx, |this, window, cx| {
 4202            if clear_linked_edit_ranges {
 4203                this.linked_edit_ranges.clear();
 4204            }
 4205            let initial_buffer_versions =
 4206                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4207
 4208            this.buffer.update(cx, |buffer, cx| {
 4209                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4210            });
 4211            for (buffer, edits) in linked_edits {
 4212                buffer.update(cx, |buffer, cx| {
 4213                    let snapshot = buffer.snapshot();
 4214                    let edits = edits
 4215                        .into_iter()
 4216                        .map(|(range, text)| {
 4217                            use text::ToPoint as TP;
 4218                            let end_point = TP::to_point(&range.end, &snapshot);
 4219                            let start_point = TP::to_point(&range.start, &snapshot);
 4220                            (start_point..end_point, text)
 4221                        })
 4222                        .sorted_by_key(|(range, _)| range.start);
 4223                    buffer.edit(edits, None, cx);
 4224                })
 4225            }
 4226            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4227            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4228            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4229            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4230                .zip(new_selection_deltas)
 4231                .map(|(selection, delta)| Selection {
 4232                    id: selection.id,
 4233                    start: selection.start + delta,
 4234                    end: selection.end + delta,
 4235                    reversed: selection.reversed,
 4236                    goal: SelectionGoal::None,
 4237                })
 4238                .collect::<Vec<_>>();
 4239
 4240            let mut i = 0;
 4241            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4242                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4243                let start = map.buffer_snapshot.anchor_before(position);
 4244                let end = map.buffer_snapshot.anchor_after(position);
 4245                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4246                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4247                        Ordering::Less => i += 1,
 4248                        Ordering::Greater => break,
 4249                        Ordering::Equal => {
 4250                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4251                                Ordering::Less => i += 1,
 4252                                Ordering::Equal => break,
 4253                                Ordering::Greater => break,
 4254                            }
 4255                        }
 4256                    }
 4257                }
 4258                this.autoclose_regions.insert(
 4259                    i,
 4260                    AutocloseRegion {
 4261                        selection_id,
 4262                        range: start..end,
 4263                        pair,
 4264                    },
 4265                );
 4266            }
 4267
 4268            let had_active_edit_prediction = this.has_active_edit_prediction();
 4269            this.change_selections(
 4270                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4271                window,
 4272                cx,
 4273                |s| s.select(new_selections),
 4274            );
 4275
 4276            if !bracket_inserted {
 4277                if let Some(on_type_format_task) =
 4278                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4279                {
 4280                    on_type_format_task.detach_and_log_err(cx);
 4281                }
 4282            }
 4283
 4284            let editor_settings = EditorSettings::get_global(cx);
 4285            if bracket_inserted
 4286                && (editor_settings.auto_signature_help
 4287                    || editor_settings.show_signature_help_after_edits)
 4288            {
 4289                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4290            }
 4291
 4292            let trigger_in_words =
 4293                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4294            if this.hard_wrap.is_some() {
 4295                let latest: Range<Point> = this.selections.newest(cx).range();
 4296                if latest.is_empty()
 4297                    && this
 4298                        .buffer()
 4299                        .read(cx)
 4300                        .snapshot(cx)
 4301                        .line_len(MultiBufferRow(latest.start.row))
 4302                        == latest.start.column
 4303                {
 4304                    this.rewrap_impl(
 4305                        RewrapOptions {
 4306                            override_language_settings: true,
 4307                            preserve_existing_whitespace: true,
 4308                        },
 4309                        cx,
 4310                    )
 4311                }
 4312            }
 4313            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4314            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4315            this.refresh_edit_prediction(true, false, window, cx);
 4316            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4317        });
 4318    }
 4319
 4320    fn find_possible_emoji_shortcode_at_position(
 4321        snapshot: &MultiBufferSnapshot,
 4322        position: Point,
 4323    ) -> Option<String> {
 4324        let mut chars = Vec::new();
 4325        let mut found_colon = false;
 4326        for char in snapshot.reversed_chars_at(position).take(100) {
 4327            // Found a possible emoji shortcode in the middle of the buffer
 4328            if found_colon {
 4329                if char.is_whitespace() {
 4330                    chars.reverse();
 4331                    return Some(chars.iter().collect());
 4332                }
 4333                // If the previous character is not a whitespace, we are in the middle of a word
 4334                // and we only want to complete the shortcode if the word is made up of other emojis
 4335                let mut containing_word = String::new();
 4336                for ch in snapshot
 4337                    .reversed_chars_at(position)
 4338                    .skip(chars.len() + 1)
 4339                    .take(100)
 4340                {
 4341                    if ch.is_whitespace() {
 4342                        break;
 4343                    }
 4344                    containing_word.push(ch);
 4345                }
 4346                let containing_word = containing_word.chars().rev().collect::<String>();
 4347                if util::word_consists_of_emojis(containing_word.as_str()) {
 4348                    chars.reverse();
 4349                    return Some(chars.iter().collect());
 4350                }
 4351            }
 4352
 4353            if char.is_whitespace() || !char.is_ascii() {
 4354                return None;
 4355            }
 4356            if char == ':' {
 4357                found_colon = true;
 4358            } else {
 4359                chars.push(char);
 4360            }
 4361        }
 4362        // Found a possible emoji shortcode at the beginning of the buffer
 4363        chars.reverse();
 4364        Some(chars.iter().collect())
 4365    }
 4366
 4367    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4368        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4369        self.transact(window, cx, |this, window, cx| {
 4370            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4371                let selections = this.selections.all::<usize>(cx);
 4372                let multi_buffer = this.buffer.read(cx);
 4373                let buffer = multi_buffer.snapshot(cx);
 4374                selections
 4375                    .iter()
 4376                    .map(|selection| {
 4377                        let start_point = selection.start.to_point(&buffer);
 4378                        let mut existing_indent =
 4379                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4380                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4381                        let start = selection.start;
 4382                        let end = selection.end;
 4383                        let selection_is_empty = start == end;
 4384                        let language_scope = buffer.language_scope_at(start);
 4385                        let (
 4386                            comment_delimiter,
 4387                            doc_delimiter,
 4388                            insert_extra_newline,
 4389                            indent_on_newline,
 4390                            indent_on_extra_newline,
 4391                        ) = if let Some(language) = &language_scope {
 4392                            let mut insert_extra_newline =
 4393                                insert_extra_newline_brackets(&buffer, start..end, language)
 4394                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4395
 4396                            // Comment extension on newline is allowed only for cursor selections
 4397                            let comment_delimiter = maybe!({
 4398                                if !selection_is_empty {
 4399                                    return None;
 4400                                }
 4401
 4402                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4403                                    return None;
 4404                                }
 4405
 4406                                let delimiters = language.line_comment_prefixes();
 4407                                let max_len_of_delimiter =
 4408                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4409                                let (snapshot, range) =
 4410                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4411
 4412                                let num_of_whitespaces = snapshot
 4413                                    .chars_for_range(range.clone())
 4414                                    .take_while(|c| c.is_whitespace())
 4415                                    .count();
 4416                                let comment_candidate = snapshot
 4417                                    .chars_for_range(range.clone())
 4418                                    .skip(num_of_whitespaces)
 4419                                    .take(max_len_of_delimiter)
 4420                                    .collect::<String>();
 4421                                let (delimiter, trimmed_len) = delimiters
 4422                                    .iter()
 4423                                    .filter_map(|delimiter| {
 4424                                        let prefix = delimiter.trim_end();
 4425                                        if comment_candidate.starts_with(prefix) {
 4426                                            Some((delimiter, prefix.len()))
 4427                                        } else {
 4428                                            None
 4429                                        }
 4430                                    })
 4431                                    .max_by_key(|(_, len)| *len)?;
 4432
 4433                                if let Some(BlockCommentConfig {
 4434                                    start: block_start, ..
 4435                                }) = language.block_comment()
 4436                                {
 4437                                    let block_start_trimmed = block_start.trim_end();
 4438                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4439                                        let line_content = snapshot
 4440                                            .chars_for_range(range)
 4441                                            .skip(num_of_whitespaces)
 4442                                            .take(block_start_trimmed.len())
 4443                                            .collect::<String>();
 4444
 4445                                        if line_content.starts_with(block_start_trimmed) {
 4446                                            return None;
 4447                                        }
 4448                                    }
 4449                                }
 4450
 4451                                let cursor_is_placed_after_comment_marker =
 4452                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4453                                if cursor_is_placed_after_comment_marker {
 4454                                    Some(delimiter.clone())
 4455                                } else {
 4456                                    None
 4457                                }
 4458                            });
 4459
 4460                            let mut indent_on_newline = IndentSize::spaces(0);
 4461                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4462
 4463                            let doc_delimiter = maybe!({
 4464                                if !selection_is_empty {
 4465                                    return None;
 4466                                }
 4467
 4468                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4469                                    return None;
 4470                                }
 4471
 4472                                let BlockCommentConfig {
 4473                                    start: start_tag,
 4474                                    end: end_tag,
 4475                                    prefix: delimiter,
 4476                                    tab_size: len,
 4477                                } = language.documentation_comment()?;
 4478                                let is_within_block_comment = buffer
 4479                                    .language_scope_at(start_point)
 4480                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4481                                if !is_within_block_comment {
 4482                                    return None;
 4483                                }
 4484
 4485                                let (snapshot, range) =
 4486                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4487
 4488                                let num_of_whitespaces = snapshot
 4489                                    .chars_for_range(range.clone())
 4490                                    .take_while(|c| c.is_whitespace())
 4491                                    .count();
 4492
 4493                                // 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.
 4494                                let column = start_point.column;
 4495                                let cursor_is_after_start_tag = {
 4496                                    let start_tag_len = start_tag.len();
 4497                                    let start_tag_line = snapshot
 4498                                        .chars_for_range(range.clone())
 4499                                        .skip(num_of_whitespaces)
 4500                                        .take(start_tag_len)
 4501                                        .collect::<String>();
 4502                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4503                                        num_of_whitespaces + start_tag_len <= column as usize
 4504                                    } else {
 4505                                        false
 4506                                    }
 4507                                };
 4508
 4509                                let cursor_is_after_delimiter = {
 4510                                    let delimiter_trim = delimiter.trim_end();
 4511                                    let delimiter_line = snapshot
 4512                                        .chars_for_range(range.clone())
 4513                                        .skip(num_of_whitespaces)
 4514                                        .take(delimiter_trim.len())
 4515                                        .collect::<String>();
 4516                                    if delimiter_line.starts_with(delimiter_trim) {
 4517                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4518                                    } else {
 4519                                        false
 4520                                    }
 4521                                };
 4522
 4523                                let cursor_is_before_end_tag_if_exists = {
 4524                                    let mut char_position = 0u32;
 4525                                    let mut end_tag_offset = None;
 4526
 4527                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4528                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4529                                            let chars_before_match =
 4530                                                chunk[..byte_pos].chars().count() as u32;
 4531                                            end_tag_offset =
 4532                                                Some(char_position + chars_before_match);
 4533                                            break 'outer;
 4534                                        }
 4535                                        char_position += chunk.chars().count() as u32;
 4536                                    }
 4537
 4538                                    if let Some(end_tag_offset) = end_tag_offset {
 4539                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4540                                        if cursor_is_after_start_tag {
 4541                                            if cursor_is_before_end_tag {
 4542                                                insert_extra_newline = true;
 4543                                            }
 4544                                            let cursor_is_at_start_of_end_tag =
 4545                                                column == end_tag_offset;
 4546                                            if cursor_is_at_start_of_end_tag {
 4547                                                indent_on_extra_newline.len = *len;
 4548                                            }
 4549                                        }
 4550                                        cursor_is_before_end_tag
 4551                                    } else {
 4552                                        true
 4553                                    }
 4554                                };
 4555
 4556                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4557                                    && cursor_is_before_end_tag_if_exists
 4558                                {
 4559                                    if cursor_is_after_start_tag {
 4560                                        indent_on_newline.len = *len;
 4561                                    }
 4562                                    Some(delimiter.clone())
 4563                                } else {
 4564                                    None
 4565                                }
 4566                            });
 4567
 4568                            (
 4569                                comment_delimiter,
 4570                                doc_delimiter,
 4571                                insert_extra_newline,
 4572                                indent_on_newline,
 4573                                indent_on_extra_newline,
 4574                            )
 4575                        } else {
 4576                            (
 4577                                None,
 4578                                None,
 4579                                false,
 4580                                IndentSize::default(),
 4581                                IndentSize::default(),
 4582                            )
 4583                        };
 4584
 4585                        let prevent_auto_indent = doc_delimiter.is_some();
 4586                        let delimiter = comment_delimiter.or(doc_delimiter);
 4587
 4588                        let capacity_for_delimiter =
 4589                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4590                        let mut new_text = String::with_capacity(
 4591                            1 + capacity_for_delimiter
 4592                                + existing_indent.len as usize
 4593                                + indent_on_newline.len as usize
 4594                                + indent_on_extra_newline.len as usize,
 4595                        );
 4596                        new_text.push('\n');
 4597                        new_text.extend(existing_indent.chars());
 4598                        new_text.extend(indent_on_newline.chars());
 4599
 4600                        if let Some(delimiter) = &delimiter {
 4601                            new_text.push_str(delimiter);
 4602                        }
 4603
 4604                        if insert_extra_newline {
 4605                            new_text.push('\n');
 4606                            new_text.extend(existing_indent.chars());
 4607                            new_text.extend(indent_on_extra_newline.chars());
 4608                        }
 4609
 4610                        let anchor = buffer.anchor_after(end);
 4611                        let new_selection = selection.map(|_| anchor);
 4612                        (
 4613                            ((start..end, new_text), prevent_auto_indent),
 4614                            (insert_extra_newline, new_selection),
 4615                        )
 4616                    })
 4617                    .unzip()
 4618            };
 4619
 4620            let mut auto_indent_edits = Vec::new();
 4621            let mut edits = Vec::new();
 4622            for (edit, prevent_auto_indent) in edits_with_flags {
 4623                if prevent_auto_indent {
 4624                    edits.push(edit);
 4625                } else {
 4626                    auto_indent_edits.push(edit);
 4627                }
 4628            }
 4629            if !edits.is_empty() {
 4630                this.edit(edits, cx);
 4631            }
 4632            if !auto_indent_edits.is_empty() {
 4633                this.edit_with_autoindent(auto_indent_edits, cx);
 4634            }
 4635
 4636            let buffer = this.buffer.read(cx).snapshot(cx);
 4637            let new_selections = selection_info
 4638                .into_iter()
 4639                .map(|(extra_newline_inserted, new_selection)| {
 4640                    let mut cursor = new_selection.end.to_point(&buffer);
 4641                    if extra_newline_inserted {
 4642                        cursor.row -= 1;
 4643                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4644                    }
 4645                    new_selection.map(|_| cursor)
 4646                })
 4647                .collect();
 4648
 4649            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4650            this.refresh_edit_prediction(true, false, window, cx);
 4651        });
 4652    }
 4653
 4654    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4655        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4656
 4657        let buffer = self.buffer.read(cx);
 4658        let snapshot = buffer.snapshot(cx);
 4659
 4660        let mut edits = Vec::new();
 4661        let mut rows = Vec::new();
 4662
 4663        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4664            let cursor = selection.head();
 4665            let row = cursor.row;
 4666
 4667            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4668
 4669            let newline = "\n".to_string();
 4670            edits.push((start_of_line..start_of_line, newline));
 4671
 4672            rows.push(row + rows_inserted as u32);
 4673        }
 4674
 4675        self.transact(window, cx, |editor, window, cx| {
 4676            editor.edit(edits, cx);
 4677
 4678            editor.change_selections(Default::default(), window, cx, |s| {
 4679                let mut index = 0;
 4680                s.move_cursors_with(|map, _, _| {
 4681                    let row = rows[index];
 4682                    index += 1;
 4683
 4684                    let point = Point::new(row, 0);
 4685                    let boundary = map.next_line_boundary(point).1;
 4686                    let clipped = map.clip_point(boundary, Bias::Left);
 4687
 4688                    (clipped, SelectionGoal::None)
 4689                });
 4690            });
 4691
 4692            let mut indent_edits = Vec::new();
 4693            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4694            for row in rows {
 4695                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4696                for (row, indent) in indents {
 4697                    if indent.len == 0 {
 4698                        continue;
 4699                    }
 4700
 4701                    let text = match indent.kind {
 4702                        IndentKind::Space => " ".repeat(indent.len as usize),
 4703                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4704                    };
 4705                    let point = Point::new(row.0, 0);
 4706                    indent_edits.push((point..point, text));
 4707                }
 4708            }
 4709            editor.edit(indent_edits, cx);
 4710        });
 4711    }
 4712
 4713    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4714        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4715
 4716        let buffer = self.buffer.read(cx);
 4717        let snapshot = buffer.snapshot(cx);
 4718
 4719        let mut edits = Vec::new();
 4720        let mut rows = Vec::new();
 4721        let mut rows_inserted = 0;
 4722
 4723        for selection in self.selections.all_adjusted(cx) {
 4724            let cursor = selection.head();
 4725            let row = cursor.row;
 4726
 4727            let point = Point::new(row + 1, 0);
 4728            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4729
 4730            let newline = "\n".to_string();
 4731            edits.push((start_of_line..start_of_line, newline));
 4732
 4733            rows_inserted += 1;
 4734            rows.push(row + rows_inserted);
 4735        }
 4736
 4737        self.transact(window, cx, |editor, window, cx| {
 4738            editor.edit(edits, cx);
 4739
 4740            editor.change_selections(Default::default(), window, cx, |s| {
 4741                let mut index = 0;
 4742                s.move_cursors_with(|map, _, _| {
 4743                    let row = rows[index];
 4744                    index += 1;
 4745
 4746                    let point = Point::new(row, 0);
 4747                    let boundary = map.next_line_boundary(point).1;
 4748                    let clipped = map.clip_point(boundary, Bias::Left);
 4749
 4750                    (clipped, SelectionGoal::None)
 4751                });
 4752            });
 4753
 4754            let mut indent_edits = Vec::new();
 4755            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4756            for row in rows {
 4757                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4758                for (row, indent) in indents {
 4759                    if indent.len == 0 {
 4760                        continue;
 4761                    }
 4762
 4763                    let text = match indent.kind {
 4764                        IndentKind::Space => " ".repeat(indent.len as usize),
 4765                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4766                    };
 4767                    let point = Point::new(row.0, 0);
 4768                    indent_edits.push((point..point, text));
 4769                }
 4770            }
 4771            editor.edit(indent_edits, cx);
 4772        });
 4773    }
 4774
 4775    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4776        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4777            original_indent_columns: Vec::new(),
 4778        });
 4779        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4780    }
 4781
 4782    fn insert_with_autoindent_mode(
 4783        &mut self,
 4784        text: &str,
 4785        autoindent_mode: Option<AutoindentMode>,
 4786        window: &mut Window,
 4787        cx: &mut Context<Self>,
 4788    ) {
 4789        if self.read_only(cx) {
 4790            return;
 4791        }
 4792
 4793        let text: Arc<str> = text.into();
 4794        self.transact(window, cx, |this, window, cx| {
 4795            let old_selections = this.selections.all_adjusted(cx);
 4796            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4797                let anchors = {
 4798                    let snapshot = buffer.read(cx);
 4799                    old_selections
 4800                        .iter()
 4801                        .map(|s| {
 4802                            let anchor = snapshot.anchor_after(s.head());
 4803                            s.map(|_| anchor)
 4804                        })
 4805                        .collect::<Vec<_>>()
 4806                };
 4807                buffer.edit(
 4808                    old_selections
 4809                        .iter()
 4810                        .map(|s| (s.start..s.end, text.clone())),
 4811                    autoindent_mode,
 4812                    cx,
 4813                );
 4814                anchors
 4815            });
 4816
 4817            this.change_selections(Default::default(), window, cx, |s| {
 4818                s.select_anchors(selection_anchors);
 4819            });
 4820
 4821            cx.notify();
 4822        });
 4823    }
 4824
 4825    fn trigger_completion_on_input(
 4826        &mut self,
 4827        text: &str,
 4828        trigger_in_words: bool,
 4829        window: &mut Window,
 4830        cx: &mut Context<Self>,
 4831    ) {
 4832        let completions_source = self
 4833            .context_menu
 4834            .borrow()
 4835            .as_ref()
 4836            .and_then(|menu| match menu {
 4837                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4838                CodeContextMenu::CodeActions(_) => None,
 4839            });
 4840
 4841        match completions_source {
 4842            Some(CompletionsMenuSource::Words) => {
 4843                self.show_word_completions(&ShowWordCompletions, window, cx)
 4844            }
 4845            Some(CompletionsMenuSource::Normal)
 4846            | Some(CompletionsMenuSource::SnippetChoices)
 4847            | None
 4848                if self.is_completion_trigger(
 4849                    text,
 4850                    trigger_in_words,
 4851                    completions_source.is_some(),
 4852                    cx,
 4853                ) =>
 4854            {
 4855                self.show_completions(
 4856                    &ShowCompletions {
 4857                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4858                    },
 4859                    window,
 4860                    cx,
 4861                )
 4862            }
 4863            _ => {
 4864                self.hide_context_menu(window, cx);
 4865            }
 4866        }
 4867    }
 4868
 4869    fn is_completion_trigger(
 4870        &self,
 4871        text: &str,
 4872        trigger_in_words: bool,
 4873        menu_is_open: bool,
 4874        cx: &mut Context<Self>,
 4875    ) -> bool {
 4876        let position = self.selections.newest_anchor().head();
 4877        let multibuffer = self.buffer.read(cx);
 4878        let Some(buffer) = position
 4879            .buffer_id
 4880            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4881        else {
 4882            return false;
 4883        };
 4884
 4885        if let Some(completion_provider) = &self.completion_provider {
 4886            completion_provider.is_completion_trigger(
 4887                &buffer,
 4888                position.text_anchor,
 4889                text,
 4890                trigger_in_words,
 4891                menu_is_open,
 4892                cx,
 4893            )
 4894        } else {
 4895            false
 4896        }
 4897    }
 4898
 4899    /// If any empty selections is touching the start of its innermost containing autoclose
 4900    /// region, expand it to select the brackets.
 4901    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4902        let selections = self.selections.all::<usize>(cx);
 4903        let buffer = self.buffer.read(cx).read(cx);
 4904        let new_selections = self
 4905            .selections_with_autoclose_regions(selections, &buffer)
 4906            .map(|(mut selection, region)| {
 4907                if !selection.is_empty() {
 4908                    return selection;
 4909                }
 4910
 4911                if let Some(region) = region {
 4912                    let mut range = region.range.to_offset(&buffer);
 4913                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4914                        range.start -= region.pair.start.len();
 4915                        if buffer.contains_str_at(range.start, &region.pair.start)
 4916                            && buffer.contains_str_at(range.end, &region.pair.end)
 4917                        {
 4918                            range.end += region.pair.end.len();
 4919                            selection.start = range.start;
 4920                            selection.end = range.end;
 4921
 4922                            return selection;
 4923                        }
 4924                    }
 4925                }
 4926
 4927                let always_treat_brackets_as_autoclosed = buffer
 4928                    .language_settings_at(selection.start, cx)
 4929                    .always_treat_brackets_as_autoclosed;
 4930
 4931                if !always_treat_brackets_as_autoclosed {
 4932                    return selection;
 4933                }
 4934
 4935                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4936                    for (pair, enabled) in scope.brackets() {
 4937                        if !enabled || !pair.close {
 4938                            continue;
 4939                        }
 4940
 4941                        if buffer.contains_str_at(selection.start, &pair.end) {
 4942                            let pair_start_len = pair.start.len();
 4943                            if buffer.contains_str_at(
 4944                                selection.start.saturating_sub(pair_start_len),
 4945                                &pair.start,
 4946                            ) {
 4947                                selection.start -= pair_start_len;
 4948                                selection.end += pair.end.len();
 4949
 4950                                return selection;
 4951                            }
 4952                        }
 4953                    }
 4954                }
 4955
 4956                selection
 4957            })
 4958            .collect();
 4959
 4960        drop(buffer);
 4961        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4962            selections.select(new_selections)
 4963        });
 4964    }
 4965
 4966    /// Iterate the given selections, and for each one, find the smallest surrounding
 4967    /// autoclose region. This uses the ordering of the selections and the autoclose
 4968    /// regions to avoid repeated comparisons.
 4969    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4970        &'a self,
 4971        selections: impl IntoIterator<Item = Selection<D>>,
 4972        buffer: &'a MultiBufferSnapshot,
 4973    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4974        let mut i = 0;
 4975        let mut regions = self.autoclose_regions.as_slice();
 4976        selections.into_iter().map(move |selection| {
 4977            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4978
 4979            let mut enclosing = None;
 4980            while let Some(pair_state) = regions.get(i) {
 4981                if pair_state.range.end.to_offset(buffer) < range.start {
 4982                    regions = &regions[i + 1..];
 4983                    i = 0;
 4984                } else if pair_state.range.start.to_offset(buffer) > range.end {
 4985                    break;
 4986                } else {
 4987                    if pair_state.selection_id == selection.id {
 4988                        enclosing = Some(pair_state);
 4989                    }
 4990                    i += 1;
 4991                }
 4992            }
 4993
 4994            (selection, enclosing)
 4995        })
 4996    }
 4997
 4998    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 4999    fn invalidate_autoclose_regions(
 5000        &mut self,
 5001        mut selections: &[Selection<Anchor>],
 5002        buffer: &MultiBufferSnapshot,
 5003    ) {
 5004        self.autoclose_regions.retain(|state| {
 5005            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5006                return false;
 5007            }
 5008
 5009            let mut i = 0;
 5010            while let Some(selection) = selections.get(i) {
 5011                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5012                    selections = &selections[1..];
 5013                    continue;
 5014                }
 5015                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5016                    break;
 5017                }
 5018                if selection.id == state.selection_id {
 5019                    return true;
 5020                } else {
 5021                    i += 1;
 5022                }
 5023            }
 5024            false
 5025        });
 5026    }
 5027
 5028    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5029        let offset = position.to_offset(buffer);
 5030        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5031        if offset > word_range.start && kind == Some(CharKind::Word) {
 5032            Some(
 5033                buffer
 5034                    .text_for_range(word_range.start..offset)
 5035                    .collect::<String>(),
 5036            )
 5037        } else {
 5038            None
 5039        }
 5040    }
 5041
 5042    pub fn toggle_inline_values(
 5043        &mut self,
 5044        _: &ToggleInlineValues,
 5045        _: &mut Window,
 5046        cx: &mut Context<Self>,
 5047    ) {
 5048        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5049
 5050        self.refresh_inline_values(cx);
 5051    }
 5052
 5053    pub fn toggle_inlay_hints(
 5054        &mut self,
 5055        _: &ToggleInlayHints,
 5056        _: &mut Window,
 5057        cx: &mut Context<Self>,
 5058    ) {
 5059        self.refresh_inlay_hints(
 5060            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5061            cx,
 5062        );
 5063    }
 5064
 5065    pub fn inlay_hints_enabled(&self) -> bool {
 5066        self.inlay_hint_cache.enabled
 5067    }
 5068
 5069    pub fn inline_values_enabled(&self) -> bool {
 5070        self.inline_value_cache.enabled
 5071    }
 5072
 5073    #[cfg(any(test, feature = "test-support"))]
 5074    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5075        self.display_map
 5076            .read(cx)
 5077            .current_inlays()
 5078            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5079            .cloned()
 5080            .collect()
 5081    }
 5082
 5083    #[cfg(any(test, feature = "test-support"))]
 5084    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5085        self.display_map
 5086            .read(cx)
 5087            .current_inlays()
 5088            .cloned()
 5089            .collect()
 5090    }
 5091
 5092    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5093        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5094            return;
 5095        }
 5096
 5097        let reason_description = reason.description();
 5098        let ignore_debounce = matches!(
 5099            reason,
 5100            InlayHintRefreshReason::SettingsChange(_)
 5101                | InlayHintRefreshReason::Toggle(_)
 5102                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5103                | InlayHintRefreshReason::ModifiersChanged(_)
 5104        );
 5105        let (invalidate_cache, required_languages) = match reason {
 5106            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5107                match self.inlay_hint_cache.modifiers_override(enabled) {
 5108                    Some(enabled) => {
 5109                        if enabled {
 5110                            (InvalidationStrategy::RefreshRequested, None)
 5111                        } else {
 5112                            self.splice_inlays(
 5113                                &self
 5114                                    .visible_inlay_hints(cx)
 5115                                    .iter()
 5116                                    .map(|inlay| inlay.id)
 5117                                    .collect::<Vec<InlayId>>(),
 5118                                Vec::new(),
 5119                                cx,
 5120                            );
 5121                            return;
 5122                        }
 5123                    }
 5124                    None => return,
 5125                }
 5126            }
 5127            InlayHintRefreshReason::Toggle(enabled) => {
 5128                if self.inlay_hint_cache.toggle(enabled) {
 5129                    if enabled {
 5130                        (InvalidationStrategy::RefreshRequested, None)
 5131                    } else {
 5132                        self.splice_inlays(
 5133                            &self
 5134                                .visible_inlay_hints(cx)
 5135                                .iter()
 5136                                .map(|inlay| inlay.id)
 5137                                .collect::<Vec<InlayId>>(),
 5138                            Vec::new(),
 5139                            cx,
 5140                        );
 5141                        return;
 5142                    }
 5143                } else {
 5144                    return;
 5145                }
 5146            }
 5147            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5148                match self.inlay_hint_cache.update_settings(
 5149                    &self.buffer,
 5150                    new_settings,
 5151                    self.visible_inlay_hints(cx),
 5152                    cx,
 5153                ) {
 5154                    ControlFlow::Break(Some(InlaySplice {
 5155                        to_remove,
 5156                        to_insert,
 5157                    })) => {
 5158                        self.splice_inlays(&to_remove, to_insert, cx);
 5159                        return;
 5160                    }
 5161                    ControlFlow::Break(None) => return,
 5162                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5163                }
 5164            }
 5165            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5166                if let Some(InlaySplice {
 5167                    to_remove,
 5168                    to_insert,
 5169                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5170                {
 5171                    self.splice_inlays(&to_remove, to_insert, cx);
 5172                }
 5173                self.display_map.update(cx, |display_map, _| {
 5174                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5175                });
 5176                return;
 5177            }
 5178            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5179            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5180                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5181            }
 5182            InlayHintRefreshReason::RefreshRequested => {
 5183                (InvalidationStrategy::RefreshRequested, None)
 5184            }
 5185        };
 5186
 5187        if let Some(InlaySplice {
 5188            to_remove,
 5189            to_insert,
 5190        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5191            reason_description,
 5192            self.visible_excerpts(required_languages.as_ref(), cx),
 5193            invalidate_cache,
 5194            ignore_debounce,
 5195            cx,
 5196        ) {
 5197            self.splice_inlays(&to_remove, to_insert, cx);
 5198        }
 5199    }
 5200
 5201    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5202        self.display_map
 5203            .read(cx)
 5204            .current_inlays()
 5205            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5206            .cloned()
 5207            .collect()
 5208    }
 5209
 5210    pub fn visible_excerpts(
 5211        &self,
 5212        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5213        cx: &mut Context<Editor>,
 5214    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5215        let Some(project) = self.project.as_ref() else {
 5216            return HashMap::default();
 5217        };
 5218        let project = project.read(cx);
 5219        let multi_buffer = self.buffer().read(cx);
 5220        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5221        let multi_buffer_visible_start = self
 5222            .scroll_manager
 5223            .anchor()
 5224            .anchor
 5225            .to_point(&multi_buffer_snapshot);
 5226        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5227            multi_buffer_visible_start
 5228                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5229            Bias::Left,
 5230        );
 5231        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5232        multi_buffer_snapshot
 5233            .range_to_buffer_ranges(multi_buffer_visible_range)
 5234            .into_iter()
 5235            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5236            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5237                let buffer_file = project::File::from_dyn(buffer.file())?;
 5238                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5239                let worktree_entry = buffer_worktree
 5240                    .read(cx)
 5241                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5242                if worktree_entry.is_ignored {
 5243                    return None;
 5244                }
 5245
 5246                let language = buffer.language()?;
 5247                if let Some(restrict_to_languages) = restrict_to_languages {
 5248                    if !restrict_to_languages.contains(language) {
 5249                        return None;
 5250                    }
 5251                }
 5252                Some((
 5253                    excerpt_id,
 5254                    (
 5255                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5256                        buffer.version().clone(),
 5257                        excerpt_visible_range,
 5258                    ),
 5259                ))
 5260            })
 5261            .collect()
 5262    }
 5263
 5264    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5265        TextLayoutDetails {
 5266            text_system: window.text_system().clone(),
 5267            editor_style: self.style.clone().unwrap(),
 5268            rem_size: window.rem_size(),
 5269            scroll_anchor: self.scroll_manager.anchor(),
 5270            visible_rows: self.visible_line_count(),
 5271            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5272        }
 5273    }
 5274
 5275    pub fn splice_inlays(
 5276        &self,
 5277        to_remove: &[InlayId],
 5278        to_insert: Vec<Inlay>,
 5279        cx: &mut Context<Self>,
 5280    ) {
 5281        self.display_map.update(cx, |display_map, cx| {
 5282            display_map.splice_inlays(to_remove, to_insert, cx)
 5283        });
 5284        cx.notify();
 5285    }
 5286
 5287    fn trigger_on_type_formatting(
 5288        &self,
 5289        input: String,
 5290        window: &mut Window,
 5291        cx: &mut Context<Self>,
 5292    ) -> Option<Task<Result<()>>> {
 5293        if input.len() != 1 {
 5294            return None;
 5295        }
 5296
 5297        let project = self.project.as_ref()?;
 5298        let position = self.selections.newest_anchor().head();
 5299        let (buffer, buffer_position) = self
 5300            .buffer
 5301            .read(cx)
 5302            .text_anchor_for_position(position, cx)?;
 5303
 5304        let settings = language_settings::language_settings(
 5305            buffer
 5306                .read(cx)
 5307                .language_at(buffer_position)
 5308                .map(|l| l.name()),
 5309            buffer.read(cx).file(),
 5310            cx,
 5311        );
 5312        if !settings.use_on_type_format {
 5313            return None;
 5314        }
 5315
 5316        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5317        // hence we do LSP request & edit on host side only — add formats to host's history.
 5318        let push_to_lsp_host_history = true;
 5319        // If this is not the host, append its history with new edits.
 5320        let push_to_client_history = project.read(cx).is_via_collab();
 5321
 5322        let on_type_formatting = project.update(cx, |project, cx| {
 5323            project.on_type_format(
 5324                buffer.clone(),
 5325                buffer_position,
 5326                input,
 5327                push_to_lsp_host_history,
 5328                cx,
 5329            )
 5330        });
 5331        Some(cx.spawn_in(window, async move |editor, cx| {
 5332            if let Some(transaction) = on_type_formatting.await? {
 5333                if push_to_client_history {
 5334                    buffer
 5335                        .update(cx, |buffer, _| {
 5336                            buffer.push_transaction(transaction, Instant::now());
 5337                            buffer.finalize_last_transaction();
 5338                        })
 5339                        .ok();
 5340                }
 5341                editor.update(cx, |editor, cx| {
 5342                    editor.refresh_document_highlights(cx);
 5343                })?;
 5344            }
 5345            Ok(())
 5346        }))
 5347    }
 5348
 5349    pub fn show_word_completions(
 5350        &mut self,
 5351        _: &ShowWordCompletions,
 5352        window: &mut Window,
 5353        cx: &mut Context<Self>,
 5354    ) {
 5355        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5356    }
 5357
 5358    pub fn show_completions(
 5359        &mut self,
 5360        options: &ShowCompletions,
 5361        window: &mut Window,
 5362        cx: &mut Context<Self>,
 5363    ) {
 5364        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5365    }
 5366
 5367    fn open_or_update_completions_menu(
 5368        &mut self,
 5369        requested_source: Option<CompletionsMenuSource>,
 5370        trigger: Option<&str>,
 5371        window: &mut Window,
 5372        cx: &mut Context<Self>,
 5373    ) {
 5374        if self.pending_rename.is_some() {
 5375            return;
 5376        }
 5377
 5378        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5379
 5380        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5381        // inserted and selected. To handle that case, the start of the selection is used so that
 5382        // the menu starts with all choices.
 5383        let position = self
 5384            .selections
 5385            .newest_anchor()
 5386            .start
 5387            .bias_right(&multibuffer_snapshot);
 5388        if position.diff_base_anchor.is_some() {
 5389            return;
 5390        }
 5391        let (buffer, buffer_position) =
 5392            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5393                output
 5394            } else {
 5395                return;
 5396            };
 5397        let buffer_snapshot = buffer.read(cx).snapshot();
 5398
 5399        let query: Option<Arc<String>> =
 5400            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5401
 5402        drop(multibuffer_snapshot);
 5403
 5404        let provider = match requested_source {
 5405            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5406            Some(CompletionsMenuSource::Words) => None,
 5407            Some(CompletionsMenuSource::SnippetChoices) => {
 5408                log::error!("bug: SnippetChoices requested_source is not handled");
 5409                None
 5410            }
 5411        };
 5412
 5413        let sort_completions = provider
 5414            .as_ref()
 5415            .map_or(false, |provider| provider.sort_completions());
 5416
 5417        let filter_completions = provider
 5418            .as_ref()
 5419            .map_or(true, |provider| provider.filter_completions());
 5420
 5421        let trigger_kind = match trigger {
 5422            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5423                CompletionTriggerKind::TRIGGER_CHARACTER
 5424            }
 5425            _ => CompletionTriggerKind::INVOKED,
 5426        };
 5427        let completion_context = CompletionContext {
 5428            trigger_character: trigger.and_then(|trigger| {
 5429                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5430                    Some(String::from(trigger))
 5431                } else {
 5432                    None
 5433                }
 5434            }),
 5435            trigger_kind,
 5436        };
 5437
 5438        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5439        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5440        // involve trigger chars, so this is skipped in that case.
 5441        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5442        {
 5443            let menu_is_open = matches!(
 5444                self.context_menu.borrow().as_ref(),
 5445                Some(CodeContextMenu::Completions(_))
 5446            );
 5447            if menu_is_open {
 5448                self.hide_context_menu(window, cx);
 5449            }
 5450        }
 5451
 5452        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5453            if filter_completions {
 5454                menu.filter(query.clone(), provider.clone(), window, cx);
 5455            }
 5456            // When `is_incomplete` is false, no need to re-query completions when the current query
 5457            // is a suffix of the initial query.
 5458            if !menu.is_incomplete {
 5459                // If the new query is a suffix of the old query (typing more characters) and
 5460                // the previous result was complete, the existing completions can be filtered.
 5461                //
 5462                // Note that this is always true for snippet completions.
 5463                let query_matches = match (&menu.initial_query, &query) {
 5464                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5465                    (None, _) => true,
 5466                    _ => false,
 5467                };
 5468                if query_matches {
 5469                    let position_matches = if menu.initial_position == position {
 5470                        true
 5471                    } else {
 5472                        let snapshot = self.buffer.read(cx).read(cx);
 5473                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5474                    };
 5475                    if position_matches {
 5476                        return;
 5477                    }
 5478                }
 5479            }
 5480        };
 5481
 5482        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5483            buffer_snapshot.surrounding_word(buffer_position, false)
 5484        {
 5485            let word_to_exclude = buffer_snapshot
 5486                .text_for_range(word_range.clone())
 5487                .collect::<String>();
 5488            (
 5489                buffer_snapshot.anchor_before(word_range.start)
 5490                    ..buffer_snapshot.anchor_after(buffer_position),
 5491                Some(word_to_exclude),
 5492            )
 5493        } else {
 5494            (buffer_position..buffer_position, None)
 5495        };
 5496
 5497        let language = buffer_snapshot
 5498            .language_at(buffer_position)
 5499            .map(|language| language.name());
 5500
 5501        let completion_settings =
 5502            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5503
 5504        let show_completion_documentation = buffer_snapshot
 5505            .settings_at(buffer_position, cx)
 5506            .show_completion_documentation;
 5507
 5508        // The document can be large, so stay in reasonable bounds when searching for words,
 5509        // otherwise completion pop-up might be slow to appear.
 5510        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5511        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5512        let min_word_search = buffer_snapshot.clip_point(
 5513            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5514            Bias::Left,
 5515        );
 5516        let max_word_search = buffer_snapshot.clip_point(
 5517            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5518            Bias::Right,
 5519        );
 5520        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5521            ..buffer_snapshot.point_to_offset(max_word_search);
 5522
 5523        let skip_digits = query
 5524            .as_ref()
 5525            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5526
 5527        let (mut words, provider_responses) = match &provider {
 5528            Some(provider) => {
 5529                let provider_responses = provider.completions(
 5530                    position.excerpt_id,
 5531                    &buffer,
 5532                    buffer_position,
 5533                    completion_context,
 5534                    window,
 5535                    cx,
 5536                );
 5537
 5538                let words = match completion_settings.words {
 5539                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5540                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5541                        .background_spawn(async move {
 5542                            buffer_snapshot.words_in_range(WordsQuery {
 5543                                fuzzy_contents: None,
 5544                                range: word_search_range,
 5545                                skip_digits,
 5546                            })
 5547                        }),
 5548                };
 5549
 5550                (words, provider_responses)
 5551            }
 5552            None => (
 5553                cx.background_spawn(async move {
 5554                    buffer_snapshot.words_in_range(WordsQuery {
 5555                        fuzzy_contents: None,
 5556                        range: word_search_range,
 5557                        skip_digits,
 5558                    })
 5559                }),
 5560                Task::ready(Ok(Vec::new())),
 5561            ),
 5562        };
 5563
 5564        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5565
 5566        let id = post_inc(&mut self.next_completion_id);
 5567        let task = cx.spawn_in(window, async move |editor, cx| {
 5568            let Ok(()) = editor.update(cx, |this, _| {
 5569                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5570            }) else {
 5571                return;
 5572            };
 5573
 5574            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5575            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5576            let mut completions = Vec::new();
 5577            let mut is_incomplete = false;
 5578            if let Some(provider_responses) = provider_responses.await.log_err() {
 5579                if !provider_responses.is_empty() {
 5580                    for response in provider_responses {
 5581                        completions.extend(response.completions);
 5582                        is_incomplete = is_incomplete || response.is_incomplete;
 5583                    }
 5584                    if completion_settings.words == WordsCompletionMode::Fallback {
 5585                        words = Task::ready(BTreeMap::default());
 5586                    }
 5587                }
 5588            }
 5589
 5590            let mut words = words.await;
 5591            if let Some(word_to_exclude) = &word_to_exclude {
 5592                words.remove(word_to_exclude);
 5593            }
 5594            for lsp_completion in &completions {
 5595                words.remove(&lsp_completion.new_text);
 5596            }
 5597            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5598                replace_range: word_replace_range.clone(),
 5599                new_text: word.clone(),
 5600                label: CodeLabel::plain(word, None),
 5601                icon_path: None,
 5602                documentation: None,
 5603                source: CompletionSource::BufferWord {
 5604                    word_range,
 5605                    resolved: false,
 5606                },
 5607                insert_text_mode: Some(InsertTextMode::AS_IS),
 5608                confirm: None,
 5609            }));
 5610
 5611            let menu = if completions.is_empty() {
 5612                None
 5613            } else {
 5614                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5615                    let languages = editor
 5616                        .workspace
 5617                        .as_ref()
 5618                        .and_then(|(workspace, _)| workspace.upgrade())
 5619                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5620                    let menu = CompletionsMenu::new(
 5621                        id,
 5622                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5623                        sort_completions,
 5624                        show_completion_documentation,
 5625                        position,
 5626                        query.clone(),
 5627                        is_incomplete,
 5628                        buffer.clone(),
 5629                        completions.into(),
 5630                        snippet_sort_order,
 5631                        languages,
 5632                        language,
 5633                        cx,
 5634                    );
 5635
 5636                    let query = if filter_completions { query } else { None };
 5637                    let matches_task = if let Some(query) = query {
 5638                        menu.do_async_filtering(query, cx)
 5639                    } else {
 5640                        Task::ready(menu.unfiltered_matches())
 5641                    };
 5642                    (menu, matches_task)
 5643                }) else {
 5644                    return;
 5645                };
 5646
 5647                let matches = matches_task.await;
 5648
 5649                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5650                    // Newer menu already set, so exit.
 5651                    match editor.context_menu.borrow().as_ref() {
 5652                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5653                            if prev_menu.id > id {
 5654                                return;
 5655                            }
 5656                        }
 5657                        _ => {}
 5658                    };
 5659
 5660                    // Only valid to take prev_menu because it the new menu is immediately set
 5661                    // below, or the menu is hidden.
 5662                    match editor.context_menu.borrow_mut().take() {
 5663                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5664                            let position_matches =
 5665                                if prev_menu.initial_position == menu.initial_position {
 5666                                    true
 5667                                } else {
 5668                                    let snapshot = editor.buffer.read(cx).read(cx);
 5669                                    prev_menu.initial_position.to_offset(&snapshot)
 5670                                        == menu.initial_position.to_offset(&snapshot)
 5671                                };
 5672                            if position_matches {
 5673                                // Preserve markdown cache before `set_filter_results` because it will
 5674                                // try to populate the documentation cache.
 5675                                menu.preserve_markdown_cache(prev_menu);
 5676                            }
 5677                        }
 5678                        _ => {}
 5679                    };
 5680
 5681                    menu.set_filter_results(matches, provider, window, cx);
 5682                }) else {
 5683                    return;
 5684                };
 5685
 5686                menu.visible().then_some(menu)
 5687            };
 5688
 5689            editor
 5690                .update_in(cx, |editor, window, cx| {
 5691                    if editor.focus_handle.is_focused(window) {
 5692                        if let Some(menu) = menu {
 5693                            *editor.context_menu.borrow_mut() =
 5694                                Some(CodeContextMenu::Completions(menu));
 5695
 5696                            crate::hover_popover::hide_hover(editor, cx);
 5697                            if editor.show_edit_predictions_in_menu() {
 5698                                editor.update_visible_edit_prediction(window, cx);
 5699                            } else {
 5700                                editor.discard_edit_prediction(false, cx);
 5701                            }
 5702
 5703                            cx.notify();
 5704                            return;
 5705                        }
 5706                    }
 5707
 5708                    if editor.completion_tasks.len() <= 1 {
 5709                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5710                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5711                        // If it was already hidden and we don't show edit predictions in the menu,
 5712                        // we should also show the edit prediction when available.
 5713                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5714                            editor.update_visible_edit_prediction(window, cx);
 5715                        }
 5716                    }
 5717                })
 5718                .ok();
 5719        });
 5720
 5721        self.completion_tasks.push((id, task));
 5722    }
 5723
 5724    #[cfg(feature = "test-support")]
 5725    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5726        let menu = self.context_menu.borrow();
 5727        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5728            let completions = menu.completions.borrow();
 5729            Some(completions.to_vec())
 5730        } else {
 5731            None
 5732        }
 5733    }
 5734
 5735    pub fn with_completions_menu_matching_id<R>(
 5736        &self,
 5737        id: CompletionId,
 5738        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5739    ) -> R {
 5740        let mut context_menu = self.context_menu.borrow_mut();
 5741        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5742            return f(None);
 5743        };
 5744        if completions_menu.id != id {
 5745            return f(None);
 5746        }
 5747        f(Some(completions_menu))
 5748    }
 5749
 5750    pub fn confirm_completion(
 5751        &mut self,
 5752        action: &ConfirmCompletion,
 5753        window: &mut Window,
 5754        cx: &mut Context<Self>,
 5755    ) -> Option<Task<Result<()>>> {
 5756        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5757        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5758    }
 5759
 5760    pub fn confirm_completion_insert(
 5761        &mut self,
 5762        _: &ConfirmCompletionInsert,
 5763        window: &mut Window,
 5764        cx: &mut Context<Self>,
 5765    ) -> Option<Task<Result<()>>> {
 5766        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5767        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5768    }
 5769
 5770    pub fn confirm_completion_replace(
 5771        &mut self,
 5772        _: &ConfirmCompletionReplace,
 5773        window: &mut Window,
 5774        cx: &mut Context<Self>,
 5775    ) -> Option<Task<Result<()>>> {
 5776        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5777        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5778    }
 5779
 5780    pub fn compose_completion(
 5781        &mut self,
 5782        action: &ComposeCompletion,
 5783        window: &mut Window,
 5784        cx: &mut Context<Self>,
 5785    ) -> Option<Task<Result<()>>> {
 5786        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5787        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5788    }
 5789
 5790    fn do_completion(
 5791        &mut self,
 5792        item_ix: Option<usize>,
 5793        intent: CompletionIntent,
 5794        window: &mut Window,
 5795        cx: &mut Context<Editor>,
 5796    ) -> Option<Task<Result<()>>> {
 5797        use language::ToOffset as _;
 5798
 5799        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5800        else {
 5801            return None;
 5802        };
 5803
 5804        let candidate_id = {
 5805            let entries = completions_menu.entries.borrow();
 5806            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5807            if self.show_edit_predictions_in_menu() {
 5808                self.discard_edit_prediction(true, cx);
 5809            }
 5810            mat.candidate_id
 5811        };
 5812
 5813        let completion = completions_menu
 5814            .completions
 5815            .borrow()
 5816            .get(candidate_id)?
 5817            .clone();
 5818        cx.stop_propagation();
 5819
 5820        let buffer_handle = completions_menu.buffer.clone();
 5821
 5822        let CompletionEdit {
 5823            new_text,
 5824            snippet,
 5825            replace_range,
 5826        } = process_completion_for_edit(
 5827            &completion,
 5828            intent,
 5829            &buffer_handle,
 5830            &completions_menu.initial_position.text_anchor,
 5831            cx,
 5832        );
 5833
 5834        let buffer = buffer_handle.read(cx);
 5835        let snapshot = self.buffer.read(cx).snapshot(cx);
 5836        let newest_anchor = self.selections.newest_anchor();
 5837        let replace_range_multibuffer = {
 5838            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5839            let multibuffer_anchor = snapshot
 5840                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5841                .unwrap()
 5842                ..snapshot
 5843                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5844                    .unwrap();
 5845            multibuffer_anchor.start.to_offset(&snapshot)
 5846                ..multibuffer_anchor.end.to_offset(&snapshot)
 5847        };
 5848        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5849            return None;
 5850        }
 5851
 5852        let old_text = buffer
 5853            .text_for_range(replace_range.clone())
 5854            .collect::<String>();
 5855        let lookbehind = newest_anchor
 5856            .start
 5857            .text_anchor
 5858            .to_offset(buffer)
 5859            .saturating_sub(replace_range.start);
 5860        let lookahead = replace_range
 5861            .end
 5862            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5863        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5864        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5865
 5866        let selections = self.selections.all::<usize>(cx);
 5867        let mut ranges = Vec::new();
 5868        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5869
 5870        for selection in &selections {
 5871            let range = if selection.id == newest_anchor.id {
 5872                replace_range_multibuffer.clone()
 5873            } else {
 5874                let mut range = selection.range();
 5875
 5876                // if prefix is present, don't duplicate it
 5877                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5878                    range.start = range.start.saturating_sub(lookbehind);
 5879
 5880                    // if suffix is also present, mimic the newest cursor and replace it
 5881                    if selection.id != newest_anchor.id
 5882                        && snapshot.contains_str_at(range.end, suffix)
 5883                    {
 5884                        range.end += lookahead;
 5885                    }
 5886                }
 5887                range
 5888            };
 5889
 5890            ranges.push(range.clone());
 5891
 5892            if !self.linked_edit_ranges.is_empty() {
 5893                let start_anchor = snapshot.anchor_before(range.start);
 5894                let end_anchor = snapshot.anchor_after(range.end);
 5895                if let Some(ranges) = self
 5896                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5897                {
 5898                    for (buffer, edits) in ranges {
 5899                        linked_edits
 5900                            .entry(buffer.clone())
 5901                            .or_default()
 5902                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5903                    }
 5904                }
 5905            }
 5906        }
 5907
 5908        let common_prefix_len = old_text
 5909            .chars()
 5910            .zip(new_text.chars())
 5911            .take_while(|(a, b)| a == b)
 5912            .map(|(a, _)| a.len_utf8())
 5913            .sum::<usize>();
 5914
 5915        cx.emit(EditorEvent::InputHandled {
 5916            utf16_range_to_replace: None,
 5917            text: new_text[common_prefix_len..].into(),
 5918        });
 5919
 5920        self.transact(window, cx, |editor, window, cx| {
 5921            if let Some(mut snippet) = snippet {
 5922                snippet.text = new_text.to_string();
 5923                editor
 5924                    .insert_snippet(&ranges, snippet, window, cx)
 5925                    .log_err();
 5926            } else {
 5927                editor.buffer.update(cx, |multi_buffer, cx| {
 5928                    let auto_indent = match completion.insert_text_mode {
 5929                        Some(InsertTextMode::AS_IS) => None,
 5930                        _ => editor.autoindent_mode.clone(),
 5931                    };
 5932                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5933                    multi_buffer.edit(edits, auto_indent, cx);
 5934                });
 5935            }
 5936            for (buffer, edits) in linked_edits {
 5937                buffer.update(cx, |buffer, cx| {
 5938                    let snapshot = buffer.snapshot();
 5939                    let edits = edits
 5940                        .into_iter()
 5941                        .map(|(range, text)| {
 5942                            use text::ToPoint as TP;
 5943                            let end_point = TP::to_point(&range.end, &snapshot);
 5944                            let start_point = TP::to_point(&range.start, &snapshot);
 5945                            (start_point..end_point, text)
 5946                        })
 5947                        .sorted_by_key(|(range, _)| range.start);
 5948                    buffer.edit(edits, None, cx);
 5949                })
 5950            }
 5951
 5952            editor.refresh_edit_prediction(true, false, window, cx);
 5953        });
 5954        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 5955
 5956        let show_new_completions_on_confirm = completion
 5957            .confirm
 5958            .as_ref()
 5959            .map_or(false, |confirm| confirm(intent, window, cx));
 5960        if show_new_completions_on_confirm {
 5961            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5962        }
 5963
 5964        let provider = self.completion_provider.as_ref()?;
 5965        drop(completion);
 5966        let apply_edits = provider.apply_additional_edits_for_completion(
 5967            buffer_handle,
 5968            completions_menu.completions.clone(),
 5969            candidate_id,
 5970            true,
 5971            cx,
 5972        );
 5973
 5974        let editor_settings = EditorSettings::get_global(cx);
 5975        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5976            // After the code completion is finished, users often want to know what signatures are needed.
 5977            // so we should automatically call signature_help
 5978            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5979        }
 5980
 5981        Some(cx.foreground_executor().spawn(async move {
 5982            apply_edits.await?;
 5983            Ok(())
 5984        }))
 5985    }
 5986
 5987    pub fn toggle_code_actions(
 5988        &mut self,
 5989        action: &ToggleCodeActions,
 5990        window: &mut Window,
 5991        cx: &mut Context<Self>,
 5992    ) {
 5993        let quick_launch = action.quick_launch;
 5994        let mut context_menu = self.context_menu.borrow_mut();
 5995        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5996            if code_actions.deployed_from == action.deployed_from {
 5997                // Toggle if we're selecting the same one
 5998                *context_menu = None;
 5999                cx.notify();
 6000                return;
 6001            } else {
 6002                // Otherwise, clear it and start a new one
 6003                *context_menu = None;
 6004                cx.notify();
 6005            }
 6006        }
 6007        drop(context_menu);
 6008        let snapshot = self.snapshot(window, cx);
 6009        let deployed_from = action.deployed_from.clone();
 6010        let action = action.clone();
 6011        self.completion_tasks.clear();
 6012        self.discard_edit_prediction(false, cx);
 6013
 6014        let multibuffer_point = match &action.deployed_from {
 6015            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6016                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6017            }
 6018            _ => self.selections.newest::<Point>(cx).head(),
 6019        };
 6020        let Some((buffer, buffer_row)) = snapshot
 6021            .buffer_snapshot
 6022            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6023            .and_then(|(buffer_snapshot, range)| {
 6024                self.buffer()
 6025                    .read(cx)
 6026                    .buffer(buffer_snapshot.remote_id())
 6027                    .map(|buffer| (buffer, range.start.row))
 6028            })
 6029        else {
 6030            return;
 6031        };
 6032        let buffer_id = buffer.read(cx).remote_id();
 6033        let tasks = self
 6034            .tasks
 6035            .get(&(buffer_id, buffer_row))
 6036            .map(|t| Arc::new(t.to_owned()));
 6037
 6038        if !self.focus_handle.is_focused(window) {
 6039            return;
 6040        }
 6041        let project = self.project.clone();
 6042
 6043        let code_actions_task = match deployed_from {
 6044            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6045            _ => self.code_actions(buffer_row, window, cx),
 6046        };
 6047
 6048        let runnable_task = match deployed_from {
 6049            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6050            _ => {
 6051                let mut task_context_task = Task::ready(None);
 6052                if let Some(tasks) = &tasks {
 6053                    if let Some(project) = project {
 6054                        task_context_task =
 6055                            Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 6056                    }
 6057                }
 6058
 6059                cx.spawn_in(window, {
 6060                    let buffer = buffer.clone();
 6061                    async move |editor, cx| {
 6062                        let task_context = task_context_task.await;
 6063
 6064                        let resolved_tasks =
 6065                            tasks
 6066                                .zip(task_context.clone())
 6067                                .map(|(tasks, task_context)| ResolvedTasks {
 6068                                    templates: tasks.resolve(&task_context).collect(),
 6069                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6070                                        multibuffer_point.row,
 6071                                        tasks.column,
 6072                                    )),
 6073                                });
 6074                        let debug_scenarios = editor
 6075                            .update(cx, |editor, cx| {
 6076                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6077                            })?
 6078                            .await;
 6079                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6080                    }
 6081                })
 6082            }
 6083        };
 6084
 6085        cx.spawn_in(window, async move |editor, cx| {
 6086            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6087            let code_actions = code_actions_task.await;
 6088            let spawn_straight_away = quick_launch
 6089                && resolved_tasks
 6090                    .as_ref()
 6091                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6092                && code_actions
 6093                    .as_ref()
 6094                    .map_or(true, |actions| actions.is_empty())
 6095                && debug_scenarios.is_empty();
 6096
 6097            editor.update_in(cx, |editor, window, cx| {
 6098                crate::hover_popover::hide_hover(editor, cx);
 6099                let actions = CodeActionContents::new(
 6100                    resolved_tasks,
 6101                    code_actions,
 6102                    debug_scenarios,
 6103                    task_context.unwrap_or_default(),
 6104                );
 6105
 6106                // Don't show the menu if there are no actions available
 6107                if actions.is_empty() {
 6108                    cx.notify();
 6109                    return Task::ready(Ok(()));
 6110                }
 6111
 6112                *editor.context_menu.borrow_mut() =
 6113                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6114                        buffer,
 6115                        actions,
 6116                        selected_item: Default::default(),
 6117                        scroll_handle: UniformListScrollHandle::default(),
 6118                        deployed_from,
 6119                    }));
 6120                cx.notify();
 6121                if spawn_straight_away {
 6122                    if let Some(task) = editor.confirm_code_action(
 6123                        &ConfirmCodeAction { item_ix: Some(0) },
 6124                        window,
 6125                        cx,
 6126                    ) {
 6127                        return task;
 6128                    }
 6129                }
 6130
 6131                Task::ready(Ok(()))
 6132            })
 6133        })
 6134        .detach_and_log_err(cx);
 6135    }
 6136
 6137    fn debug_scenarios(
 6138        &mut self,
 6139        resolved_tasks: &Option<ResolvedTasks>,
 6140        buffer: &Entity<Buffer>,
 6141        cx: &mut App,
 6142    ) -> Task<Vec<task::DebugScenario>> {
 6143        maybe!({
 6144            let project = self.project.as_ref()?;
 6145            let dap_store = project.read(cx).dap_store();
 6146            let mut scenarios = vec![];
 6147            let resolved_tasks = resolved_tasks.as_ref()?;
 6148            let buffer = buffer.read(cx);
 6149            let language = buffer.language()?;
 6150            let file = buffer.file();
 6151            let debug_adapter = language_settings(language.name().into(), file, cx)
 6152                .debuggers
 6153                .first()
 6154                .map(SharedString::from)
 6155                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6156
 6157            dap_store.update(cx, |dap_store, cx| {
 6158                for (_, task) in &resolved_tasks.templates {
 6159                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6160                        task.original_task().clone(),
 6161                        debug_adapter.clone().into(),
 6162                        task.display_label().to_owned().into(),
 6163                        cx,
 6164                    );
 6165                    scenarios.push(maybe_scenario);
 6166                }
 6167            });
 6168            Some(cx.background_spawn(async move {
 6169                let scenarios = futures::future::join_all(scenarios)
 6170                    .await
 6171                    .into_iter()
 6172                    .flatten()
 6173                    .collect::<Vec<_>>();
 6174                scenarios
 6175            }))
 6176        })
 6177        .unwrap_or_else(|| Task::ready(vec![]))
 6178    }
 6179
 6180    fn code_actions(
 6181        &mut self,
 6182        buffer_row: u32,
 6183        window: &mut Window,
 6184        cx: &mut Context<Self>,
 6185    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6186        let mut task = self.code_actions_task.take();
 6187        cx.spawn_in(window, async move |editor, cx| {
 6188            while let Some(prev_task) = task {
 6189                prev_task.await.log_err();
 6190                task = editor
 6191                    .update(cx, |this, _| this.code_actions_task.take())
 6192                    .ok()?;
 6193            }
 6194
 6195            editor
 6196                .update(cx, |editor, cx| {
 6197                    editor
 6198                        .available_code_actions
 6199                        .clone()
 6200                        .and_then(|(location, code_actions)| {
 6201                            let snapshot = location.buffer.read(cx).snapshot();
 6202                            let point_range = location.range.to_point(&snapshot);
 6203                            let point_range = point_range.start.row..=point_range.end.row;
 6204                            if point_range.contains(&buffer_row) {
 6205                                Some(code_actions)
 6206                            } else {
 6207                                None
 6208                            }
 6209                        })
 6210                })
 6211                .ok()
 6212                .flatten()
 6213        })
 6214    }
 6215
 6216    pub fn confirm_code_action(
 6217        &mut self,
 6218        action: &ConfirmCodeAction,
 6219        window: &mut Window,
 6220        cx: &mut Context<Self>,
 6221    ) -> Option<Task<Result<()>>> {
 6222        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6223
 6224        let actions_menu =
 6225            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6226                menu
 6227            } else {
 6228                return None;
 6229            };
 6230
 6231        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6232        let action = actions_menu.actions.get(action_ix)?;
 6233        let title = action.label();
 6234        let buffer = actions_menu.buffer;
 6235        let workspace = self.workspace()?;
 6236
 6237        match action {
 6238            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6239                workspace.update(cx, |workspace, cx| {
 6240                    workspace.schedule_resolved_task(
 6241                        task_source_kind,
 6242                        resolved_task,
 6243                        false,
 6244                        window,
 6245                        cx,
 6246                    );
 6247
 6248                    Some(Task::ready(Ok(())))
 6249                })
 6250            }
 6251            CodeActionsItem::CodeAction {
 6252                excerpt_id,
 6253                action,
 6254                provider,
 6255            } => {
 6256                let apply_code_action =
 6257                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6258                let workspace = workspace.downgrade();
 6259                Some(cx.spawn_in(window, async move |editor, cx| {
 6260                    let project_transaction = apply_code_action.await?;
 6261                    Self::open_project_transaction(
 6262                        &editor,
 6263                        workspace,
 6264                        project_transaction,
 6265                        title,
 6266                        cx,
 6267                    )
 6268                    .await
 6269                }))
 6270            }
 6271            CodeActionsItem::DebugScenario(scenario) => {
 6272                let context = actions_menu.actions.context.clone();
 6273
 6274                workspace.update(cx, |workspace, cx| {
 6275                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6276                    workspace.start_debug_session(
 6277                        scenario,
 6278                        context,
 6279                        Some(buffer),
 6280                        None,
 6281                        window,
 6282                        cx,
 6283                    );
 6284                });
 6285                Some(Task::ready(Ok(())))
 6286            }
 6287        }
 6288    }
 6289
 6290    pub async fn open_project_transaction(
 6291        this: &WeakEntity<Editor>,
 6292        workspace: WeakEntity<Workspace>,
 6293        transaction: ProjectTransaction,
 6294        title: String,
 6295        cx: &mut AsyncWindowContext,
 6296    ) -> Result<()> {
 6297        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6298        cx.update(|_, cx| {
 6299            entries.sort_unstable_by_key(|(buffer, _)| {
 6300                buffer.read(cx).file().map(|f| f.path().clone())
 6301            });
 6302        })?;
 6303
 6304        // If the project transaction's edits are all contained within this editor, then
 6305        // avoid opening a new editor to display them.
 6306
 6307        if let Some((buffer, transaction)) = entries.first() {
 6308            if entries.len() == 1 {
 6309                let excerpt = this.update(cx, |editor, cx| {
 6310                    editor
 6311                        .buffer()
 6312                        .read(cx)
 6313                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6314                })?;
 6315                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt {
 6316                    if excerpted_buffer == *buffer {
 6317                        let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6318                            let excerpt_range = excerpt_range.to_offset(buffer);
 6319                            buffer
 6320                                .edited_ranges_for_transaction::<usize>(transaction)
 6321                                .all(|range| {
 6322                                    excerpt_range.start <= range.start
 6323                                        && excerpt_range.end >= range.end
 6324                                })
 6325                        })?;
 6326
 6327                        if all_edits_within_excerpt {
 6328                            return Ok(());
 6329                        }
 6330                    }
 6331                }
 6332            }
 6333        } else {
 6334            return Ok(());
 6335        }
 6336
 6337        let mut ranges_to_highlight = Vec::new();
 6338        let excerpt_buffer = cx.new(|cx| {
 6339            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6340            for (buffer_handle, transaction) in &entries {
 6341                let edited_ranges = buffer_handle
 6342                    .read(cx)
 6343                    .edited_ranges_for_transaction::<Point>(transaction)
 6344                    .collect::<Vec<_>>();
 6345                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6346                    PathKey::for_buffer(buffer_handle, cx),
 6347                    buffer_handle.clone(),
 6348                    edited_ranges,
 6349                    DEFAULT_MULTIBUFFER_CONTEXT,
 6350                    cx,
 6351                );
 6352
 6353                ranges_to_highlight.extend(ranges);
 6354            }
 6355            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6356            multibuffer
 6357        })?;
 6358
 6359        workspace.update_in(cx, |workspace, window, cx| {
 6360            let project = workspace.project().clone();
 6361            let editor =
 6362                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6363            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6364            editor.update(cx, |editor, cx| {
 6365                editor.highlight_background::<Self>(
 6366                    &ranges_to_highlight,
 6367                    |theme| theme.colors().editor_highlighted_line_background,
 6368                    cx,
 6369                );
 6370            });
 6371        })?;
 6372
 6373        Ok(())
 6374    }
 6375
 6376    pub fn clear_code_action_providers(&mut self) {
 6377        self.code_action_providers.clear();
 6378        self.available_code_actions.take();
 6379    }
 6380
 6381    pub fn add_code_action_provider(
 6382        &mut self,
 6383        provider: Rc<dyn CodeActionProvider>,
 6384        window: &mut Window,
 6385        cx: &mut Context<Self>,
 6386    ) {
 6387        if self
 6388            .code_action_providers
 6389            .iter()
 6390            .any(|existing_provider| existing_provider.id() == provider.id())
 6391        {
 6392            return;
 6393        }
 6394
 6395        self.code_action_providers.push(provider);
 6396        self.refresh_code_actions(window, cx);
 6397    }
 6398
 6399    pub fn remove_code_action_provider(
 6400        &mut self,
 6401        id: Arc<str>,
 6402        window: &mut Window,
 6403        cx: &mut Context<Self>,
 6404    ) {
 6405        self.code_action_providers
 6406            .retain(|provider| provider.id() != id);
 6407        self.refresh_code_actions(window, cx);
 6408    }
 6409
 6410    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6411        !self.code_action_providers.is_empty()
 6412            && EditorSettings::get_global(cx).toolbar.code_actions
 6413    }
 6414
 6415    pub fn has_available_code_actions(&self) -> bool {
 6416        self.available_code_actions
 6417            .as_ref()
 6418            .is_some_and(|(_, actions)| !actions.is_empty())
 6419    }
 6420
 6421    fn render_inline_code_actions(
 6422        &self,
 6423        icon_size: ui::IconSize,
 6424        display_row: DisplayRow,
 6425        is_active: bool,
 6426        cx: &mut Context<Self>,
 6427    ) -> AnyElement {
 6428        let show_tooltip = !self.context_menu_visible();
 6429        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6430            .icon_size(icon_size)
 6431            .shape(ui::IconButtonShape::Square)
 6432            .icon_color(ui::Color::Hidden)
 6433            .toggle_state(is_active)
 6434            .when(show_tooltip, |this| {
 6435                this.tooltip({
 6436                    let focus_handle = self.focus_handle.clone();
 6437                    move |window, cx| {
 6438                        Tooltip::for_action_in(
 6439                            "Toggle Code Actions",
 6440                            &ToggleCodeActions {
 6441                                deployed_from: None,
 6442                                quick_launch: false,
 6443                            },
 6444                            &focus_handle,
 6445                            window,
 6446                            cx,
 6447                        )
 6448                    }
 6449                })
 6450            })
 6451            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6452                window.focus(&editor.focus_handle(cx));
 6453                editor.toggle_code_actions(
 6454                    &crate::actions::ToggleCodeActions {
 6455                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6456                            display_row,
 6457                        )),
 6458                        quick_launch: false,
 6459                    },
 6460                    window,
 6461                    cx,
 6462                );
 6463            }))
 6464            .into_any_element()
 6465    }
 6466
 6467    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6468        &self.context_menu
 6469    }
 6470
 6471    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6472        let newest_selection = self.selections.newest_anchor().clone();
 6473        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6474        let buffer = self.buffer.read(cx);
 6475        if newest_selection.head().diff_base_anchor.is_some() {
 6476            return None;
 6477        }
 6478        let (start_buffer, start) =
 6479            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6480        let (end_buffer, end) =
 6481            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6482        if start_buffer != end_buffer {
 6483            return None;
 6484        }
 6485
 6486        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6487            cx.background_executor()
 6488                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6489                .await;
 6490
 6491            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6492                let providers = this.code_action_providers.clone();
 6493                let tasks = this
 6494                    .code_action_providers
 6495                    .iter()
 6496                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6497                    .collect::<Vec<_>>();
 6498                (providers, tasks)
 6499            })?;
 6500
 6501            let mut actions = Vec::new();
 6502            for (provider, provider_actions) in
 6503                providers.into_iter().zip(future::join_all(tasks).await)
 6504            {
 6505                if let Some(provider_actions) = provider_actions.log_err() {
 6506                    actions.extend(provider_actions.into_iter().map(|action| {
 6507                        AvailableCodeAction {
 6508                            excerpt_id: newest_selection.start.excerpt_id,
 6509                            action,
 6510                            provider: provider.clone(),
 6511                        }
 6512                    }));
 6513                }
 6514            }
 6515
 6516            this.update(cx, |this, cx| {
 6517                this.available_code_actions = if actions.is_empty() {
 6518                    None
 6519                } else {
 6520                    Some((
 6521                        Location {
 6522                            buffer: start_buffer,
 6523                            range: start..end,
 6524                        },
 6525                        actions.into(),
 6526                    ))
 6527                };
 6528                cx.notify();
 6529            })
 6530        }));
 6531        None
 6532    }
 6533
 6534    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6535        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6536            self.show_git_blame_inline = false;
 6537
 6538            self.show_git_blame_inline_delay_task =
 6539                Some(cx.spawn_in(window, async move |this, cx| {
 6540                    cx.background_executor().timer(delay).await;
 6541
 6542                    this.update(cx, |this, cx| {
 6543                        this.show_git_blame_inline = true;
 6544                        cx.notify();
 6545                    })
 6546                    .log_err();
 6547                }));
 6548        }
 6549    }
 6550
 6551    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6552        let snapshot = self.snapshot(window, cx);
 6553        let cursor = self.selections.newest::<Point>(cx).head();
 6554        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6555        else {
 6556            return;
 6557        };
 6558
 6559        let Some(blame) = self.blame.as_ref() else {
 6560            return;
 6561        };
 6562
 6563        let row_info = RowInfo {
 6564            buffer_id: Some(buffer.remote_id()),
 6565            buffer_row: Some(point.row),
 6566            ..Default::default()
 6567        };
 6568        let Some(blame_entry) = blame
 6569            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6570            .flatten()
 6571        else {
 6572            return;
 6573        };
 6574
 6575        let anchor = self.selections.newest_anchor().head();
 6576        let position = self.to_pixel_point(anchor, &snapshot, window);
 6577        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6578            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6579        };
 6580    }
 6581
 6582    fn show_blame_popover(
 6583        &mut self,
 6584        blame_entry: &BlameEntry,
 6585        position: gpui::Point<Pixels>,
 6586        ignore_timeout: bool,
 6587        cx: &mut Context<Self>,
 6588    ) {
 6589        if let Some(state) = &mut self.inline_blame_popover {
 6590            state.hide_task.take();
 6591        } else {
 6592            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6593            let blame_entry = blame_entry.clone();
 6594            let show_task = cx.spawn(async move |editor, cx| {
 6595                if !ignore_timeout {
 6596                    cx.background_executor()
 6597                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6598                        .await;
 6599                }
 6600                editor
 6601                    .update(cx, |editor, cx| {
 6602                        editor.inline_blame_popover_show_task.take();
 6603                        let Some(blame) = editor.blame.as_ref() else {
 6604                            return;
 6605                        };
 6606                        let blame = blame.read(cx);
 6607                        let details = blame.details_for_entry(&blame_entry);
 6608                        let markdown = cx.new(|cx| {
 6609                            Markdown::new(
 6610                                details
 6611                                    .as_ref()
 6612                                    .map(|message| message.message.clone())
 6613                                    .unwrap_or_default(),
 6614                                None,
 6615                                None,
 6616                                cx,
 6617                            )
 6618                        });
 6619                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6620                            position,
 6621                            hide_task: None,
 6622                            popover_bounds: None,
 6623                            popover_state: InlineBlamePopoverState {
 6624                                scroll_handle: ScrollHandle::new(),
 6625                                commit_message: details,
 6626                                markdown,
 6627                            },
 6628                            keyboard_grace: ignore_timeout,
 6629                        });
 6630                        cx.notify();
 6631                    })
 6632                    .ok();
 6633            });
 6634            self.inline_blame_popover_show_task = Some(show_task);
 6635        }
 6636    }
 6637
 6638    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6639        self.inline_blame_popover_show_task.take();
 6640        if let Some(state) = &mut self.inline_blame_popover {
 6641            let hide_task = cx.spawn(async move |editor, cx| {
 6642                cx.background_executor()
 6643                    .timer(std::time::Duration::from_millis(100))
 6644                    .await;
 6645                editor
 6646                    .update(cx, |editor, cx| {
 6647                        editor.inline_blame_popover.take();
 6648                        cx.notify();
 6649                    })
 6650                    .ok();
 6651            });
 6652            state.hide_task = Some(hide_task);
 6653        }
 6654    }
 6655
 6656    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6657        if self.pending_rename.is_some() {
 6658            return None;
 6659        }
 6660
 6661        let provider = self.semantics_provider.clone()?;
 6662        let buffer = self.buffer.read(cx);
 6663        let newest_selection = self.selections.newest_anchor().clone();
 6664        let cursor_position = newest_selection.head();
 6665        let (cursor_buffer, cursor_buffer_position) =
 6666            buffer.text_anchor_for_position(cursor_position, cx)?;
 6667        let (tail_buffer, tail_buffer_position) =
 6668            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6669        if cursor_buffer != tail_buffer {
 6670            return None;
 6671        }
 6672
 6673        let snapshot = cursor_buffer.read(cx).snapshot();
 6674        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6675        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6676        if start_word_range != end_word_range {
 6677            self.document_highlights_task.take();
 6678            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6679            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6680            return None;
 6681        }
 6682
 6683        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6684        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6685            cx.background_executor()
 6686                .timer(Duration::from_millis(debounce))
 6687                .await;
 6688
 6689            let highlights = if let Some(highlights) = cx
 6690                .update(|cx| {
 6691                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6692                })
 6693                .ok()
 6694                .flatten()
 6695            {
 6696                highlights.await.log_err()
 6697            } else {
 6698                None
 6699            };
 6700
 6701            if let Some(highlights) = highlights {
 6702                this.update(cx, |this, cx| {
 6703                    if this.pending_rename.is_some() {
 6704                        return;
 6705                    }
 6706
 6707                    let buffer_id = cursor_position.buffer_id;
 6708                    let buffer = this.buffer.read(cx);
 6709                    if !buffer
 6710                        .text_anchor_for_position(cursor_position, cx)
 6711                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6712                    {
 6713                        return;
 6714                    }
 6715
 6716                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6717                    let mut write_ranges = Vec::new();
 6718                    let mut read_ranges = Vec::new();
 6719                    for highlight in highlights {
 6720                        for (excerpt_id, excerpt_range) in
 6721                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6722                        {
 6723                            let start = highlight
 6724                                .range
 6725                                .start
 6726                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6727                            let end = highlight
 6728                                .range
 6729                                .end
 6730                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6731                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6732                                continue;
 6733                            }
 6734
 6735                            let range = Anchor {
 6736                                buffer_id,
 6737                                excerpt_id,
 6738                                text_anchor: start,
 6739                                diff_base_anchor: None,
 6740                            }..Anchor {
 6741                                buffer_id,
 6742                                excerpt_id,
 6743                                text_anchor: end,
 6744                                diff_base_anchor: None,
 6745                            };
 6746                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6747                                write_ranges.push(range);
 6748                            } else {
 6749                                read_ranges.push(range);
 6750                            }
 6751                        }
 6752                    }
 6753
 6754                    this.highlight_background::<DocumentHighlightRead>(
 6755                        &read_ranges,
 6756                        |theme| theme.colors().editor_document_highlight_read_background,
 6757                        cx,
 6758                    );
 6759                    this.highlight_background::<DocumentHighlightWrite>(
 6760                        &write_ranges,
 6761                        |theme| theme.colors().editor_document_highlight_write_background,
 6762                        cx,
 6763                    );
 6764                    cx.notify();
 6765                })
 6766                .log_err();
 6767            }
 6768        }));
 6769        None
 6770    }
 6771
 6772    fn prepare_highlight_query_from_selection(
 6773        &mut self,
 6774        cx: &mut Context<Editor>,
 6775    ) -> Option<(String, Range<Anchor>)> {
 6776        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6777            return None;
 6778        }
 6779        if !EditorSettings::get_global(cx).selection_highlight {
 6780            return None;
 6781        }
 6782        if self.selections.count() != 1 || self.selections.line_mode {
 6783            return None;
 6784        }
 6785        let selection = self.selections.newest::<Point>(cx);
 6786        if selection.is_empty() || selection.start.row != selection.end.row {
 6787            return None;
 6788        }
 6789        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6790        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6791        let query = multi_buffer_snapshot
 6792            .text_for_range(selection_anchor_range.clone())
 6793            .collect::<String>();
 6794        if query.trim().is_empty() {
 6795            return None;
 6796        }
 6797        Some((query, selection_anchor_range))
 6798    }
 6799
 6800    fn update_selection_occurrence_highlights(
 6801        &mut self,
 6802        query_text: String,
 6803        query_range: Range<Anchor>,
 6804        multi_buffer_range_to_query: Range<Point>,
 6805        use_debounce: bool,
 6806        window: &mut Window,
 6807        cx: &mut Context<Editor>,
 6808    ) -> Task<()> {
 6809        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6810        cx.spawn_in(window, async move |editor, cx| {
 6811            if use_debounce {
 6812                cx.background_executor()
 6813                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6814                    .await;
 6815            }
 6816            let match_task = cx.background_spawn(async move {
 6817                let buffer_ranges = multi_buffer_snapshot
 6818                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6819                    .into_iter()
 6820                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6821                let mut match_ranges = Vec::new();
 6822                let Ok(regex) = project::search::SearchQuery::text(
 6823                    query_text.clone(),
 6824                    false,
 6825                    false,
 6826                    false,
 6827                    Default::default(),
 6828                    Default::default(),
 6829                    false,
 6830                    None,
 6831                ) else {
 6832                    return Vec::default();
 6833                };
 6834                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6835                    match_ranges.extend(
 6836                        regex
 6837                            .search(&buffer_snapshot, Some(search_range.clone()))
 6838                            .await
 6839                            .into_iter()
 6840                            .filter_map(|match_range| {
 6841                                let match_start = buffer_snapshot
 6842                                    .anchor_after(search_range.start + match_range.start);
 6843                                let match_end = buffer_snapshot
 6844                                    .anchor_before(search_range.start + match_range.end);
 6845                                let match_anchor_range = Anchor::range_in_buffer(
 6846                                    excerpt_id,
 6847                                    buffer_snapshot.remote_id(),
 6848                                    match_start..match_end,
 6849                                );
 6850                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6851                            }),
 6852                    );
 6853                }
 6854                match_ranges
 6855            });
 6856            let match_ranges = match_task.await;
 6857            editor
 6858                .update_in(cx, |editor, _, cx| {
 6859                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6860                    if !match_ranges.is_empty() {
 6861                        editor.highlight_background::<SelectedTextHighlight>(
 6862                            &match_ranges,
 6863                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6864                            cx,
 6865                        )
 6866                    }
 6867                })
 6868                .log_err();
 6869        })
 6870    }
 6871
 6872    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6873        struct NewlineFold;
 6874        let type_id = std::any::TypeId::of::<NewlineFold>();
 6875        if !self.mode.is_single_line() {
 6876            return;
 6877        }
 6878        let snapshot = self.snapshot(window, cx);
 6879        if snapshot.buffer_snapshot.max_point().row == 0 {
 6880            return;
 6881        }
 6882        let task = cx.background_spawn(async move {
 6883            let new_newlines = snapshot
 6884                .buffer_chars_at(0)
 6885                .filter_map(|(c, i)| {
 6886                    if c == '\n' {
 6887                        Some(
 6888                            snapshot.buffer_snapshot.anchor_after(i)
 6889                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6890                        )
 6891                    } else {
 6892                        None
 6893                    }
 6894                })
 6895                .collect::<Vec<_>>();
 6896            let existing_newlines = snapshot
 6897                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6898                .filter_map(|fold| {
 6899                    if fold.placeholder.type_tag == Some(type_id) {
 6900                        Some(fold.range.start..fold.range.end)
 6901                    } else {
 6902                        None
 6903                    }
 6904                })
 6905                .collect::<Vec<_>>();
 6906
 6907            (new_newlines, existing_newlines)
 6908        });
 6909        self.folding_newlines = cx.spawn(async move |this, cx| {
 6910            let (new_newlines, existing_newlines) = task.await;
 6911            if new_newlines == existing_newlines {
 6912                return;
 6913            }
 6914            let placeholder = FoldPlaceholder {
 6915                render: Arc::new(move |_, _, cx| {
 6916                    div()
 6917                        .bg(cx.theme().status().hint_background)
 6918                        .border_b_1()
 6919                        .size_full()
 6920                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6921                        .border_color(cx.theme().status().hint)
 6922                        .child("\\n")
 6923                        .into_any()
 6924                }),
 6925                constrain_width: false,
 6926                merge_adjacent: false,
 6927                type_tag: Some(type_id),
 6928            };
 6929            let creases = new_newlines
 6930                .into_iter()
 6931                .map(|range| Crease::simple(range, placeholder.clone()))
 6932                .collect();
 6933            this.update(cx, |this, cx| {
 6934                this.display_map.update(cx, |display_map, cx| {
 6935                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6936                    display_map.fold(creases, cx);
 6937                });
 6938            })
 6939            .ok();
 6940        });
 6941    }
 6942
 6943    fn refresh_selected_text_highlights(
 6944        &mut self,
 6945        on_buffer_edit: bool,
 6946        window: &mut Window,
 6947        cx: &mut Context<Editor>,
 6948    ) {
 6949        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6950        else {
 6951            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6952            self.quick_selection_highlight_task.take();
 6953            self.debounced_selection_highlight_task.take();
 6954            return;
 6955        };
 6956        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6957        if on_buffer_edit
 6958            || self
 6959                .quick_selection_highlight_task
 6960                .as_ref()
 6961                .map_or(true, |(prev_anchor_range, _)| {
 6962                    prev_anchor_range != &query_range
 6963                })
 6964        {
 6965            let multi_buffer_visible_start = self
 6966                .scroll_manager
 6967                .anchor()
 6968                .anchor
 6969                .to_point(&multi_buffer_snapshot);
 6970            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6971                multi_buffer_visible_start
 6972                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6973                Bias::Left,
 6974            );
 6975            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6976            self.quick_selection_highlight_task = Some((
 6977                query_range.clone(),
 6978                self.update_selection_occurrence_highlights(
 6979                    query_text.clone(),
 6980                    query_range.clone(),
 6981                    multi_buffer_visible_range,
 6982                    false,
 6983                    window,
 6984                    cx,
 6985                ),
 6986            ));
 6987        }
 6988        if on_buffer_edit
 6989            || self
 6990                .debounced_selection_highlight_task
 6991                .as_ref()
 6992                .map_or(true, |(prev_anchor_range, _)| {
 6993                    prev_anchor_range != &query_range
 6994                })
 6995        {
 6996            let multi_buffer_start = multi_buffer_snapshot
 6997                .anchor_before(0)
 6998                .to_point(&multi_buffer_snapshot);
 6999            let multi_buffer_end = multi_buffer_snapshot
 7000                .anchor_after(multi_buffer_snapshot.len())
 7001                .to_point(&multi_buffer_snapshot);
 7002            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7003            self.debounced_selection_highlight_task = Some((
 7004                query_range.clone(),
 7005                self.update_selection_occurrence_highlights(
 7006                    query_text,
 7007                    query_range,
 7008                    multi_buffer_full_range,
 7009                    true,
 7010                    window,
 7011                    cx,
 7012                ),
 7013            ));
 7014        }
 7015    }
 7016
 7017    pub fn refresh_edit_prediction(
 7018        &mut self,
 7019        debounce: bool,
 7020        user_requested: bool,
 7021        window: &mut Window,
 7022        cx: &mut Context<Self>,
 7023    ) -> Option<()> {
 7024        if DisableAiSettings::get_global(cx).disable_ai {
 7025            return None;
 7026        }
 7027
 7028        let provider = self.edit_prediction_provider()?;
 7029        let cursor = self.selections.newest_anchor().head();
 7030        let (buffer, cursor_buffer_position) =
 7031            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7032
 7033        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7034            self.discard_edit_prediction(false, cx);
 7035            return None;
 7036        }
 7037
 7038        if !user_requested
 7039            && (!self.should_show_edit_predictions()
 7040                || !self.is_focused(window)
 7041                || buffer.read(cx).is_empty())
 7042        {
 7043            self.discard_edit_prediction(false, cx);
 7044            return None;
 7045        }
 7046
 7047        self.update_visible_edit_prediction(window, cx);
 7048        provider.refresh(
 7049            self.project.clone(),
 7050            buffer,
 7051            cursor_buffer_position,
 7052            debounce,
 7053            cx,
 7054        );
 7055        Some(())
 7056    }
 7057
 7058    fn show_edit_predictions_in_menu(&self) -> bool {
 7059        match self.edit_prediction_settings {
 7060            EditPredictionSettings::Disabled => false,
 7061            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7062        }
 7063    }
 7064
 7065    pub fn edit_predictions_enabled(&self) -> bool {
 7066        match self.edit_prediction_settings {
 7067            EditPredictionSettings::Disabled => false,
 7068            EditPredictionSettings::Enabled { .. } => true,
 7069        }
 7070    }
 7071
 7072    fn edit_prediction_requires_modifier(&self) -> bool {
 7073        match self.edit_prediction_settings {
 7074            EditPredictionSettings::Disabled => false,
 7075            EditPredictionSettings::Enabled {
 7076                preview_requires_modifier,
 7077                ..
 7078            } => preview_requires_modifier,
 7079        }
 7080    }
 7081
 7082    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7083        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7084            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7085            self.discard_edit_prediction(false, cx);
 7086        } else {
 7087            let selection = self.selections.newest_anchor();
 7088            let cursor = selection.head();
 7089
 7090            if let Some((buffer, cursor_buffer_position)) =
 7091                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7092            {
 7093                self.edit_prediction_settings =
 7094                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7095            }
 7096        }
 7097    }
 7098
 7099    fn edit_prediction_settings_at_position(
 7100        &self,
 7101        buffer: &Entity<Buffer>,
 7102        buffer_position: language::Anchor,
 7103        cx: &App,
 7104    ) -> EditPredictionSettings {
 7105        if !self.mode.is_full()
 7106            || !self.show_edit_predictions_override.unwrap_or(true)
 7107            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7108        {
 7109            return EditPredictionSettings::Disabled;
 7110        }
 7111
 7112        let buffer = buffer.read(cx);
 7113
 7114        let file = buffer.file();
 7115
 7116        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7117            return EditPredictionSettings::Disabled;
 7118        };
 7119
 7120        let by_provider = matches!(
 7121            self.menu_edit_predictions_policy,
 7122            MenuEditPredictionsPolicy::ByProvider
 7123        );
 7124
 7125        let show_in_menu = by_provider
 7126            && self
 7127                .edit_prediction_provider
 7128                .as_ref()
 7129                .map_or(false, |provider| {
 7130                    provider.provider.show_completions_in_menu()
 7131                });
 7132
 7133        let preview_requires_modifier =
 7134            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7135
 7136        EditPredictionSettings::Enabled {
 7137            show_in_menu,
 7138            preview_requires_modifier,
 7139        }
 7140    }
 7141
 7142    fn should_show_edit_predictions(&self) -> bool {
 7143        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7144    }
 7145
 7146    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7147        matches!(
 7148            self.edit_prediction_preview,
 7149            EditPredictionPreview::Active { .. }
 7150        )
 7151    }
 7152
 7153    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7154        let cursor = self.selections.newest_anchor().head();
 7155        if let Some((buffer, cursor_position)) =
 7156            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7157        {
 7158            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7159        } else {
 7160            false
 7161        }
 7162    }
 7163
 7164    pub fn supports_minimap(&self, cx: &App) -> bool {
 7165        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7166    }
 7167
 7168    fn edit_predictions_enabled_in_buffer(
 7169        &self,
 7170        buffer: &Entity<Buffer>,
 7171        buffer_position: language::Anchor,
 7172        cx: &App,
 7173    ) -> bool {
 7174        maybe!({
 7175            if self.read_only(cx) {
 7176                return Some(false);
 7177            }
 7178            let provider = self.edit_prediction_provider()?;
 7179            if !provider.is_enabled(&buffer, buffer_position, cx) {
 7180                return Some(false);
 7181            }
 7182            let buffer = buffer.read(cx);
 7183            let Some(file) = buffer.file() else {
 7184                return Some(true);
 7185            };
 7186            let settings = all_language_settings(Some(file), cx);
 7187            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7188        })
 7189        .unwrap_or(false)
 7190    }
 7191
 7192    fn cycle_edit_prediction(
 7193        &mut self,
 7194        direction: Direction,
 7195        window: &mut Window,
 7196        cx: &mut Context<Self>,
 7197    ) -> Option<()> {
 7198        let provider = self.edit_prediction_provider()?;
 7199        let cursor = self.selections.newest_anchor().head();
 7200        let (buffer, cursor_buffer_position) =
 7201            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7202        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7203            return None;
 7204        }
 7205
 7206        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7207        self.update_visible_edit_prediction(window, cx);
 7208
 7209        Some(())
 7210    }
 7211
 7212    pub fn show_edit_prediction(
 7213        &mut self,
 7214        _: &ShowEditPrediction,
 7215        window: &mut Window,
 7216        cx: &mut Context<Self>,
 7217    ) {
 7218        if !self.has_active_edit_prediction() {
 7219            self.refresh_edit_prediction(false, true, window, cx);
 7220            return;
 7221        }
 7222
 7223        self.update_visible_edit_prediction(window, cx);
 7224    }
 7225
 7226    pub fn display_cursor_names(
 7227        &mut self,
 7228        _: &DisplayCursorNames,
 7229        window: &mut Window,
 7230        cx: &mut Context<Self>,
 7231    ) {
 7232        self.show_cursor_names(window, cx);
 7233    }
 7234
 7235    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7236        self.show_cursor_names = true;
 7237        cx.notify();
 7238        cx.spawn_in(window, async move |this, cx| {
 7239            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7240            this.update(cx, |this, cx| {
 7241                this.show_cursor_names = false;
 7242                cx.notify()
 7243            })
 7244            .ok()
 7245        })
 7246        .detach();
 7247    }
 7248
 7249    pub fn next_edit_prediction(
 7250        &mut self,
 7251        _: &NextEditPrediction,
 7252        window: &mut Window,
 7253        cx: &mut Context<Self>,
 7254    ) {
 7255        if self.has_active_edit_prediction() {
 7256            self.cycle_edit_prediction(Direction::Next, window, cx);
 7257        } else {
 7258            let is_copilot_disabled = self
 7259                .refresh_edit_prediction(false, true, window, cx)
 7260                .is_none();
 7261            if is_copilot_disabled {
 7262                cx.propagate();
 7263            }
 7264        }
 7265    }
 7266
 7267    pub fn previous_edit_prediction(
 7268        &mut self,
 7269        _: &PreviousEditPrediction,
 7270        window: &mut Window,
 7271        cx: &mut Context<Self>,
 7272    ) {
 7273        if self.has_active_edit_prediction() {
 7274            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7275        } else {
 7276            let is_copilot_disabled = self
 7277                .refresh_edit_prediction(false, true, window, cx)
 7278                .is_none();
 7279            if is_copilot_disabled {
 7280                cx.propagate();
 7281            }
 7282        }
 7283    }
 7284
 7285    pub fn accept_edit_prediction(
 7286        &mut self,
 7287        _: &AcceptEditPrediction,
 7288        window: &mut Window,
 7289        cx: &mut Context<Self>,
 7290    ) {
 7291        if self.show_edit_predictions_in_menu() {
 7292            self.hide_context_menu(window, cx);
 7293        }
 7294
 7295        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7296            return;
 7297        };
 7298
 7299        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7300
 7301        match &active_edit_prediction.completion {
 7302            EditPrediction::Move { target, .. } => {
 7303                let target = *target;
 7304
 7305                if let Some(position_map) = &self.last_position_map {
 7306                    if position_map
 7307                        .visible_row_range
 7308                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7309                        || !self.edit_prediction_requires_modifier()
 7310                    {
 7311                        self.unfold_ranges(&[target..target], true, false, cx);
 7312                        // Note that this is also done in vim's handler of the Tab action.
 7313                        self.change_selections(
 7314                            SelectionEffects::scroll(Autoscroll::newest()),
 7315                            window,
 7316                            cx,
 7317                            |selections| {
 7318                                selections.select_anchor_ranges([target..target]);
 7319                            },
 7320                        );
 7321                        self.clear_row_highlights::<EditPredictionPreview>();
 7322
 7323                        self.edit_prediction_preview
 7324                            .set_previous_scroll_position(None);
 7325                    } else {
 7326                        self.edit_prediction_preview
 7327                            .set_previous_scroll_position(Some(
 7328                                position_map.snapshot.scroll_anchor,
 7329                            ));
 7330
 7331                        self.highlight_rows::<EditPredictionPreview>(
 7332                            target..target,
 7333                            cx.theme().colors().editor_highlighted_line_background,
 7334                            RowHighlightOptions {
 7335                                autoscroll: true,
 7336                                ..Default::default()
 7337                            },
 7338                            cx,
 7339                        );
 7340                        self.request_autoscroll(Autoscroll::fit(), cx);
 7341                    }
 7342                }
 7343            }
 7344            EditPrediction::Edit { edits, .. } => {
 7345                if let Some(provider) = self.edit_prediction_provider() {
 7346                    provider.accept(cx);
 7347                }
 7348
 7349                // Store the transaction ID and selections before applying the edit
 7350                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7351
 7352                let snapshot = self.buffer.read(cx).snapshot(cx);
 7353                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7354
 7355                self.buffer.update(cx, |buffer, cx| {
 7356                    buffer.edit(edits.iter().cloned(), None, cx)
 7357                });
 7358
 7359                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7360                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7361                });
 7362
 7363                let selections = self.selections.disjoint_anchors();
 7364                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7365                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7366                    if has_new_transaction {
 7367                        self.selection_history
 7368                            .insert_transaction(transaction_id_now, selections);
 7369                    }
 7370                }
 7371
 7372                self.update_visible_edit_prediction(window, cx);
 7373                if self.active_edit_prediction.is_none() {
 7374                    self.refresh_edit_prediction(true, true, window, cx);
 7375                }
 7376
 7377                cx.notify();
 7378            }
 7379        }
 7380
 7381        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7382    }
 7383
 7384    pub fn accept_partial_edit_prediction(
 7385        &mut self,
 7386        _: &AcceptPartialEditPrediction,
 7387        window: &mut Window,
 7388        cx: &mut Context<Self>,
 7389    ) {
 7390        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7391            return;
 7392        };
 7393        if self.selections.count() != 1 {
 7394            return;
 7395        }
 7396
 7397        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7398
 7399        match &active_edit_prediction.completion {
 7400            EditPrediction::Move { target, .. } => {
 7401                let target = *target;
 7402                self.change_selections(
 7403                    SelectionEffects::scroll(Autoscroll::newest()),
 7404                    window,
 7405                    cx,
 7406                    |selections| {
 7407                        selections.select_anchor_ranges([target..target]);
 7408                    },
 7409                );
 7410            }
 7411            EditPrediction::Edit { edits, .. } => {
 7412                // Find an insertion that starts at the cursor position.
 7413                let snapshot = self.buffer.read(cx).snapshot(cx);
 7414                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7415                let insertion = edits.iter().find_map(|(range, text)| {
 7416                    let range = range.to_offset(&snapshot);
 7417                    if range.is_empty() && range.start == cursor_offset {
 7418                        Some(text)
 7419                    } else {
 7420                        None
 7421                    }
 7422                });
 7423
 7424                if let Some(text) = insertion {
 7425                    let mut partial_completion = text
 7426                        .chars()
 7427                        .by_ref()
 7428                        .take_while(|c| c.is_alphabetic())
 7429                        .collect::<String>();
 7430                    if partial_completion.is_empty() {
 7431                        partial_completion = text
 7432                            .chars()
 7433                            .by_ref()
 7434                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7435                            .collect::<String>();
 7436                    }
 7437
 7438                    cx.emit(EditorEvent::InputHandled {
 7439                        utf16_range_to_replace: None,
 7440                        text: partial_completion.clone().into(),
 7441                    });
 7442
 7443                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7444
 7445                    self.refresh_edit_prediction(true, true, window, cx);
 7446                    cx.notify();
 7447                } else {
 7448                    self.accept_edit_prediction(&Default::default(), window, cx);
 7449                }
 7450            }
 7451        }
 7452    }
 7453
 7454    fn discard_edit_prediction(
 7455        &mut self,
 7456        should_report_edit_prediction_event: bool,
 7457        cx: &mut Context<Self>,
 7458    ) -> bool {
 7459        if should_report_edit_prediction_event {
 7460            let completion_id = self
 7461                .active_edit_prediction
 7462                .as_ref()
 7463                .and_then(|active_completion| active_completion.completion_id.clone());
 7464
 7465            self.report_edit_prediction_event(completion_id, false, cx);
 7466        }
 7467
 7468        if let Some(provider) = self.edit_prediction_provider() {
 7469            provider.discard(cx);
 7470        }
 7471
 7472        self.take_active_edit_prediction(cx)
 7473    }
 7474
 7475    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7476        let Some(provider) = self.edit_prediction_provider() else {
 7477            return;
 7478        };
 7479
 7480        let Some((_, buffer, _)) = self
 7481            .buffer
 7482            .read(cx)
 7483            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7484        else {
 7485            return;
 7486        };
 7487
 7488        let extension = buffer
 7489            .read(cx)
 7490            .file()
 7491            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7492
 7493        let event_type = match accepted {
 7494            true => "Edit Prediction Accepted",
 7495            false => "Edit Prediction Discarded",
 7496        };
 7497        telemetry::event!(
 7498            event_type,
 7499            provider = provider.name(),
 7500            prediction_id = id,
 7501            suggestion_accepted = accepted,
 7502            file_extension = extension,
 7503        );
 7504    }
 7505
 7506    pub fn has_active_edit_prediction(&self) -> bool {
 7507        self.active_edit_prediction.is_some()
 7508    }
 7509
 7510    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7511        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7512            return false;
 7513        };
 7514
 7515        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7516        self.clear_highlights::<EditPredictionHighlight>(cx);
 7517        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7518        true
 7519    }
 7520
 7521    /// Returns true when we're displaying the edit prediction popover below the cursor
 7522    /// like we are not previewing and the LSP autocomplete menu is visible
 7523    /// or we are in `when_holding_modifier` mode.
 7524    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7525        if self.edit_prediction_preview_is_active()
 7526            || !self.show_edit_predictions_in_menu()
 7527            || !self.edit_predictions_enabled()
 7528        {
 7529            return false;
 7530        }
 7531
 7532        if self.has_visible_completions_menu() {
 7533            return true;
 7534        }
 7535
 7536        has_completion && self.edit_prediction_requires_modifier()
 7537    }
 7538
 7539    fn handle_modifiers_changed(
 7540        &mut self,
 7541        modifiers: Modifiers,
 7542        position_map: &PositionMap,
 7543        window: &mut Window,
 7544        cx: &mut Context<Self>,
 7545    ) {
 7546        if self.show_edit_predictions_in_menu() {
 7547            self.update_edit_prediction_preview(&modifiers, window, cx);
 7548        }
 7549
 7550        self.update_selection_mode(&modifiers, position_map, window, cx);
 7551
 7552        let mouse_position = window.mouse_position();
 7553        if !position_map.text_hitbox.is_hovered(window) {
 7554            return;
 7555        }
 7556
 7557        self.update_hovered_link(
 7558            position_map.point_for_position(mouse_position),
 7559            &position_map.snapshot,
 7560            modifiers,
 7561            window,
 7562            cx,
 7563        )
 7564    }
 7565
 7566    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7567        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7568        if invert {
 7569            match multi_cursor_setting {
 7570                MultiCursorModifier::Alt => modifiers.alt,
 7571                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7572            }
 7573        } else {
 7574            match multi_cursor_setting {
 7575                MultiCursorModifier::Alt => modifiers.secondary(),
 7576                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7577            }
 7578        }
 7579    }
 7580
 7581    fn columnar_selection_mode(
 7582        modifiers: &Modifiers,
 7583        cx: &mut Context<Self>,
 7584    ) -> Option<ColumnarMode> {
 7585        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7586            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7587                Some(ColumnarMode::FromMouse)
 7588            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7589                Some(ColumnarMode::FromSelection)
 7590            } else {
 7591                None
 7592            }
 7593        } else {
 7594            None
 7595        }
 7596    }
 7597
 7598    fn update_selection_mode(
 7599        &mut self,
 7600        modifiers: &Modifiers,
 7601        position_map: &PositionMap,
 7602        window: &mut Window,
 7603        cx: &mut Context<Self>,
 7604    ) {
 7605        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7606            return;
 7607        };
 7608        if self.selections.pending.is_none() {
 7609            return;
 7610        }
 7611
 7612        let mouse_position = window.mouse_position();
 7613        let point_for_position = position_map.point_for_position(mouse_position);
 7614        let position = point_for_position.previous_valid;
 7615
 7616        self.select(
 7617            SelectPhase::BeginColumnar {
 7618                position,
 7619                reset: false,
 7620                mode,
 7621                goal_column: point_for_position.exact_unclipped.column(),
 7622            },
 7623            window,
 7624            cx,
 7625        );
 7626    }
 7627
 7628    fn update_edit_prediction_preview(
 7629        &mut self,
 7630        modifiers: &Modifiers,
 7631        window: &mut Window,
 7632        cx: &mut Context<Self>,
 7633    ) {
 7634        let mut modifiers_held = false;
 7635        if let Some(accept_keystroke) = self
 7636            .accept_edit_prediction_keybind(false, window, cx)
 7637            .keystroke()
 7638        {
 7639            modifiers_held = modifiers_held
 7640                || (&accept_keystroke.modifiers == modifiers
 7641                    && accept_keystroke.modifiers.modified());
 7642        };
 7643        if let Some(accept_partial_keystroke) = self
 7644            .accept_edit_prediction_keybind(true, window, cx)
 7645            .keystroke()
 7646        {
 7647            modifiers_held = modifiers_held
 7648                || (&accept_partial_keystroke.modifiers == modifiers
 7649                    && accept_partial_keystroke.modifiers.modified());
 7650        }
 7651
 7652        if modifiers_held {
 7653            if matches!(
 7654                self.edit_prediction_preview,
 7655                EditPredictionPreview::Inactive { .. }
 7656            ) {
 7657                self.edit_prediction_preview = EditPredictionPreview::Active {
 7658                    previous_scroll_position: None,
 7659                    since: Instant::now(),
 7660                };
 7661
 7662                self.update_visible_edit_prediction(window, cx);
 7663                cx.notify();
 7664            }
 7665        } else if let EditPredictionPreview::Active {
 7666            previous_scroll_position,
 7667            since,
 7668        } = self.edit_prediction_preview
 7669        {
 7670            if let (Some(previous_scroll_position), Some(position_map)) =
 7671                (previous_scroll_position, self.last_position_map.as_ref())
 7672            {
 7673                self.set_scroll_position(
 7674                    previous_scroll_position
 7675                        .scroll_position(&position_map.snapshot.display_snapshot),
 7676                    window,
 7677                    cx,
 7678                );
 7679            }
 7680
 7681            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7682                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7683            };
 7684            self.clear_row_highlights::<EditPredictionPreview>();
 7685            self.update_visible_edit_prediction(window, cx);
 7686            cx.notify();
 7687        }
 7688    }
 7689
 7690    fn update_visible_edit_prediction(
 7691        &mut self,
 7692        _window: &mut Window,
 7693        cx: &mut Context<Self>,
 7694    ) -> Option<()> {
 7695        if DisableAiSettings::get_global(cx).disable_ai {
 7696            return None;
 7697        }
 7698
 7699        let selection = self.selections.newest_anchor();
 7700        let cursor = selection.head();
 7701        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7702        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7703        let excerpt_id = cursor.excerpt_id;
 7704
 7705        let show_in_menu = self.show_edit_predictions_in_menu();
 7706        let completions_menu_has_precedence = !show_in_menu
 7707            && (self.context_menu.borrow().is_some()
 7708                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7709
 7710        if completions_menu_has_precedence
 7711            || !offset_selection.is_empty()
 7712            || self
 7713                .active_edit_prediction
 7714                .as_ref()
 7715                .map_or(false, |completion| {
 7716                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7717                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7718                    !invalidation_range.contains(&offset_selection.head())
 7719                })
 7720        {
 7721            self.discard_edit_prediction(false, cx);
 7722            return None;
 7723        }
 7724
 7725        self.take_active_edit_prediction(cx);
 7726        let Some(provider) = self.edit_prediction_provider() else {
 7727            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7728            return None;
 7729        };
 7730
 7731        let (buffer, cursor_buffer_position) =
 7732            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7733
 7734        self.edit_prediction_settings =
 7735            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7736
 7737        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7738
 7739        if self.edit_prediction_indent_conflict {
 7740            let cursor_point = cursor.to_point(&multibuffer);
 7741
 7742            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7743
 7744            if let Some((_, indent)) = indents.iter().next() {
 7745                if indent.len == cursor_point.column {
 7746                    self.edit_prediction_indent_conflict = false;
 7747                }
 7748            }
 7749        }
 7750
 7751        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7752        let edits = edit_prediction
 7753            .edits
 7754            .into_iter()
 7755            .flat_map(|(range, new_text)| {
 7756                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7757                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7758                Some((start..end, new_text))
 7759            })
 7760            .collect::<Vec<_>>();
 7761        if edits.is_empty() {
 7762            return None;
 7763        }
 7764
 7765        let first_edit_start = edits.first().unwrap().0.start;
 7766        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7767        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7768
 7769        let last_edit_end = edits.last().unwrap().0.end;
 7770        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7771        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7772
 7773        let cursor_row = cursor.to_point(&multibuffer).row;
 7774
 7775        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7776
 7777        let mut inlay_ids = Vec::new();
 7778        let invalidation_row_range;
 7779        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7780            Some(cursor_row..edit_end_row)
 7781        } else if cursor_row > edit_end_row {
 7782            Some(edit_start_row..cursor_row)
 7783        } else {
 7784            None
 7785        };
 7786        let supports_jump = self
 7787            .edit_prediction_provider
 7788            .as_ref()
 7789            .map(|provider| provider.provider.supports_jump_to_edit())
 7790            .unwrap_or(true);
 7791
 7792        let is_move = supports_jump
 7793            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7794        let completion = if is_move {
 7795            invalidation_row_range =
 7796                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7797            let target = first_edit_start;
 7798            EditPrediction::Move { target, snapshot }
 7799        } else {
 7800            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7801                && !self.edit_predictions_hidden_for_vim_mode;
 7802
 7803            if show_completions_in_buffer {
 7804                if edits
 7805                    .iter()
 7806                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7807                {
 7808                    let mut inlays = Vec::new();
 7809                    for (range, new_text) in &edits {
 7810                        let inlay = Inlay::edit_prediction(
 7811                            post_inc(&mut self.next_inlay_id),
 7812                            range.start,
 7813                            new_text.as_str(),
 7814                        );
 7815                        inlay_ids.push(inlay.id);
 7816                        inlays.push(inlay);
 7817                    }
 7818
 7819                    self.splice_inlays(&[], inlays, cx);
 7820                } else {
 7821                    let background_color = cx.theme().status().deleted_background;
 7822                    self.highlight_text::<EditPredictionHighlight>(
 7823                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7824                        HighlightStyle {
 7825                            background_color: Some(background_color),
 7826                            ..Default::default()
 7827                        },
 7828                        cx,
 7829                    );
 7830                }
 7831            }
 7832
 7833            invalidation_row_range = edit_start_row..edit_end_row;
 7834
 7835            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7836                if provider.show_tab_accept_marker() {
 7837                    EditDisplayMode::TabAccept
 7838                } else {
 7839                    EditDisplayMode::Inline
 7840                }
 7841            } else {
 7842                EditDisplayMode::DiffPopover
 7843            };
 7844
 7845            EditPrediction::Edit {
 7846                edits,
 7847                edit_preview: edit_prediction.edit_preview,
 7848                display_mode,
 7849                snapshot,
 7850            }
 7851        };
 7852
 7853        let invalidation_range = multibuffer
 7854            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7855            ..multibuffer.anchor_after(Point::new(
 7856                invalidation_row_range.end,
 7857                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7858            ));
 7859
 7860        self.stale_edit_prediction_in_menu = None;
 7861        self.active_edit_prediction = Some(EditPredictionState {
 7862            inlay_ids,
 7863            completion,
 7864            completion_id: edit_prediction.id,
 7865            invalidation_range,
 7866        });
 7867
 7868        cx.notify();
 7869
 7870        Some(())
 7871    }
 7872
 7873    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7874        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7875    }
 7876
 7877    fn clear_tasks(&mut self) {
 7878        self.tasks.clear()
 7879    }
 7880
 7881    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7882        if self.tasks.insert(key, value).is_some() {
 7883            // This case should hopefully be rare, but just in case...
 7884            log::error!(
 7885                "multiple different run targets found on a single line, only the last target will be rendered"
 7886            )
 7887        }
 7888    }
 7889
 7890    /// Get all display points of breakpoints that will be rendered within editor
 7891    ///
 7892    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7893    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7894    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7895    fn active_breakpoints(
 7896        &self,
 7897        range: Range<DisplayRow>,
 7898        window: &mut Window,
 7899        cx: &mut Context<Self>,
 7900    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7901        let mut breakpoint_display_points = HashMap::default();
 7902
 7903        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7904            return breakpoint_display_points;
 7905        };
 7906
 7907        let snapshot = self.snapshot(window, cx);
 7908
 7909        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7910        let Some(project) = self.project.as_ref() else {
 7911            return breakpoint_display_points;
 7912        };
 7913
 7914        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7915            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7916
 7917        for (buffer_snapshot, range, excerpt_id) in
 7918            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7919        {
 7920            let Some(buffer) = project
 7921                .read(cx)
 7922                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7923            else {
 7924                continue;
 7925            };
 7926            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7927                &buffer,
 7928                Some(
 7929                    buffer_snapshot.anchor_before(range.start)
 7930                        ..buffer_snapshot.anchor_after(range.end),
 7931                ),
 7932                buffer_snapshot,
 7933                cx,
 7934            );
 7935            for (breakpoint, state) in breakpoints {
 7936                let multi_buffer_anchor =
 7937                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7938                let position = multi_buffer_anchor
 7939                    .to_point(&multi_buffer_snapshot)
 7940                    .to_display_point(&snapshot);
 7941
 7942                breakpoint_display_points.insert(
 7943                    position.row(),
 7944                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7945                );
 7946            }
 7947        }
 7948
 7949        breakpoint_display_points
 7950    }
 7951
 7952    fn breakpoint_context_menu(
 7953        &self,
 7954        anchor: Anchor,
 7955        window: &mut Window,
 7956        cx: &mut Context<Self>,
 7957    ) -> Entity<ui::ContextMenu> {
 7958        let weak_editor = cx.weak_entity();
 7959        let focus_handle = self.focus_handle(cx);
 7960
 7961        let row = self
 7962            .buffer
 7963            .read(cx)
 7964            .snapshot(cx)
 7965            .summary_for_anchor::<Point>(&anchor)
 7966            .row;
 7967
 7968        let breakpoint = self
 7969            .breakpoint_at_row(row, window, cx)
 7970            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7971
 7972        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7973            "Edit Log Breakpoint"
 7974        } else {
 7975            "Set Log Breakpoint"
 7976        };
 7977
 7978        let condition_breakpoint_msg = if breakpoint
 7979            .as_ref()
 7980            .is_some_and(|bp| bp.1.condition.is_some())
 7981        {
 7982            "Edit Condition Breakpoint"
 7983        } else {
 7984            "Set Condition Breakpoint"
 7985        };
 7986
 7987        let hit_condition_breakpoint_msg = if breakpoint
 7988            .as_ref()
 7989            .is_some_and(|bp| bp.1.hit_condition.is_some())
 7990        {
 7991            "Edit Hit Condition Breakpoint"
 7992        } else {
 7993            "Set Hit Condition Breakpoint"
 7994        };
 7995
 7996        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 7997            "Unset Breakpoint"
 7998        } else {
 7999            "Set Breakpoint"
 8000        };
 8001
 8002        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8003
 8004        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8005            BreakpointState::Enabled => Some("Disable"),
 8006            BreakpointState::Disabled => Some("Enable"),
 8007        });
 8008
 8009        let (anchor, breakpoint) =
 8010            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8011
 8012        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8013            menu.on_blur_subscription(Subscription::new(|| {}))
 8014                .context(focus_handle)
 8015                .when(run_to_cursor, |this| {
 8016                    let weak_editor = weak_editor.clone();
 8017                    this.entry("Run to cursor", None, move |window, cx| {
 8018                        weak_editor
 8019                            .update(cx, |editor, cx| {
 8020                                editor.change_selections(
 8021                                    SelectionEffects::no_scroll(),
 8022                                    window,
 8023                                    cx,
 8024                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8025                                );
 8026                            })
 8027                            .ok();
 8028
 8029                        window.dispatch_action(Box::new(RunToCursor), cx);
 8030                    })
 8031                    .separator()
 8032                })
 8033                .when_some(toggle_state_msg, |this, msg| {
 8034                    this.entry(msg, None, {
 8035                        let weak_editor = weak_editor.clone();
 8036                        let breakpoint = breakpoint.clone();
 8037                        move |_window, cx| {
 8038                            weak_editor
 8039                                .update(cx, |this, cx| {
 8040                                    this.edit_breakpoint_at_anchor(
 8041                                        anchor,
 8042                                        breakpoint.as_ref().clone(),
 8043                                        BreakpointEditAction::InvertState,
 8044                                        cx,
 8045                                    );
 8046                                })
 8047                                .log_err();
 8048                        }
 8049                    })
 8050                })
 8051                .entry(set_breakpoint_msg, None, {
 8052                    let weak_editor = weak_editor.clone();
 8053                    let breakpoint = breakpoint.clone();
 8054                    move |_window, cx| {
 8055                        weak_editor
 8056                            .update(cx, |this, cx| {
 8057                                this.edit_breakpoint_at_anchor(
 8058                                    anchor,
 8059                                    breakpoint.as_ref().clone(),
 8060                                    BreakpointEditAction::Toggle,
 8061                                    cx,
 8062                                );
 8063                            })
 8064                            .log_err();
 8065                    }
 8066                })
 8067                .entry(log_breakpoint_msg, None, {
 8068                    let breakpoint = breakpoint.clone();
 8069                    let weak_editor = weak_editor.clone();
 8070                    move |window, cx| {
 8071                        weak_editor
 8072                            .update(cx, |this, cx| {
 8073                                this.add_edit_breakpoint_block(
 8074                                    anchor,
 8075                                    breakpoint.as_ref(),
 8076                                    BreakpointPromptEditAction::Log,
 8077                                    window,
 8078                                    cx,
 8079                                );
 8080                            })
 8081                            .log_err();
 8082                    }
 8083                })
 8084                .entry(condition_breakpoint_msg, None, {
 8085                    let breakpoint = breakpoint.clone();
 8086                    let weak_editor = weak_editor.clone();
 8087                    move |window, cx| {
 8088                        weak_editor
 8089                            .update(cx, |this, cx| {
 8090                                this.add_edit_breakpoint_block(
 8091                                    anchor,
 8092                                    breakpoint.as_ref(),
 8093                                    BreakpointPromptEditAction::Condition,
 8094                                    window,
 8095                                    cx,
 8096                                );
 8097                            })
 8098                            .log_err();
 8099                    }
 8100                })
 8101                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8102                    weak_editor
 8103                        .update(cx, |this, cx| {
 8104                            this.add_edit_breakpoint_block(
 8105                                anchor,
 8106                                breakpoint.as_ref(),
 8107                                BreakpointPromptEditAction::HitCondition,
 8108                                window,
 8109                                cx,
 8110                            );
 8111                        })
 8112                        .log_err();
 8113                })
 8114        })
 8115    }
 8116
 8117    fn render_breakpoint(
 8118        &self,
 8119        position: Anchor,
 8120        row: DisplayRow,
 8121        breakpoint: &Breakpoint,
 8122        state: Option<BreakpointSessionState>,
 8123        cx: &mut Context<Self>,
 8124    ) -> IconButton {
 8125        let is_rejected = state.is_some_and(|s| !s.verified);
 8126        // Is it a breakpoint that shows up when hovering over gutter?
 8127        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8128            (false, false),
 8129            |PhantomBreakpointIndicator {
 8130                 is_active,
 8131                 display_row,
 8132                 collides_with_existing_breakpoint,
 8133             }| {
 8134                (
 8135                    is_active && display_row == row,
 8136                    collides_with_existing_breakpoint,
 8137                )
 8138            },
 8139        );
 8140
 8141        let (color, icon) = {
 8142            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8143                (false, false) => ui::IconName::DebugBreakpoint,
 8144                (true, false) => ui::IconName::DebugLogBreakpoint,
 8145                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8146                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8147            };
 8148
 8149            let color = if is_phantom {
 8150                Color::Hint
 8151            } else if is_rejected {
 8152                Color::Disabled
 8153            } else {
 8154                Color::Debugger
 8155            };
 8156
 8157            (color, icon)
 8158        };
 8159
 8160        let breakpoint = Arc::from(breakpoint.clone());
 8161
 8162        let alt_as_text = gpui::Keystroke {
 8163            modifiers: Modifiers::secondary_key(),
 8164            ..Default::default()
 8165        };
 8166        let primary_action_text = if breakpoint.is_disabled() {
 8167            "Enable breakpoint"
 8168        } else if is_phantom && !collides_with_existing {
 8169            "Set breakpoint"
 8170        } else {
 8171            "Unset breakpoint"
 8172        };
 8173        let focus_handle = self.focus_handle.clone();
 8174
 8175        let meta = if is_rejected {
 8176            SharedString::from("No executable code is associated with this line.")
 8177        } else if collides_with_existing && !breakpoint.is_disabled() {
 8178            SharedString::from(format!(
 8179                "{alt_as_text}-click to disable,\nright-click for more options."
 8180            ))
 8181        } else {
 8182            SharedString::from("Right-click for more options.")
 8183        };
 8184        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8185            .icon_size(IconSize::XSmall)
 8186            .size(ui::ButtonSize::None)
 8187            .when(is_rejected, |this| {
 8188                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8189            })
 8190            .icon_color(color)
 8191            .style(ButtonStyle::Transparent)
 8192            .on_click(cx.listener({
 8193                let breakpoint = breakpoint.clone();
 8194
 8195                move |editor, event: &ClickEvent, window, cx| {
 8196                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8197                        BreakpointEditAction::InvertState
 8198                    } else {
 8199                        BreakpointEditAction::Toggle
 8200                    };
 8201
 8202                    window.focus(&editor.focus_handle(cx));
 8203                    editor.edit_breakpoint_at_anchor(
 8204                        position,
 8205                        breakpoint.as_ref().clone(),
 8206                        edit_action,
 8207                        cx,
 8208                    );
 8209                }
 8210            }))
 8211            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8212                editor.set_breakpoint_context_menu(
 8213                    row,
 8214                    Some(position),
 8215                    event.position(),
 8216                    window,
 8217                    cx,
 8218                );
 8219            }))
 8220            .tooltip(move |window, cx| {
 8221                Tooltip::with_meta_in(
 8222                    primary_action_text,
 8223                    Some(&ToggleBreakpoint),
 8224                    meta.clone(),
 8225                    &focus_handle,
 8226                    window,
 8227                    cx,
 8228                )
 8229            })
 8230    }
 8231
 8232    fn build_tasks_context(
 8233        project: &Entity<Project>,
 8234        buffer: &Entity<Buffer>,
 8235        buffer_row: u32,
 8236        tasks: &Arc<RunnableTasks>,
 8237        cx: &mut Context<Self>,
 8238    ) -> Task<Option<task::TaskContext>> {
 8239        let position = Point::new(buffer_row, tasks.column);
 8240        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8241        let location = Location {
 8242            buffer: buffer.clone(),
 8243            range: range_start..range_start,
 8244        };
 8245        // Fill in the environmental variables from the tree-sitter captures
 8246        let mut captured_task_variables = TaskVariables::default();
 8247        for (capture_name, value) in tasks.extra_variables.clone() {
 8248            captured_task_variables.insert(
 8249                task::VariableName::Custom(capture_name.into()),
 8250                value.clone(),
 8251            );
 8252        }
 8253        project.update(cx, |project, cx| {
 8254            project.task_store().update(cx, |task_store, cx| {
 8255                task_store.task_context_for_location(captured_task_variables, location, cx)
 8256            })
 8257        })
 8258    }
 8259
 8260    pub fn spawn_nearest_task(
 8261        &mut self,
 8262        action: &SpawnNearestTask,
 8263        window: &mut Window,
 8264        cx: &mut Context<Self>,
 8265    ) {
 8266        let Some((workspace, _)) = self.workspace.clone() else {
 8267            return;
 8268        };
 8269        let Some(project) = self.project.clone() else {
 8270            return;
 8271        };
 8272
 8273        // Try to find a closest, enclosing node using tree-sitter that has a task
 8274        let Some((buffer, buffer_row, tasks)) = self
 8275            .find_enclosing_node_task(cx)
 8276            // Or find the task that's closest in row-distance.
 8277            .or_else(|| self.find_closest_task(cx))
 8278        else {
 8279            return;
 8280        };
 8281
 8282        let reveal_strategy = action.reveal;
 8283        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8284        cx.spawn_in(window, async move |_, cx| {
 8285            let context = task_context.await?;
 8286            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8287
 8288            let resolved = &mut resolved_task.resolved;
 8289            resolved.reveal = reveal_strategy;
 8290
 8291            workspace
 8292                .update_in(cx, |workspace, window, cx| {
 8293                    workspace.schedule_resolved_task(
 8294                        task_source_kind,
 8295                        resolved_task,
 8296                        false,
 8297                        window,
 8298                        cx,
 8299                    );
 8300                })
 8301                .ok()
 8302        })
 8303        .detach();
 8304    }
 8305
 8306    fn find_closest_task(
 8307        &mut self,
 8308        cx: &mut Context<Self>,
 8309    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8310        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8311
 8312        let ((buffer_id, row), tasks) = self
 8313            .tasks
 8314            .iter()
 8315            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8316
 8317        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8318        let tasks = Arc::new(tasks.to_owned());
 8319        Some((buffer, *row, tasks))
 8320    }
 8321
 8322    fn find_enclosing_node_task(
 8323        &mut self,
 8324        cx: &mut Context<Self>,
 8325    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8326        let snapshot = self.buffer.read(cx).snapshot(cx);
 8327        let offset = self.selections.newest::<usize>(cx).head();
 8328        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8329        let buffer_id = excerpt.buffer().remote_id();
 8330
 8331        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8332        let mut cursor = layer.node().walk();
 8333
 8334        while cursor.goto_first_child_for_byte(offset).is_some() {
 8335            if cursor.node().end_byte() == offset {
 8336                cursor.goto_next_sibling();
 8337            }
 8338        }
 8339
 8340        // Ascend to the smallest ancestor that contains the range and has a task.
 8341        loop {
 8342            let node = cursor.node();
 8343            let node_range = node.byte_range();
 8344            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8345
 8346            // Check if this node contains our offset
 8347            if node_range.start <= offset && node_range.end >= offset {
 8348                // If it contains offset, check for task
 8349                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8350                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8351                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8352                }
 8353            }
 8354
 8355            if !cursor.goto_parent() {
 8356                break;
 8357            }
 8358        }
 8359        None
 8360    }
 8361
 8362    fn render_run_indicator(
 8363        &self,
 8364        _style: &EditorStyle,
 8365        is_active: bool,
 8366        row: DisplayRow,
 8367        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8368        cx: &mut Context<Self>,
 8369    ) -> IconButton {
 8370        let color = Color::Muted;
 8371        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8372
 8373        IconButton::new(
 8374            ("run_indicator", row.0 as usize),
 8375            ui::IconName::PlayOutlined,
 8376        )
 8377        .shape(ui::IconButtonShape::Square)
 8378        .icon_size(IconSize::XSmall)
 8379        .icon_color(color)
 8380        .toggle_state(is_active)
 8381        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8382            let quick_launch = match e {
 8383                ClickEvent::Keyboard(_) => true,
 8384                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8385            };
 8386
 8387            window.focus(&editor.focus_handle(cx));
 8388            editor.toggle_code_actions(
 8389                &ToggleCodeActions {
 8390                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8391                    quick_launch,
 8392                },
 8393                window,
 8394                cx,
 8395            );
 8396        }))
 8397        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8398            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8399        }))
 8400    }
 8401
 8402    pub fn context_menu_visible(&self) -> bool {
 8403        !self.edit_prediction_preview_is_active()
 8404            && self
 8405                .context_menu
 8406                .borrow()
 8407                .as_ref()
 8408                .map_or(false, |menu| menu.visible())
 8409    }
 8410
 8411    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8412        self.context_menu
 8413            .borrow()
 8414            .as_ref()
 8415            .map(|menu| menu.origin())
 8416    }
 8417
 8418    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8419        self.context_menu_options = Some(options);
 8420    }
 8421
 8422    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8423    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8424
 8425    fn render_edit_prediction_popover(
 8426        &mut self,
 8427        text_bounds: &Bounds<Pixels>,
 8428        content_origin: gpui::Point<Pixels>,
 8429        right_margin: Pixels,
 8430        editor_snapshot: &EditorSnapshot,
 8431        visible_row_range: Range<DisplayRow>,
 8432        scroll_top: f32,
 8433        scroll_bottom: f32,
 8434        line_layouts: &[LineWithInvisibles],
 8435        line_height: Pixels,
 8436        scroll_pixel_position: gpui::Point<Pixels>,
 8437        newest_selection_head: Option<DisplayPoint>,
 8438        editor_width: Pixels,
 8439        style: &EditorStyle,
 8440        window: &mut Window,
 8441        cx: &mut App,
 8442    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8443        if self.mode().is_minimap() {
 8444            return None;
 8445        }
 8446        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8447
 8448        if self.edit_prediction_visible_in_cursor_popover(true) {
 8449            return None;
 8450        }
 8451
 8452        match &active_edit_prediction.completion {
 8453            EditPrediction::Move { target, .. } => {
 8454                let target_display_point = target.to_display_point(editor_snapshot);
 8455
 8456                if self.edit_prediction_requires_modifier() {
 8457                    if !self.edit_prediction_preview_is_active() {
 8458                        return None;
 8459                    }
 8460
 8461                    self.render_edit_prediction_modifier_jump_popover(
 8462                        text_bounds,
 8463                        content_origin,
 8464                        visible_row_range,
 8465                        line_layouts,
 8466                        line_height,
 8467                        scroll_pixel_position,
 8468                        newest_selection_head,
 8469                        target_display_point,
 8470                        window,
 8471                        cx,
 8472                    )
 8473                } else {
 8474                    self.render_edit_prediction_eager_jump_popover(
 8475                        text_bounds,
 8476                        content_origin,
 8477                        editor_snapshot,
 8478                        visible_row_range,
 8479                        scroll_top,
 8480                        scroll_bottom,
 8481                        line_height,
 8482                        scroll_pixel_position,
 8483                        target_display_point,
 8484                        editor_width,
 8485                        window,
 8486                        cx,
 8487                    )
 8488                }
 8489            }
 8490            EditPrediction::Edit {
 8491                display_mode: EditDisplayMode::Inline,
 8492                ..
 8493            } => None,
 8494            EditPrediction::Edit {
 8495                display_mode: EditDisplayMode::TabAccept,
 8496                edits,
 8497                ..
 8498            } => {
 8499                let range = &edits.first()?.0;
 8500                let target_display_point = range.end.to_display_point(editor_snapshot);
 8501
 8502                self.render_edit_prediction_end_of_line_popover(
 8503                    "Accept",
 8504                    editor_snapshot,
 8505                    visible_row_range,
 8506                    target_display_point,
 8507                    line_height,
 8508                    scroll_pixel_position,
 8509                    content_origin,
 8510                    editor_width,
 8511                    window,
 8512                    cx,
 8513                )
 8514            }
 8515            EditPrediction::Edit {
 8516                edits,
 8517                edit_preview,
 8518                display_mode: EditDisplayMode::DiffPopover,
 8519                snapshot,
 8520            } => self.render_edit_prediction_diff_popover(
 8521                text_bounds,
 8522                content_origin,
 8523                right_margin,
 8524                editor_snapshot,
 8525                visible_row_range,
 8526                line_layouts,
 8527                line_height,
 8528                scroll_pixel_position,
 8529                newest_selection_head,
 8530                editor_width,
 8531                style,
 8532                edits,
 8533                edit_preview,
 8534                snapshot,
 8535                window,
 8536                cx,
 8537            ),
 8538        }
 8539    }
 8540
 8541    fn render_edit_prediction_modifier_jump_popover(
 8542        &mut self,
 8543        text_bounds: &Bounds<Pixels>,
 8544        content_origin: gpui::Point<Pixels>,
 8545        visible_row_range: Range<DisplayRow>,
 8546        line_layouts: &[LineWithInvisibles],
 8547        line_height: Pixels,
 8548        scroll_pixel_position: gpui::Point<Pixels>,
 8549        newest_selection_head: Option<DisplayPoint>,
 8550        target_display_point: DisplayPoint,
 8551        window: &mut Window,
 8552        cx: &mut App,
 8553    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8554        let scrolled_content_origin =
 8555            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8556
 8557        const SCROLL_PADDING_Y: Pixels = px(12.);
 8558
 8559        if target_display_point.row() < visible_row_range.start {
 8560            return self.render_edit_prediction_scroll_popover(
 8561                |_| SCROLL_PADDING_Y,
 8562                IconName::ArrowUp,
 8563                visible_row_range,
 8564                line_layouts,
 8565                newest_selection_head,
 8566                scrolled_content_origin,
 8567                window,
 8568                cx,
 8569            );
 8570        } else if target_display_point.row() >= visible_row_range.end {
 8571            return self.render_edit_prediction_scroll_popover(
 8572                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8573                IconName::ArrowDown,
 8574                visible_row_range,
 8575                line_layouts,
 8576                newest_selection_head,
 8577                scrolled_content_origin,
 8578                window,
 8579                cx,
 8580            );
 8581        }
 8582
 8583        const POLE_WIDTH: Pixels = px(2.);
 8584
 8585        let line_layout =
 8586            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8587        let target_column = target_display_point.column() as usize;
 8588
 8589        let target_x = line_layout.x_for_index(target_column);
 8590        let target_y =
 8591            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8592
 8593        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8594
 8595        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8596        border_color.l += 0.001;
 8597
 8598        let mut element = v_flex()
 8599            .items_end()
 8600            .when(flag_on_right, |el| el.items_start())
 8601            .child(if flag_on_right {
 8602                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8603                    .rounded_bl(px(0.))
 8604                    .rounded_tl(px(0.))
 8605                    .border_l_2()
 8606                    .border_color(border_color)
 8607            } else {
 8608                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8609                    .rounded_br(px(0.))
 8610                    .rounded_tr(px(0.))
 8611                    .border_r_2()
 8612                    .border_color(border_color)
 8613            })
 8614            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8615            .into_any();
 8616
 8617        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8618
 8619        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8620            - point(
 8621                if flag_on_right {
 8622                    POLE_WIDTH
 8623                } else {
 8624                    size.width - POLE_WIDTH
 8625                },
 8626                size.height - line_height,
 8627            );
 8628
 8629        origin.x = origin.x.max(content_origin.x);
 8630
 8631        element.prepaint_at(origin, window, cx);
 8632
 8633        Some((element, origin))
 8634    }
 8635
 8636    fn render_edit_prediction_scroll_popover(
 8637        &mut self,
 8638        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8639        scroll_icon: IconName,
 8640        visible_row_range: Range<DisplayRow>,
 8641        line_layouts: &[LineWithInvisibles],
 8642        newest_selection_head: Option<DisplayPoint>,
 8643        scrolled_content_origin: gpui::Point<Pixels>,
 8644        window: &mut Window,
 8645        cx: &mut App,
 8646    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8647        let mut element = self
 8648            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8649            .into_any();
 8650
 8651        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8652
 8653        let cursor = newest_selection_head?;
 8654        let cursor_row_layout =
 8655            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8656        let cursor_column = cursor.column() as usize;
 8657
 8658        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8659
 8660        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8661
 8662        element.prepaint_at(origin, window, cx);
 8663        Some((element, origin))
 8664    }
 8665
 8666    fn render_edit_prediction_eager_jump_popover(
 8667        &mut self,
 8668        text_bounds: &Bounds<Pixels>,
 8669        content_origin: gpui::Point<Pixels>,
 8670        editor_snapshot: &EditorSnapshot,
 8671        visible_row_range: Range<DisplayRow>,
 8672        scroll_top: f32,
 8673        scroll_bottom: f32,
 8674        line_height: Pixels,
 8675        scroll_pixel_position: gpui::Point<Pixels>,
 8676        target_display_point: DisplayPoint,
 8677        editor_width: Pixels,
 8678        window: &mut Window,
 8679        cx: &mut App,
 8680    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8681        if target_display_point.row().as_f32() < scroll_top {
 8682            let mut element = self
 8683                .render_edit_prediction_line_popover(
 8684                    "Jump to Edit",
 8685                    Some(IconName::ArrowUp),
 8686                    window,
 8687                    cx,
 8688                )?
 8689                .into_any();
 8690
 8691            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8692            let offset = point(
 8693                (text_bounds.size.width - size.width) / 2.,
 8694                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8695            );
 8696
 8697            let origin = text_bounds.origin + offset;
 8698            element.prepaint_at(origin, window, cx);
 8699            Some((element, origin))
 8700        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8701            let mut element = self
 8702                .render_edit_prediction_line_popover(
 8703                    "Jump to Edit",
 8704                    Some(IconName::ArrowDown),
 8705                    window,
 8706                    cx,
 8707                )?
 8708                .into_any();
 8709
 8710            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8711            let offset = point(
 8712                (text_bounds.size.width - size.width) / 2.,
 8713                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8714            );
 8715
 8716            let origin = text_bounds.origin + offset;
 8717            element.prepaint_at(origin, window, cx);
 8718            Some((element, origin))
 8719        } else {
 8720            self.render_edit_prediction_end_of_line_popover(
 8721                "Jump to Edit",
 8722                editor_snapshot,
 8723                visible_row_range,
 8724                target_display_point,
 8725                line_height,
 8726                scroll_pixel_position,
 8727                content_origin,
 8728                editor_width,
 8729                window,
 8730                cx,
 8731            )
 8732        }
 8733    }
 8734
 8735    fn render_edit_prediction_end_of_line_popover(
 8736        self: &mut Editor,
 8737        label: &'static str,
 8738        editor_snapshot: &EditorSnapshot,
 8739        visible_row_range: Range<DisplayRow>,
 8740        target_display_point: DisplayPoint,
 8741        line_height: Pixels,
 8742        scroll_pixel_position: gpui::Point<Pixels>,
 8743        content_origin: gpui::Point<Pixels>,
 8744        editor_width: Pixels,
 8745        window: &mut Window,
 8746        cx: &mut App,
 8747    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8748        let target_line_end = DisplayPoint::new(
 8749            target_display_point.row(),
 8750            editor_snapshot.line_len(target_display_point.row()),
 8751        );
 8752
 8753        let mut element = self
 8754            .render_edit_prediction_line_popover(label, None, window, cx)?
 8755            .into_any();
 8756
 8757        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8758
 8759        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8760
 8761        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8762        let mut origin = start_point
 8763            + line_origin
 8764            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8765        origin.x = origin.x.max(content_origin.x);
 8766
 8767        let max_x = content_origin.x + editor_width - size.width;
 8768
 8769        if origin.x > max_x {
 8770            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8771
 8772            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8773                origin.y += offset;
 8774                IconName::ArrowUp
 8775            } else {
 8776                origin.y -= offset;
 8777                IconName::ArrowDown
 8778            };
 8779
 8780            element = self
 8781                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8782                .into_any();
 8783
 8784            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8785
 8786            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8787        }
 8788
 8789        element.prepaint_at(origin, window, cx);
 8790        Some((element, origin))
 8791    }
 8792
 8793    fn render_edit_prediction_diff_popover(
 8794        self: &Editor,
 8795        text_bounds: &Bounds<Pixels>,
 8796        content_origin: gpui::Point<Pixels>,
 8797        right_margin: Pixels,
 8798        editor_snapshot: &EditorSnapshot,
 8799        visible_row_range: Range<DisplayRow>,
 8800        line_layouts: &[LineWithInvisibles],
 8801        line_height: Pixels,
 8802        scroll_pixel_position: gpui::Point<Pixels>,
 8803        newest_selection_head: Option<DisplayPoint>,
 8804        editor_width: Pixels,
 8805        style: &EditorStyle,
 8806        edits: &Vec<(Range<Anchor>, String)>,
 8807        edit_preview: &Option<language::EditPreview>,
 8808        snapshot: &language::BufferSnapshot,
 8809        window: &mut Window,
 8810        cx: &mut App,
 8811    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8812        let edit_start = edits
 8813            .first()
 8814            .unwrap()
 8815            .0
 8816            .start
 8817            .to_display_point(editor_snapshot);
 8818        let edit_end = edits
 8819            .last()
 8820            .unwrap()
 8821            .0
 8822            .end
 8823            .to_display_point(editor_snapshot);
 8824
 8825        let is_visible = visible_row_range.contains(&edit_start.row())
 8826            || visible_row_range.contains(&edit_end.row());
 8827        if !is_visible {
 8828            return None;
 8829        }
 8830
 8831        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8832            crate::edit_prediction_edit_text(&snapshot, edits, edit_preview, false, cx)
 8833        } else {
 8834            // Fallback for providers without edit_preview
 8835            crate::edit_prediction_fallback_text(edits, cx)
 8836        };
 8837
 8838        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8839        let line_count = highlighted_edits.text.lines().count();
 8840
 8841        const BORDER_WIDTH: Pixels = px(1.);
 8842
 8843        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8844        let has_keybind = keybind.is_some();
 8845
 8846        let mut element = h_flex()
 8847            .items_start()
 8848            .child(
 8849                h_flex()
 8850                    .bg(cx.theme().colors().editor_background)
 8851                    .border(BORDER_WIDTH)
 8852                    .shadow_xs()
 8853                    .border_color(cx.theme().colors().border)
 8854                    .rounded_l_lg()
 8855                    .when(line_count > 1, |el| el.rounded_br_lg())
 8856                    .pr_1()
 8857                    .child(styled_text),
 8858            )
 8859            .child(
 8860                h_flex()
 8861                    .h(line_height + BORDER_WIDTH * 2.)
 8862                    .px_1p5()
 8863                    .gap_1()
 8864                    // Workaround: For some reason, there's a gap if we don't do this
 8865                    .ml(-BORDER_WIDTH)
 8866                    .shadow(vec![gpui::BoxShadow {
 8867                        color: gpui::black().opacity(0.05),
 8868                        offset: point(px(1.), px(1.)),
 8869                        blur_radius: px(2.),
 8870                        spread_radius: px(0.),
 8871                    }])
 8872                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8873                    .border(BORDER_WIDTH)
 8874                    .border_color(cx.theme().colors().border)
 8875                    .rounded_r_lg()
 8876                    .id("edit_prediction_diff_popover_keybind")
 8877                    .when(!has_keybind, |el| {
 8878                        let status_colors = cx.theme().status();
 8879
 8880                        el.bg(status_colors.error_background)
 8881                            .border_color(status_colors.error.opacity(0.6))
 8882                            .child(Icon::new(IconName::Info).color(Color::Error))
 8883                            .cursor_default()
 8884                            .hoverable_tooltip(move |_window, cx| {
 8885                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8886                            })
 8887                    })
 8888                    .children(keybind),
 8889            )
 8890            .into_any();
 8891
 8892        let longest_row =
 8893            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8894        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8895            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8896        } else {
 8897            layout_line(
 8898                longest_row,
 8899                editor_snapshot,
 8900                style,
 8901                editor_width,
 8902                |_| false,
 8903                window,
 8904                cx,
 8905            )
 8906            .width
 8907        };
 8908
 8909        let viewport_bounds =
 8910            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8911                right: -right_margin,
 8912                ..Default::default()
 8913            });
 8914
 8915        let x_after_longest =
 8916            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8917                - scroll_pixel_position.x;
 8918
 8919        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8920
 8921        // Fully visible if it can be displayed within the window (allow overlapping other
 8922        // panes). However, this is only allowed if the popover starts within text_bounds.
 8923        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8924            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8925
 8926        let mut origin = if can_position_to_the_right {
 8927            point(
 8928                x_after_longest,
 8929                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8930                    - scroll_pixel_position.y,
 8931            )
 8932        } else {
 8933            let cursor_row = newest_selection_head.map(|head| head.row());
 8934            let above_edit = edit_start
 8935                .row()
 8936                .0
 8937                .checked_sub(line_count as u32)
 8938                .map(DisplayRow);
 8939            let below_edit = Some(edit_end.row() + 1);
 8940            let above_cursor =
 8941                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8942            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8943
 8944            // Place the edit popover adjacent to the edit if there is a location
 8945            // available that is onscreen and does not obscure the cursor. Otherwise,
 8946            // place it adjacent to the cursor.
 8947            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8948                .into_iter()
 8949                .flatten()
 8950                .find(|&start_row| {
 8951                    let end_row = start_row + line_count as u32;
 8952                    visible_row_range.contains(&start_row)
 8953                        && visible_row_range.contains(&end_row)
 8954                        && cursor_row.map_or(true, |cursor_row| {
 8955                            !((start_row..end_row).contains(&cursor_row))
 8956                        })
 8957                })?;
 8958
 8959            content_origin
 8960                + point(
 8961                    -scroll_pixel_position.x,
 8962                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8963                )
 8964        };
 8965
 8966        origin.x -= BORDER_WIDTH;
 8967
 8968        window.defer_draw(element, origin, 1);
 8969
 8970        // Do not return an element, since it will already be drawn due to defer_draw.
 8971        None
 8972    }
 8973
 8974    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8975        px(30.)
 8976    }
 8977
 8978    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 8979        if self.read_only(cx) {
 8980            cx.theme().players().read_only()
 8981        } else {
 8982            self.style.as_ref().unwrap().local_player
 8983        }
 8984    }
 8985
 8986    fn render_edit_prediction_accept_keybind(
 8987        &self,
 8988        window: &mut Window,
 8989        cx: &App,
 8990    ) -> Option<AnyElement> {
 8991        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 8992        let accept_keystroke = accept_binding.keystroke()?;
 8993
 8994        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 8995
 8996        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 8997            Color::Accent
 8998        } else {
 8999            Color::Muted
 9000        };
 9001
 9002        h_flex()
 9003            .px_0p5()
 9004            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9005            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9006            .text_size(TextSize::XSmall.rems(cx))
 9007            .child(h_flex().children(ui::render_modifiers(
 9008                &accept_keystroke.modifiers,
 9009                PlatformStyle::platform(),
 9010                Some(modifiers_color),
 9011                Some(IconSize::XSmall.rems().into()),
 9012                true,
 9013            )))
 9014            .when(is_platform_style_mac, |parent| {
 9015                parent.child(accept_keystroke.key.clone())
 9016            })
 9017            .when(!is_platform_style_mac, |parent| {
 9018                parent.child(
 9019                    Key::new(
 9020                        util::capitalize(&accept_keystroke.key),
 9021                        Some(Color::Default),
 9022                    )
 9023                    .size(Some(IconSize::XSmall.rems().into())),
 9024                )
 9025            })
 9026            .into_any()
 9027            .into()
 9028    }
 9029
 9030    fn render_edit_prediction_line_popover(
 9031        &self,
 9032        label: impl Into<SharedString>,
 9033        icon: Option<IconName>,
 9034        window: &mut Window,
 9035        cx: &App,
 9036    ) -> Option<Stateful<Div>> {
 9037        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9038
 9039        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9040        let has_keybind = keybind.is_some();
 9041
 9042        let result = h_flex()
 9043            .id("ep-line-popover")
 9044            .py_0p5()
 9045            .pl_1()
 9046            .pr(padding_right)
 9047            .gap_1()
 9048            .rounded_md()
 9049            .border_1()
 9050            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9051            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9052            .shadow_xs()
 9053            .when(!has_keybind, |el| {
 9054                let status_colors = cx.theme().status();
 9055
 9056                el.bg(status_colors.error_background)
 9057                    .border_color(status_colors.error.opacity(0.6))
 9058                    .pl_2()
 9059                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9060                    .cursor_default()
 9061                    .hoverable_tooltip(move |_window, cx| {
 9062                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9063                    })
 9064            })
 9065            .children(keybind)
 9066            .child(
 9067                Label::new(label)
 9068                    .size(LabelSize::Small)
 9069                    .when(!has_keybind, |el| {
 9070                        el.color(cx.theme().status().error.into()).strikethrough()
 9071                    }),
 9072            )
 9073            .when(!has_keybind, |el| {
 9074                el.child(
 9075                    h_flex().ml_1().child(
 9076                        Icon::new(IconName::Info)
 9077                            .size(IconSize::Small)
 9078                            .color(cx.theme().status().error.into()),
 9079                    ),
 9080                )
 9081            })
 9082            .when_some(icon, |element, icon| {
 9083                element.child(
 9084                    div()
 9085                        .mt(px(1.5))
 9086                        .child(Icon::new(icon).size(IconSize::Small)),
 9087                )
 9088            });
 9089
 9090        Some(result)
 9091    }
 9092
 9093    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9094        let accent_color = cx.theme().colors().text_accent;
 9095        let editor_bg_color = cx.theme().colors().editor_background;
 9096        editor_bg_color.blend(accent_color.opacity(0.1))
 9097    }
 9098
 9099    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9100        let accent_color = cx.theme().colors().text_accent;
 9101        let editor_bg_color = cx.theme().colors().editor_background;
 9102        editor_bg_color.blend(accent_color.opacity(0.6))
 9103    }
 9104    fn get_prediction_provider_icon_name(
 9105        provider: &Option<RegisteredEditPredictionProvider>,
 9106    ) -> IconName {
 9107        match provider {
 9108            Some(provider) => match provider.provider.name() {
 9109                "copilot" => IconName::Copilot,
 9110                "supermaven" => IconName::Supermaven,
 9111                _ => IconName::ZedPredict,
 9112            },
 9113            None => IconName::ZedPredict,
 9114        }
 9115    }
 9116
 9117    fn render_edit_prediction_cursor_popover(
 9118        &self,
 9119        min_width: Pixels,
 9120        max_width: Pixels,
 9121        cursor_point: Point,
 9122        style: &EditorStyle,
 9123        accept_keystroke: Option<&gpui::Keystroke>,
 9124        _window: &Window,
 9125        cx: &mut Context<Editor>,
 9126    ) -> Option<AnyElement> {
 9127        let provider = self.edit_prediction_provider.as_ref()?;
 9128        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9129
 9130        if provider.provider.needs_terms_acceptance(cx) {
 9131            return Some(
 9132                h_flex()
 9133                    .min_w(min_width)
 9134                    .flex_1()
 9135                    .px_2()
 9136                    .py_1()
 9137                    .gap_3()
 9138                    .elevation_2(cx)
 9139                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9140                    .id("accept-terms")
 9141                    .cursor_pointer()
 9142                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9143                    .on_click(cx.listener(|this, _event, window, cx| {
 9144                        cx.stop_propagation();
 9145                        this.report_editor_event(ReportEditorEvent::ZetaTosClicked, None, cx);
 9146                        window.dispatch_action(
 9147                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9148                            cx,
 9149                        );
 9150                    }))
 9151                    .child(
 9152                        h_flex()
 9153                            .flex_1()
 9154                            .gap_2()
 9155                            .child(Icon::new(provider_icon))
 9156                            .child(Label::new("Accept Terms of Service"))
 9157                            .child(div().w_full())
 9158                            .child(
 9159                                Icon::new(IconName::ArrowUpRight)
 9160                                    .color(Color::Muted)
 9161                                    .size(IconSize::Small),
 9162                            )
 9163                            .into_any_element(),
 9164                    )
 9165                    .into_any(),
 9166            );
 9167        }
 9168
 9169        let is_refreshing = provider.provider.is_refreshing(cx);
 9170
 9171        fn pending_completion_container(icon: IconName) -> Div {
 9172            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9173        }
 9174
 9175        let completion = match &self.active_edit_prediction {
 9176            Some(prediction) => {
 9177                if !self.has_visible_completions_menu() {
 9178                    const RADIUS: Pixels = px(6.);
 9179                    const BORDER_WIDTH: Pixels = px(1.);
 9180
 9181                    return Some(
 9182                        h_flex()
 9183                            .elevation_2(cx)
 9184                            .border(BORDER_WIDTH)
 9185                            .border_color(cx.theme().colors().border)
 9186                            .when(accept_keystroke.is_none(), |el| {
 9187                                el.border_color(cx.theme().status().error)
 9188                            })
 9189                            .rounded(RADIUS)
 9190                            .rounded_tl(px(0.))
 9191                            .overflow_hidden()
 9192                            .child(div().px_1p5().child(match &prediction.completion {
 9193                                EditPrediction::Move { target, snapshot } => {
 9194                                    use text::ToPoint as _;
 9195                                    if target.text_anchor.to_point(&snapshot).row > cursor_point.row
 9196                                    {
 9197                                        Icon::new(IconName::ZedPredictDown)
 9198                                    } else {
 9199                                        Icon::new(IconName::ZedPredictUp)
 9200                                    }
 9201                                }
 9202                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9203                            }))
 9204                            .child(
 9205                                h_flex()
 9206                                    .gap_1()
 9207                                    .py_1()
 9208                                    .px_2()
 9209                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9210                                    .border_l_1()
 9211                                    .border_color(cx.theme().colors().border)
 9212                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9213                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9214                                        el.child(
 9215                                            Label::new("Hold")
 9216                                                .size(LabelSize::Small)
 9217                                                .when(accept_keystroke.is_none(), |el| {
 9218                                                    el.strikethrough()
 9219                                                })
 9220                                                .line_height_style(LineHeightStyle::UiLabel),
 9221                                        )
 9222                                    })
 9223                                    .id("edit_prediction_cursor_popover_keybind")
 9224                                    .when(accept_keystroke.is_none(), |el| {
 9225                                        let status_colors = cx.theme().status();
 9226
 9227                                        el.bg(status_colors.error_background)
 9228                                            .border_color(status_colors.error.opacity(0.6))
 9229                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9230                                            .cursor_default()
 9231                                            .hoverable_tooltip(move |_window, cx| {
 9232                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9233                                                    .into()
 9234                                            })
 9235                                    })
 9236                                    .when_some(
 9237                                        accept_keystroke.as_ref(),
 9238                                        |el, accept_keystroke| {
 9239                                            el.child(h_flex().children(ui::render_modifiers(
 9240                                                &accept_keystroke.modifiers,
 9241                                                PlatformStyle::platform(),
 9242                                                Some(Color::Default),
 9243                                                Some(IconSize::XSmall.rems().into()),
 9244                                                false,
 9245                                            )))
 9246                                        },
 9247                                    ),
 9248                            )
 9249                            .into_any(),
 9250                    );
 9251                }
 9252
 9253                self.render_edit_prediction_cursor_popover_preview(
 9254                    prediction,
 9255                    cursor_point,
 9256                    style,
 9257                    cx,
 9258                )?
 9259            }
 9260
 9261            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9262                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9263                    stale_completion,
 9264                    cursor_point,
 9265                    style,
 9266                    cx,
 9267                )?,
 9268
 9269                None => pending_completion_container(provider_icon)
 9270                    .child(Label::new("...").size(LabelSize::Small)),
 9271            },
 9272
 9273            None => pending_completion_container(provider_icon)
 9274                .child(Label::new("...").size(LabelSize::Small)),
 9275        };
 9276
 9277        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9278            completion
 9279                .with_animation(
 9280                    "loading-completion",
 9281                    Animation::new(Duration::from_secs(2))
 9282                        .repeat()
 9283                        .with_easing(pulsating_between(0.4, 0.8)),
 9284                    |label, delta| label.opacity(delta),
 9285                )
 9286                .into_any_element()
 9287        } else {
 9288            completion.into_any_element()
 9289        };
 9290
 9291        let has_completion = self.active_edit_prediction.is_some();
 9292
 9293        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9294        Some(
 9295            h_flex()
 9296                .min_w(min_width)
 9297                .max_w(max_width)
 9298                .flex_1()
 9299                .elevation_2(cx)
 9300                .border_color(cx.theme().colors().border)
 9301                .child(
 9302                    div()
 9303                        .flex_1()
 9304                        .py_1()
 9305                        .px_2()
 9306                        .overflow_hidden()
 9307                        .child(completion),
 9308                )
 9309                .when_some(accept_keystroke, |el, accept_keystroke| {
 9310                    if !accept_keystroke.modifiers.modified() {
 9311                        return el;
 9312                    }
 9313
 9314                    el.child(
 9315                        h_flex()
 9316                            .h_full()
 9317                            .border_l_1()
 9318                            .rounded_r_lg()
 9319                            .border_color(cx.theme().colors().border)
 9320                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9321                            .gap_1()
 9322                            .py_1()
 9323                            .px_2()
 9324                            .child(
 9325                                h_flex()
 9326                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9327                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9328                                    .child(h_flex().children(ui::render_modifiers(
 9329                                        &accept_keystroke.modifiers,
 9330                                        PlatformStyle::platform(),
 9331                                        Some(if !has_completion {
 9332                                            Color::Muted
 9333                                        } else {
 9334                                            Color::Default
 9335                                        }),
 9336                                        None,
 9337                                        false,
 9338                                    ))),
 9339                            )
 9340                            .child(Label::new("Preview").into_any_element())
 9341                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9342                    )
 9343                })
 9344                .into_any(),
 9345        )
 9346    }
 9347
 9348    fn render_edit_prediction_cursor_popover_preview(
 9349        &self,
 9350        completion: &EditPredictionState,
 9351        cursor_point: Point,
 9352        style: &EditorStyle,
 9353        cx: &mut Context<Editor>,
 9354    ) -> Option<Div> {
 9355        use text::ToPoint as _;
 9356
 9357        fn render_relative_row_jump(
 9358            prefix: impl Into<String>,
 9359            current_row: u32,
 9360            target_row: u32,
 9361        ) -> Div {
 9362            let (row_diff, arrow) = if target_row < current_row {
 9363                (current_row - target_row, IconName::ArrowUp)
 9364            } else {
 9365                (target_row - current_row, IconName::ArrowDown)
 9366            };
 9367
 9368            h_flex()
 9369                .child(
 9370                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9371                        .color(Color::Muted)
 9372                        .size(LabelSize::Small),
 9373                )
 9374                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9375        }
 9376
 9377        let supports_jump = self
 9378            .edit_prediction_provider
 9379            .as_ref()
 9380            .map(|provider| provider.provider.supports_jump_to_edit())
 9381            .unwrap_or(true);
 9382
 9383        match &completion.completion {
 9384            EditPrediction::Move {
 9385                target, snapshot, ..
 9386            } => {
 9387                if !supports_jump {
 9388                    return None;
 9389                }
 9390
 9391                Some(
 9392                    h_flex()
 9393                        .px_2()
 9394                        .gap_2()
 9395                        .flex_1()
 9396                        .child(
 9397                            if target.text_anchor.to_point(&snapshot).row > cursor_point.row {
 9398                                Icon::new(IconName::ZedPredictDown)
 9399                            } else {
 9400                                Icon::new(IconName::ZedPredictUp)
 9401                            },
 9402                        )
 9403                        .child(Label::new("Jump to Edit")),
 9404                )
 9405            }
 9406
 9407            EditPrediction::Edit {
 9408                edits,
 9409                edit_preview,
 9410                snapshot,
 9411                display_mode: _,
 9412            } => {
 9413                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(&snapshot).row;
 9414
 9415                let (highlighted_edits, has_more_lines) =
 9416                    if let Some(edit_preview) = edit_preview.as_ref() {
 9417                        crate::edit_prediction_edit_text(&snapshot, &edits, edit_preview, true, cx)
 9418                            .first_line_preview()
 9419                    } else {
 9420                        crate::edit_prediction_fallback_text(&edits, cx).first_line_preview()
 9421                    };
 9422
 9423                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9424                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9425
 9426                let preview = h_flex()
 9427                    .gap_1()
 9428                    .min_w_16()
 9429                    .child(styled_text)
 9430                    .when(has_more_lines, |parent| parent.child(""));
 9431
 9432                let left = if supports_jump && first_edit_row != cursor_point.row {
 9433                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9434                        .into_any_element()
 9435                } else {
 9436                    let icon_name =
 9437                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9438                    Icon::new(icon_name).into_any_element()
 9439                };
 9440
 9441                Some(
 9442                    h_flex()
 9443                        .h_full()
 9444                        .flex_1()
 9445                        .gap_2()
 9446                        .pr_1()
 9447                        .overflow_x_hidden()
 9448                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9449                        .child(left)
 9450                        .child(preview),
 9451                )
 9452            }
 9453        }
 9454    }
 9455
 9456    pub fn render_context_menu(
 9457        &self,
 9458        style: &EditorStyle,
 9459        max_height_in_lines: u32,
 9460        window: &mut Window,
 9461        cx: &mut Context<Editor>,
 9462    ) -> Option<AnyElement> {
 9463        let menu = self.context_menu.borrow();
 9464        let menu = menu.as_ref()?;
 9465        if !menu.visible() {
 9466            return None;
 9467        };
 9468        Some(menu.render(style, max_height_in_lines, window, cx))
 9469    }
 9470
 9471    fn render_context_menu_aside(
 9472        &mut self,
 9473        max_size: Size<Pixels>,
 9474        window: &mut Window,
 9475        cx: &mut Context<Editor>,
 9476    ) -> Option<AnyElement> {
 9477        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9478            if menu.visible() {
 9479                menu.render_aside(max_size, window, cx)
 9480            } else {
 9481                None
 9482            }
 9483        })
 9484    }
 9485
 9486    fn hide_context_menu(
 9487        &mut self,
 9488        window: &mut Window,
 9489        cx: &mut Context<Self>,
 9490    ) -> Option<CodeContextMenu> {
 9491        cx.notify();
 9492        self.completion_tasks.clear();
 9493        let context_menu = self.context_menu.borrow_mut().take();
 9494        self.stale_edit_prediction_in_menu.take();
 9495        self.update_visible_edit_prediction(window, cx);
 9496        if let Some(CodeContextMenu::Completions(_)) = &context_menu {
 9497            if let Some(completion_provider) = &self.completion_provider {
 9498                completion_provider.selection_changed(None, window, cx);
 9499            }
 9500        }
 9501        context_menu
 9502    }
 9503
 9504    fn show_snippet_choices(
 9505        &mut self,
 9506        choices: &Vec<String>,
 9507        selection: Range<Anchor>,
 9508        cx: &mut Context<Self>,
 9509    ) {
 9510        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9511            (Some(a), Some(b)) if a == b => a,
 9512            _ => {
 9513                log::error!("expected anchor range to have matching buffer IDs");
 9514                return;
 9515            }
 9516        };
 9517        let multi_buffer = self.buffer().read(cx);
 9518        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9519            return;
 9520        };
 9521
 9522        let id = post_inc(&mut self.next_completion_id);
 9523        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9524        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9525            CompletionsMenu::new_snippet_choices(
 9526                id,
 9527                true,
 9528                choices,
 9529                selection,
 9530                buffer,
 9531                snippet_sort_order,
 9532            ),
 9533        ));
 9534    }
 9535
 9536    pub fn insert_snippet(
 9537        &mut self,
 9538        insertion_ranges: &[Range<usize>],
 9539        snippet: Snippet,
 9540        window: &mut Window,
 9541        cx: &mut Context<Self>,
 9542    ) -> Result<()> {
 9543        struct Tabstop<T> {
 9544            is_end_tabstop: bool,
 9545            ranges: Vec<Range<T>>,
 9546            choices: Option<Vec<String>>,
 9547        }
 9548
 9549        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9550            let snippet_text: Arc<str> = snippet.text.clone().into();
 9551            let edits = insertion_ranges
 9552                .iter()
 9553                .cloned()
 9554                .map(|range| (range, snippet_text.clone()));
 9555            let autoindent_mode = AutoindentMode::Block {
 9556                original_indent_columns: Vec::new(),
 9557            };
 9558            buffer.edit(edits, Some(autoindent_mode), cx);
 9559
 9560            let snapshot = &*buffer.read(cx);
 9561            let snippet = &snippet;
 9562            snippet
 9563                .tabstops
 9564                .iter()
 9565                .map(|tabstop| {
 9566                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9567                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9568                    });
 9569                    let mut tabstop_ranges = tabstop
 9570                        .ranges
 9571                        .iter()
 9572                        .flat_map(|tabstop_range| {
 9573                            let mut delta = 0_isize;
 9574                            insertion_ranges.iter().map(move |insertion_range| {
 9575                                let insertion_start = insertion_range.start as isize + delta;
 9576                                delta +=
 9577                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9578
 9579                                let start = ((insertion_start + tabstop_range.start) as usize)
 9580                                    .min(snapshot.len());
 9581                                let end = ((insertion_start + tabstop_range.end) as usize)
 9582                                    .min(snapshot.len());
 9583                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9584                            })
 9585                        })
 9586                        .collect::<Vec<_>>();
 9587                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9588
 9589                    Tabstop {
 9590                        is_end_tabstop,
 9591                        ranges: tabstop_ranges,
 9592                        choices: tabstop.choices.clone(),
 9593                    }
 9594                })
 9595                .collect::<Vec<_>>()
 9596        });
 9597        if let Some(tabstop) = tabstops.first() {
 9598            self.change_selections(Default::default(), window, cx, |s| {
 9599                // Reverse order so that the first range is the newest created selection.
 9600                // Completions will use it and autoscroll will prioritize it.
 9601                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9602            });
 9603
 9604            if let Some(choices) = &tabstop.choices {
 9605                if let Some(selection) = tabstop.ranges.first() {
 9606                    self.show_snippet_choices(choices, selection.clone(), cx)
 9607                }
 9608            }
 9609
 9610            // If we're already at the last tabstop and it's at the end of the snippet,
 9611            // we're done, we don't need to keep the state around.
 9612            if !tabstop.is_end_tabstop {
 9613                let choices = tabstops
 9614                    .iter()
 9615                    .map(|tabstop| tabstop.choices.clone())
 9616                    .collect();
 9617
 9618                let ranges = tabstops
 9619                    .into_iter()
 9620                    .map(|tabstop| tabstop.ranges)
 9621                    .collect::<Vec<_>>();
 9622
 9623                self.snippet_stack.push(SnippetState {
 9624                    active_index: 0,
 9625                    ranges,
 9626                    choices,
 9627                });
 9628            }
 9629
 9630            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9631            if self.autoclose_regions.is_empty() {
 9632                let snapshot = self.buffer.read(cx).snapshot(cx);
 9633                let mut all_selections = self.selections.all::<Point>(cx);
 9634                for selection in &mut all_selections {
 9635                    let selection_head = selection.head();
 9636                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9637                        continue;
 9638                    };
 9639
 9640                    let mut bracket_pair = None;
 9641                    let max_lookup_length = scope
 9642                        .brackets()
 9643                        .map(|(pair, _)| {
 9644                            pair.start
 9645                                .as_str()
 9646                                .chars()
 9647                                .count()
 9648                                .max(pair.end.as_str().chars().count())
 9649                        })
 9650                        .max();
 9651                    if let Some(max_lookup_length) = max_lookup_length {
 9652                        let next_text = snapshot
 9653                            .chars_at(selection_head)
 9654                            .take(max_lookup_length)
 9655                            .collect::<String>();
 9656                        let prev_text = snapshot
 9657                            .reversed_chars_at(selection_head)
 9658                            .take(max_lookup_length)
 9659                            .collect::<String>();
 9660
 9661                        for (pair, enabled) in scope.brackets() {
 9662                            if enabled
 9663                                && pair.close
 9664                                && prev_text.starts_with(pair.start.as_str())
 9665                                && next_text.starts_with(pair.end.as_str())
 9666                            {
 9667                                bracket_pair = Some(pair.clone());
 9668                                break;
 9669                            }
 9670                        }
 9671                    }
 9672
 9673                    if let Some(pair) = bracket_pair {
 9674                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9675                        let autoclose_enabled =
 9676                            self.use_autoclose && snapshot_settings.use_autoclose;
 9677                        if autoclose_enabled {
 9678                            let start = snapshot.anchor_after(selection_head);
 9679                            let end = snapshot.anchor_after(selection_head);
 9680                            self.autoclose_regions.push(AutocloseRegion {
 9681                                selection_id: selection.id,
 9682                                range: start..end,
 9683                                pair,
 9684                            });
 9685                        }
 9686                    }
 9687                }
 9688            }
 9689        }
 9690        Ok(())
 9691    }
 9692
 9693    pub fn move_to_next_snippet_tabstop(
 9694        &mut self,
 9695        window: &mut Window,
 9696        cx: &mut Context<Self>,
 9697    ) -> bool {
 9698        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9699    }
 9700
 9701    pub fn move_to_prev_snippet_tabstop(
 9702        &mut self,
 9703        window: &mut Window,
 9704        cx: &mut Context<Self>,
 9705    ) -> bool {
 9706        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9707    }
 9708
 9709    pub fn move_to_snippet_tabstop(
 9710        &mut self,
 9711        bias: Bias,
 9712        window: &mut Window,
 9713        cx: &mut Context<Self>,
 9714    ) -> bool {
 9715        if let Some(mut snippet) = self.snippet_stack.pop() {
 9716            match bias {
 9717                Bias::Left => {
 9718                    if snippet.active_index > 0 {
 9719                        snippet.active_index -= 1;
 9720                    } else {
 9721                        self.snippet_stack.push(snippet);
 9722                        return false;
 9723                    }
 9724                }
 9725                Bias::Right => {
 9726                    if snippet.active_index + 1 < snippet.ranges.len() {
 9727                        snippet.active_index += 1;
 9728                    } else {
 9729                        self.snippet_stack.push(snippet);
 9730                        return false;
 9731                    }
 9732                }
 9733            }
 9734            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9735                self.change_selections(Default::default(), window, cx, |s| {
 9736                    // Reverse order so that the first range is the newest created selection.
 9737                    // Completions will use it and autoscroll will prioritize it.
 9738                    s.select_ranges(current_ranges.iter().rev().cloned())
 9739                });
 9740
 9741                if let Some(choices) = &snippet.choices[snippet.active_index] {
 9742                    if let Some(selection) = current_ranges.first() {
 9743                        self.show_snippet_choices(&choices, selection.clone(), cx);
 9744                    }
 9745                }
 9746
 9747                // If snippet state is not at the last tabstop, push it back on the stack
 9748                if snippet.active_index + 1 < snippet.ranges.len() {
 9749                    self.snippet_stack.push(snippet);
 9750                }
 9751                return true;
 9752            }
 9753        }
 9754
 9755        false
 9756    }
 9757
 9758    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9759        self.transact(window, cx, |this, window, cx| {
 9760            this.select_all(&SelectAll, window, cx);
 9761            this.insert("", window, cx);
 9762        });
 9763    }
 9764
 9765    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9766        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9767        self.transact(window, cx, |this, window, cx| {
 9768            this.select_autoclose_pair(window, cx);
 9769            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9770            if !this.linked_edit_ranges.is_empty() {
 9771                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9772                let snapshot = this.buffer.read(cx).snapshot(cx);
 9773
 9774                for selection in selections.iter() {
 9775                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9776                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9777                    if selection_start.buffer_id != selection_end.buffer_id {
 9778                        continue;
 9779                    }
 9780                    if let Some(ranges) =
 9781                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9782                    {
 9783                        for (buffer, entries) in ranges {
 9784                            linked_ranges.entry(buffer).or_default().extend(entries);
 9785                        }
 9786                    }
 9787                }
 9788            }
 9789
 9790            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9791            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9792            for selection in &mut selections {
 9793                if selection.is_empty() {
 9794                    let old_head = selection.head();
 9795                    let mut new_head =
 9796                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9797                            .to_point(&display_map);
 9798                    if let Some((buffer, line_buffer_range)) = display_map
 9799                        .buffer_snapshot
 9800                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9801                    {
 9802                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9803                        let indent_len = match indent_size.kind {
 9804                            IndentKind::Space => {
 9805                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9806                            }
 9807                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9808                        };
 9809                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9810                            let indent_len = indent_len.get();
 9811                            new_head = cmp::min(
 9812                                new_head,
 9813                                MultiBufferPoint::new(
 9814                                    old_head.row,
 9815                                    ((old_head.column - 1) / indent_len) * indent_len,
 9816                                ),
 9817                            );
 9818                        }
 9819                    }
 9820
 9821                    selection.set_head(new_head, SelectionGoal::None);
 9822                }
 9823            }
 9824
 9825            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9826            this.insert("", window, cx);
 9827            let empty_str: Arc<str> = Arc::from("");
 9828            for (buffer, edits) in linked_ranges {
 9829                let snapshot = buffer.read(cx).snapshot();
 9830                use text::ToPoint as TP;
 9831
 9832                let edits = edits
 9833                    .into_iter()
 9834                    .map(|range| {
 9835                        let end_point = TP::to_point(&range.end, &snapshot);
 9836                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9837
 9838                        if end_point == start_point {
 9839                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9840                                .saturating_sub(1);
 9841                            start_point =
 9842                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9843                        };
 9844
 9845                        (start_point..end_point, empty_str.clone())
 9846                    })
 9847                    .sorted_by_key(|(range, _)| range.start)
 9848                    .collect::<Vec<_>>();
 9849                buffer.update(cx, |this, cx| {
 9850                    this.edit(edits, None, cx);
 9851                })
 9852            }
 9853            this.refresh_edit_prediction(true, false, window, cx);
 9854            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9855        });
 9856    }
 9857
 9858    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9859        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9860        self.transact(window, cx, |this, window, cx| {
 9861            this.change_selections(Default::default(), window, cx, |s| {
 9862                s.move_with(|map, selection| {
 9863                    if selection.is_empty() {
 9864                        let cursor = movement::right(map, selection.head());
 9865                        selection.end = cursor;
 9866                        selection.reversed = true;
 9867                        selection.goal = SelectionGoal::None;
 9868                    }
 9869                })
 9870            });
 9871            this.insert("", window, cx);
 9872            this.refresh_edit_prediction(true, false, window, cx);
 9873        });
 9874    }
 9875
 9876    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9877        if self.mode.is_single_line() {
 9878            cx.propagate();
 9879            return;
 9880        }
 9881
 9882        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9883        if self.move_to_prev_snippet_tabstop(window, cx) {
 9884            return;
 9885        }
 9886        self.outdent(&Outdent, window, cx);
 9887    }
 9888
 9889    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9890        if self.mode.is_single_line() {
 9891            cx.propagate();
 9892            return;
 9893        }
 9894
 9895        if self.move_to_next_snippet_tabstop(window, cx) {
 9896            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9897            return;
 9898        }
 9899        if self.read_only(cx) {
 9900            return;
 9901        }
 9902        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9903        let mut selections = self.selections.all_adjusted(cx);
 9904        let buffer = self.buffer.read(cx);
 9905        let snapshot = buffer.snapshot(cx);
 9906        let rows_iter = selections.iter().map(|s| s.head().row);
 9907        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9908
 9909        let has_some_cursor_in_whitespace = selections
 9910            .iter()
 9911            .filter(|selection| selection.is_empty())
 9912            .any(|selection| {
 9913                let cursor = selection.head();
 9914                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9915                cursor.column < current_indent.len
 9916            });
 9917
 9918        let mut edits = Vec::new();
 9919        let mut prev_edited_row = 0;
 9920        let mut row_delta = 0;
 9921        for selection in &mut selections {
 9922            if selection.start.row != prev_edited_row {
 9923                row_delta = 0;
 9924            }
 9925            prev_edited_row = selection.end.row;
 9926
 9927            // If the selection is non-empty, then increase the indentation of the selected lines.
 9928            if !selection.is_empty() {
 9929                row_delta =
 9930                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9931                continue;
 9932            }
 9933
 9934            let cursor = selection.head();
 9935            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9936            if let Some(suggested_indent) =
 9937                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9938            {
 9939                // Don't do anything if already at suggested indent
 9940                // and there is any other cursor which is not
 9941                if has_some_cursor_in_whitespace
 9942                    && cursor.column == current_indent.len
 9943                    && current_indent.len == suggested_indent.len
 9944                {
 9945                    continue;
 9946                }
 9947
 9948                // Adjust line and move cursor to suggested indent
 9949                // if cursor is not at suggested indent
 9950                if cursor.column < suggested_indent.len
 9951                    && cursor.column <= current_indent.len
 9952                    && current_indent.len <= suggested_indent.len
 9953                {
 9954                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9955                    selection.end = selection.start;
 9956                    if row_delta == 0 {
 9957                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9958                            cursor.row,
 9959                            current_indent,
 9960                            suggested_indent,
 9961                        ));
 9962                        row_delta = suggested_indent.len - current_indent.len;
 9963                    }
 9964                    continue;
 9965                }
 9966
 9967                // If current indent is more than suggested indent
 9968                // only move cursor to current indent and skip indent
 9969                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9970                    selection.start = Point::new(cursor.row, current_indent.len);
 9971                    selection.end = selection.start;
 9972                    continue;
 9973                }
 9974            }
 9975
 9976            // Otherwise, insert a hard or soft tab.
 9977            let settings = buffer.language_settings_at(cursor, cx);
 9978            let tab_size = if settings.hard_tabs {
 9979                IndentSize::tab()
 9980            } else {
 9981                let tab_size = settings.tab_size.get();
 9982                let indent_remainder = snapshot
 9983                    .text_for_range(Point::new(cursor.row, 0)..cursor)
 9984                    .flat_map(str::chars)
 9985                    .fold(row_delta % tab_size, |counter: u32, c| {
 9986                        if c == '\t' {
 9987                            0
 9988                        } else {
 9989                            (counter + 1) % tab_size
 9990                        }
 9991                    });
 9992
 9993                let chars_to_next_tab_stop = tab_size - indent_remainder;
 9994                IndentSize::spaces(chars_to_next_tab_stop)
 9995            };
 9996            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
 9997            selection.end = selection.start;
 9998            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
 9999            row_delta += tab_size.len;
10000        }
10001
10002        self.transact(window, cx, |this, window, cx| {
10003            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10004            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10005            this.refresh_edit_prediction(true, false, window, cx);
10006        });
10007    }
10008
10009    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10010        if self.read_only(cx) {
10011            return;
10012        }
10013        if self.mode.is_single_line() {
10014            cx.propagate();
10015            return;
10016        }
10017
10018        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10019        let mut selections = self.selections.all::<Point>(cx);
10020        let mut prev_edited_row = 0;
10021        let mut row_delta = 0;
10022        let mut edits = Vec::new();
10023        let buffer = self.buffer.read(cx);
10024        let snapshot = buffer.snapshot(cx);
10025        for selection in &mut selections {
10026            if selection.start.row != prev_edited_row {
10027                row_delta = 0;
10028            }
10029            prev_edited_row = selection.end.row;
10030
10031            row_delta =
10032                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10033        }
10034
10035        self.transact(window, cx, |this, window, cx| {
10036            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10037            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10038        });
10039    }
10040
10041    fn indent_selection(
10042        buffer: &MultiBuffer,
10043        snapshot: &MultiBufferSnapshot,
10044        selection: &mut Selection<Point>,
10045        edits: &mut Vec<(Range<Point>, String)>,
10046        delta_for_start_row: u32,
10047        cx: &App,
10048    ) -> u32 {
10049        let settings = buffer.language_settings_at(selection.start, cx);
10050        let tab_size = settings.tab_size.get();
10051        let indent_kind = if settings.hard_tabs {
10052            IndentKind::Tab
10053        } else {
10054            IndentKind::Space
10055        };
10056        let mut start_row = selection.start.row;
10057        let mut end_row = selection.end.row + 1;
10058
10059        // If a selection ends at the beginning of a line, don't indent
10060        // that last line.
10061        if selection.end.column == 0 && selection.end.row > selection.start.row {
10062            end_row -= 1;
10063        }
10064
10065        // Avoid re-indenting a row that has already been indented by a
10066        // previous selection, but still update this selection's column
10067        // to reflect that indentation.
10068        if delta_for_start_row > 0 {
10069            start_row += 1;
10070            selection.start.column += delta_for_start_row;
10071            if selection.end.row == selection.start.row {
10072                selection.end.column += delta_for_start_row;
10073            }
10074        }
10075
10076        let mut delta_for_end_row = 0;
10077        let has_multiple_rows = start_row + 1 != end_row;
10078        for row in start_row..end_row {
10079            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10080            let indent_delta = match (current_indent.kind, indent_kind) {
10081                (IndentKind::Space, IndentKind::Space) => {
10082                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10083                    IndentSize::spaces(columns_to_next_tab_stop)
10084                }
10085                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10086                (_, IndentKind::Tab) => IndentSize::tab(),
10087            };
10088
10089            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10090                0
10091            } else {
10092                selection.start.column
10093            };
10094            let row_start = Point::new(row, start);
10095            edits.push((
10096                row_start..row_start,
10097                indent_delta.chars().collect::<String>(),
10098            ));
10099
10100            // Update this selection's endpoints to reflect the indentation.
10101            if row == selection.start.row {
10102                selection.start.column += indent_delta.len;
10103            }
10104            if row == selection.end.row {
10105                selection.end.column += indent_delta.len;
10106                delta_for_end_row = indent_delta.len;
10107            }
10108        }
10109
10110        if selection.start.row == selection.end.row {
10111            delta_for_start_row + delta_for_end_row
10112        } else {
10113            delta_for_end_row
10114        }
10115    }
10116
10117    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10118        if self.read_only(cx) {
10119            return;
10120        }
10121        if self.mode.is_single_line() {
10122            cx.propagate();
10123            return;
10124        }
10125
10126        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10127        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10128        let selections = self.selections.all::<Point>(cx);
10129        let mut deletion_ranges = Vec::new();
10130        let mut last_outdent = None;
10131        {
10132            let buffer = self.buffer.read(cx);
10133            let snapshot = buffer.snapshot(cx);
10134            for selection in &selections {
10135                let settings = buffer.language_settings_at(selection.start, cx);
10136                let tab_size = settings.tab_size.get();
10137                let mut rows = selection.spanned_rows(false, &display_map);
10138
10139                // Avoid re-outdenting a row that has already been outdented by a
10140                // previous selection.
10141                if let Some(last_row) = last_outdent {
10142                    if last_row == rows.start {
10143                        rows.start = rows.start.next_row();
10144                    }
10145                }
10146                let has_multiple_rows = rows.len() > 1;
10147                for row in rows.iter_rows() {
10148                    let indent_size = snapshot.indent_size_for_line(row);
10149                    if indent_size.len > 0 {
10150                        let deletion_len = match indent_size.kind {
10151                            IndentKind::Space => {
10152                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10153                                if columns_to_prev_tab_stop == 0 {
10154                                    tab_size
10155                                } else {
10156                                    columns_to_prev_tab_stop
10157                                }
10158                            }
10159                            IndentKind::Tab => 1,
10160                        };
10161                        let start = if has_multiple_rows
10162                            || deletion_len > selection.start.column
10163                            || indent_size.len < selection.start.column
10164                        {
10165                            0
10166                        } else {
10167                            selection.start.column - deletion_len
10168                        };
10169                        deletion_ranges.push(
10170                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10171                        );
10172                        last_outdent = Some(row);
10173                    }
10174                }
10175            }
10176        }
10177
10178        self.transact(window, cx, |this, window, cx| {
10179            this.buffer.update(cx, |buffer, cx| {
10180                let empty_str: Arc<str> = Arc::default();
10181                buffer.edit(
10182                    deletion_ranges
10183                        .into_iter()
10184                        .map(|range| (range, empty_str.clone())),
10185                    None,
10186                    cx,
10187                );
10188            });
10189            let selections = this.selections.all::<usize>(cx);
10190            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10191        });
10192    }
10193
10194    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10195        if self.read_only(cx) {
10196            return;
10197        }
10198        if self.mode.is_single_line() {
10199            cx.propagate();
10200            return;
10201        }
10202
10203        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10204        let selections = self
10205            .selections
10206            .all::<usize>(cx)
10207            .into_iter()
10208            .map(|s| s.range());
10209
10210        self.transact(window, cx, |this, window, cx| {
10211            this.buffer.update(cx, |buffer, cx| {
10212                buffer.autoindent_ranges(selections, cx);
10213            });
10214            let selections = this.selections.all::<usize>(cx);
10215            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10216        });
10217    }
10218
10219    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10220        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10221        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10222        let selections = self.selections.all::<Point>(cx);
10223
10224        let mut new_cursors = Vec::new();
10225        let mut edit_ranges = Vec::new();
10226        let mut selections = selections.iter().peekable();
10227        while let Some(selection) = selections.next() {
10228            let mut rows = selection.spanned_rows(false, &display_map);
10229            let goal_display_column = selection.head().to_display_point(&display_map).column();
10230
10231            // Accumulate contiguous regions of rows that we want to delete.
10232            while let Some(next_selection) = selections.peek() {
10233                let next_rows = next_selection.spanned_rows(false, &display_map);
10234                if next_rows.start <= rows.end {
10235                    rows.end = next_rows.end;
10236                    selections.next().unwrap();
10237                } else {
10238                    break;
10239                }
10240            }
10241
10242            let buffer = &display_map.buffer_snapshot;
10243            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10244            let edit_end;
10245            let cursor_buffer_row;
10246            if buffer.max_point().row >= rows.end.0 {
10247                // If there's a line after the range, delete the \n from the end of the row range
10248                // and position the cursor on the next line.
10249                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10250                cursor_buffer_row = rows.end;
10251            } else {
10252                // If there isn't a line after the range, delete the \n from the line before the
10253                // start of the row range and position the cursor there.
10254                edit_start = edit_start.saturating_sub(1);
10255                edit_end = buffer.len();
10256                cursor_buffer_row = rows.start.previous_row();
10257            }
10258
10259            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10260            *cursor.column_mut() =
10261                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10262
10263            new_cursors.push((
10264                selection.id,
10265                buffer.anchor_after(cursor.to_point(&display_map)),
10266            ));
10267            edit_ranges.push(edit_start..edit_end);
10268        }
10269
10270        self.transact(window, cx, |this, window, cx| {
10271            let buffer = this.buffer.update(cx, |buffer, cx| {
10272                let empty_str: Arc<str> = Arc::default();
10273                buffer.edit(
10274                    edit_ranges
10275                        .into_iter()
10276                        .map(|range| (range, empty_str.clone())),
10277                    None,
10278                    cx,
10279                );
10280                buffer.snapshot(cx)
10281            });
10282            let new_selections = new_cursors
10283                .into_iter()
10284                .map(|(id, cursor)| {
10285                    let cursor = cursor.to_point(&buffer);
10286                    Selection {
10287                        id,
10288                        start: cursor,
10289                        end: cursor,
10290                        reversed: false,
10291                        goal: SelectionGoal::None,
10292                    }
10293                })
10294                .collect();
10295
10296            this.change_selections(Default::default(), window, cx, |s| {
10297                s.select(new_selections);
10298            });
10299        });
10300    }
10301
10302    pub fn join_lines_impl(
10303        &mut self,
10304        insert_whitespace: bool,
10305        window: &mut Window,
10306        cx: &mut Context<Self>,
10307    ) {
10308        if self.read_only(cx) {
10309            return;
10310        }
10311        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10312        for selection in self.selections.all::<Point>(cx) {
10313            let start = MultiBufferRow(selection.start.row);
10314            // Treat single line selections as if they include the next line. Otherwise this action
10315            // would do nothing for single line selections individual cursors.
10316            let end = if selection.start.row == selection.end.row {
10317                MultiBufferRow(selection.start.row + 1)
10318            } else {
10319                MultiBufferRow(selection.end.row)
10320            };
10321
10322            if let Some(last_row_range) = row_ranges.last_mut() {
10323                if start <= last_row_range.end {
10324                    last_row_range.end = end;
10325                    continue;
10326                }
10327            }
10328            row_ranges.push(start..end);
10329        }
10330
10331        let snapshot = self.buffer.read(cx).snapshot(cx);
10332        let mut cursor_positions = Vec::new();
10333        for row_range in &row_ranges {
10334            let anchor = snapshot.anchor_before(Point::new(
10335                row_range.end.previous_row().0,
10336                snapshot.line_len(row_range.end.previous_row()),
10337            ));
10338            cursor_positions.push(anchor..anchor);
10339        }
10340
10341        self.transact(window, cx, |this, window, cx| {
10342            for row_range in row_ranges.into_iter().rev() {
10343                for row in row_range.iter_rows().rev() {
10344                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10345                    let next_line_row = row.next_row();
10346                    let indent = snapshot.indent_size_for_line(next_line_row);
10347                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10348
10349                    let replace =
10350                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10351                            " "
10352                        } else {
10353                            ""
10354                        };
10355
10356                    this.buffer.update(cx, |buffer, cx| {
10357                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10358                    });
10359                }
10360            }
10361
10362            this.change_selections(Default::default(), window, cx, |s| {
10363                s.select_anchor_ranges(cursor_positions)
10364            });
10365        });
10366    }
10367
10368    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10369        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10370        self.join_lines_impl(true, window, cx);
10371    }
10372
10373    pub fn sort_lines_case_sensitive(
10374        &mut self,
10375        _: &SortLinesCaseSensitive,
10376        window: &mut Window,
10377        cx: &mut Context<Self>,
10378    ) {
10379        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10380    }
10381
10382    pub fn sort_lines_by_length(
10383        &mut self,
10384        _: &SortLinesByLength,
10385        window: &mut Window,
10386        cx: &mut Context<Self>,
10387    ) {
10388        self.manipulate_immutable_lines(window, cx, |lines| {
10389            lines.sort_by_key(|&line| line.chars().count())
10390        })
10391    }
10392
10393    pub fn sort_lines_case_insensitive(
10394        &mut self,
10395        _: &SortLinesCaseInsensitive,
10396        window: &mut Window,
10397        cx: &mut Context<Self>,
10398    ) {
10399        self.manipulate_immutable_lines(window, cx, |lines| {
10400            lines.sort_by_key(|line| line.to_lowercase())
10401        })
10402    }
10403
10404    pub fn unique_lines_case_insensitive(
10405        &mut self,
10406        _: &UniqueLinesCaseInsensitive,
10407        window: &mut Window,
10408        cx: &mut Context<Self>,
10409    ) {
10410        self.manipulate_immutable_lines(window, cx, |lines| {
10411            let mut seen = HashSet::default();
10412            lines.retain(|line| seen.insert(line.to_lowercase()));
10413        })
10414    }
10415
10416    pub fn unique_lines_case_sensitive(
10417        &mut self,
10418        _: &UniqueLinesCaseSensitive,
10419        window: &mut Window,
10420        cx: &mut Context<Self>,
10421    ) {
10422        self.manipulate_immutable_lines(window, cx, |lines| {
10423            let mut seen = HashSet::default();
10424            lines.retain(|line| seen.insert(*line));
10425        })
10426    }
10427
10428    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10429        let Some(project) = self.project.clone() else {
10430            return;
10431        };
10432        self.reload(project, window, cx)
10433            .detach_and_notify_err(window, cx);
10434    }
10435
10436    pub fn restore_file(
10437        &mut self,
10438        _: &::git::RestoreFile,
10439        window: &mut Window,
10440        cx: &mut Context<Self>,
10441    ) {
10442        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10443        let mut buffer_ids = HashSet::default();
10444        let snapshot = self.buffer().read(cx).snapshot(cx);
10445        for selection in self.selections.all::<usize>(cx) {
10446            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10447        }
10448
10449        let buffer = self.buffer().read(cx);
10450        let ranges = buffer_ids
10451            .into_iter()
10452            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10453            .collect::<Vec<_>>();
10454
10455        self.restore_hunks_in_ranges(ranges, window, cx);
10456    }
10457
10458    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10459        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10460        let selections = self
10461            .selections
10462            .all(cx)
10463            .into_iter()
10464            .map(|s| s.range())
10465            .collect();
10466        self.restore_hunks_in_ranges(selections, window, cx);
10467    }
10468
10469    pub fn restore_hunks_in_ranges(
10470        &mut self,
10471        ranges: Vec<Range<Point>>,
10472        window: &mut Window,
10473        cx: &mut Context<Editor>,
10474    ) {
10475        let mut revert_changes = HashMap::default();
10476        let chunk_by = self
10477            .snapshot(window, cx)
10478            .hunks_for_ranges(ranges)
10479            .into_iter()
10480            .chunk_by(|hunk| hunk.buffer_id);
10481        for (buffer_id, hunks) in &chunk_by {
10482            let hunks = hunks.collect::<Vec<_>>();
10483            for hunk in &hunks {
10484                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10485            }
10486            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10487        }
10488        drop(chunk_by);
10489        if !revert_changes.is_empty() {
10490            self.transact(window, cx, |editor, window, cx| {
10491                editor.restore(revert_changes, window, cx);
10492            });
10493        }
10494    }
10495
10496    pub fn open_active_item_in_terminal(
10497        &mut self,
10498        _: &OpenInTerminal,
10499        window: &mut Window,
10500        cx: &mut Context<Self>,
10501    ) {
10502        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10503            let project_path = buffer.read(cx).project_path(cx)?;
10504            let project = self.project.as_ref()?.read(cx);
10505            let entry = project.entry_for_path(&project_path, cx)?;
10506            let parent = match &entry.canonical_path {
10507                Some(canonical_path) => canonical_path.to_path_buf(),
10508                None => project.absolute_path(&project_path, cx)?,
10509            }
10510            .parent()?
10511            .to_path_buf();
10512            Some(parent)
10513        }) {
10514            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10515        }
10516    }
10517
10518    fn set_breakpoint_context_menu(
10519        &mut self,
10520        display_row: DisplayRow,
10521        position: Option<Anchor>,
10522        clicked_point: gpui::Point<Pixels>,
10523        window: &mut Window,
10524        cx: &mut Context<Self>,
10525    ) {
10526        let source = self
10527            .buffer
10528            .read(cx)
10529            .snapshot(cx)
10530            .anchor_before(Point::new(display_row.0, 0u32));
10531
10532        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10533
10534        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10535            self,
10536            source,
10537            clicked_point,
10538            context_menu,
10539            window,
10540            cx,
10541        );
10542    }
10543
10544    fn add_edit_breakpoint_block(
10545        &mut self,
10546        anchor: Anchor,
10547        breakpoint: &Breakpoint,
10548        edit_action: BreakpointPromptEditAction,
10549        window: &mut Window,
10550        cx: &mut Context<Self>,
10551    ) {
10552        let weak_editor = cx.weak_entity();
10553        let bp_prompt = cx.new(|cx| {
10554            BreakpointPromptEditor::new(
10555                weak_editor,
10556                anchor,
10557                breakpoint.clone(),
10558                edit_action,
10559                window,
10560                cx,
10561            )
10562        });
10563
10564        let height = bp_prompt.update(cx, |this, cx| {
10565            this.prompt
10566                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10567        });
10568        let cloned_prompt = bp_prompt.clone();
10569        let blocks = vec![BlockProperties {
10570            style: BlockStyle::Sticky,
10571            placement: BlockPlacement::Above(anchor),
10572            height: Some(height),
10573            render: Arc::new(move |cx| {
10574                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10575                cloned_prompt.clone().into_any_element()
10576            }),
10577            priority: 0,
10578        }];
10579
10580        let focus_handle = bp_prompt.focus_handle(cx);
10581        window.focus(&focus_handle);
10582
10583        let block_ids = self.insert_blocks(blocks, None, cx);
10584        bp_prompt.update(cx, |prompt, _| {
10585            prompt.add_block_ids(block_ids);
10586        });
10587    }
10588
10589    pub(crate) fn breakpoint_at_row(
10590        &self,
10591        row: u32,
10592        window: &mut Window,
10593        cx: &mut Context<Self>,
10594    ) -> Option<(Anchor, Breakpoint)> {
10595        let snapshot = self.snapshot(window, cx);
10596        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10597
10598        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10599    }
10600
10601    pub(crate) fn breakpoint_at_anchor(
10602        &self,
10603        breakpoint_position: Anchor,
10604        snapshot: &EditorSnapshot,
10605        cx: &mut Context<Self>,
10606    ) -> Option<(Anchor, Breakpoint)> {
10607        let project = self.project.clone()?;
10608
10609        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10610            snapshot
10611                .buffer_snapshot
10612                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10613        })?;
10614
10615        let enclosing_excerpt = breakpoint_position.excerpt_id;
10616        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10617        let buffer_snapshot = buffer.read(cx).snapshot();
10618
10619        let row = buffer_snapshot
10620            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10621            .row;
10622
10623        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10624        let anchor_end = snapshot
10625            .buffer_snapshot
10626            .anchor_after(Point::new(row, line_len));
10627
10628        let bp = self
10629            .breakpoint_store
10630            .as_ref()?
10631            .read_with(cx, |breakpoint_store, cx| {
10632                breakpoint_store
10633                    .breakpoints(
10634                        &buffer,
10635                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10636                        &buffer_snapshot,
10637                        cx,
10638                    )
10639                    .next()
10640                    .and_then(|(bp, _)| {
10641                        let breakpoint_row = buffer_snapshot
10642                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10643                            .row;
10644
10645                        if breakpoint_row == row {
10646                            snapshot
10647                                .buffer_snapshot
10648                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10649                                .map(|position| (position, bp.bp.clone()))
10650                        } else {
10651                            None
10652                        }
10653                    })
10654            });
10655        bp
10656    }
10657
10658    pub fn edit_log_breakpoint(
10659        &mut self,
10660        _: &EditLogBreakpoint,
10661        window: &mut Window,
10662        cx: &mut Context<Self>,
10663    ) {
10664        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10665            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10666                message: None,
10667                state: BreakpointState::Enabled,
10668                condition: None,
10669                hit_condition: None,
10670            });
10671
10672            self.add_edit_breakpoint_block(
10673                anchor,
10674                &breakpoint,
10675                BreakpointPromptEditAction::Log,
10676                window,
10677                cx,
10678            );
10679        }
10680    }
10681
10682    fn breakpoints_at_cursors(
10683        &self,
10684        window: &mut Window,
10685        cx: &mut Context<Self>,
10686    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10687        let snapshot = self.snapshot(window, cx);
10688        let cursors = self
10689            .selections
10690            .disjoint_anchors()
10691            .into_iter()
10692            .map(|selection| {
10693                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10694
10695                let breakpoint_position = self
10696                    .breakpoint_at_row(cursor_position.row, window, cx)
10697                    .map(|bp| bp.0)
10698                    .unwrap_or_else(|| {
10699                        snapshot
10700                            .display_snapshot
10701                            .buffer_snapshot
10702                            .anchor_after(Point::new(cursor_position.row, 0))
10703                    });
10704
10705                let breakpoint = self
10706                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10707                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10708
10709                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10710            })
10711            // 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.
10712            .collect::<HashMap<Anchor, _>>();
10713
10714        cursors.into_iter().collect()
10715    }
10716
10717    pub fn enable_breakpoint(
10718        &mut self,
10719        _: &crate::actions::EnableBreakpoint,
10720        window: &mut Window,
10721        cx: &mut Context<Self>,
10722    ) {
10723        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10724            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10725                continue;
10726            };
10727            self.edit_breakpoint_at_anchor(
10728                anchor,
10729                breakpoint,
10730                BreakpointEditAction::InvertState,
10731                cx,
10732            );
10733        }
10734    }
10735
10736    pub fn disable_breakpoint(
10737        &mut self,
10738        _: &crate::actions::DisableBreakpoint,
10739        window: &mut Window,
10740        cx: &mut Context<Self>,
10741    ) {
10742        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10743            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10744                continue;
10745            };
10746            self.edit_breakpoint_at_anchor(
10747                anchor,
10748                breakpoint,
10749                BreakpointEditAction::InvertState,
10750                cx,
10751            );
10752        }
10753    }
10754
10755    pub fn toggle_breakpoint(
10756        &mut self,
10757        _: &crate::actions::ToggleBreakpoint,
10758        window: &mut Window,
10759        cx: &mut Context<Self>,
10760    ) {
10761        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10762            if let Some(breakpoint) = breakpoint {
10763                self.edit_breakpoint_at_anchor(
10764                    anchor,
10765                    breakpoint,
10766                    BreakpointEditAction::Toggle,
10767                    cx,
10768                );
10769            } else {
10770                self.edit_breakpoint_at_anchor(
10771                    anchor,
10772                    Breakpoint::new_standard(),
10773                    BreakpointEditAction::Toggle,
10774                    cx,
10775                );
10776            }
10777        }
10778    }
10779
10780    pub fn edit_breakpoint_at_anchor(
10781        &mut self,
10782        breakpoint_position: Anchor,
10783        breakpoint: Breakpoint,
10784        edit_action: BreakpointEditAction,
10785        cx: &mut Context<Self>,
10786    ) {
10787        let Some(breakpoint_store) = &self.breakpoint_store else {
10788            return;
10789        };
10790
10791        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10792            if breakpoint_position == Anchor::min() {
10793                self.buffer()
10794                    .read(cx)
10795                    .excerpt_buffer_ids()
10796                    .into_iter()
10797                    .next()
10798            } else {
10799                None
10800            }
10801        }) else {
10802            return;
10803        };
10804
10805        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10806            return;
10807        };
10808
10809        breakpoint_store.update(cx, |breakpoint_store, cx| {
10810            breakpoint_store.toggle_breakpoint(
10811                buffer,
10812                BreakpointWithPosition {
10813                    position: breakpoint_position.text_anchor,
10814                    bp: breakpoint,
10815                },
10816                edit_action,
10817                cx,
10818            );
10819        });
10820
10821        cx.notify();
10822    }
10823
10824    #[cfg(any(test, feature = "test-support"))]
10825    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10826        self.breakpoint_store.clone()
10827    }
10828
10829    pub fn prepare_restore_change(
10830        &self,
10831        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10832        hunk: &MultiBufferDiffHunk,
10833        cx: &mut App,
10834    ) -> Option<()> {
10835        if hunk.is_created_file() {
10836            return None;
10837        }
10838        let buffer = self.buffer.read(cx);
10839        let diff = buffer.diff_for(hunk.buffer_id)?;
10840        let buffer = buffer.buffer(hunk.buffer_id)?;
10841        let buffer = buffer.read(cx);
10842        let original_text = diff
10843            .read(cx)
10844            .base_text()
10845            .as_rope()
10846            .slice(hunk.diff_base_byte_range.clone());
10847        let buffer_snapshot = buffer.snapshot();
10848        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10849        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10850            probe
10851                .0
10852                .start
10853                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10854                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10855        }) {
10856            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10857            Some(())
10858        } else {
10859            None
10860        }
10861    }
10862
10863    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10864        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10865    }
10866
10867    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10868        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10869    }
10870
10871    fn manipulate_lines<M>(
10872        &mut self,
10873        window: &mut Window,
10874        cx: &mut Context<Self>,
10875        mut manipulate: M,
10876    ) where
10877        M: FnMut(&str) -> LineManipulationResult,
10878    {
10879        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10880
10881        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10882        let buffer = self.buffer.read(cx).snapshot(cx);
10883
10884        let mut edits = Vec::new();
10885
10886        let selections = self.selections.all::<Point>(cx);
10887        let mut selections = selections.iter().peekable();
10888        let mut contiguous_row_selections = Vec::new();
10889        let mut new_selections = Vec::new();
10890        let mut added_lines = 0;
10891        let mut removed_lines = 0;
10892
10893        while let Some(selection) = selections.next() {
10894            let (start_row, end_row) = consume_contiguous_rows(
10895                &mut contiguous_row_selections,
10896                selection,
10897                &display_map,
10898                &mut selections,
10899            );
10900
10901            let start_point = Point::new(start_row.0, 0);
10902            let end_point = Point::new(
10903                end_row.previous_row().0,
10904                buffer.line_len(end_row.previous_row()),
10905            );
10906            let text = buffer
10907                .text_for_range(start_point..end_point)
10908                .collect::<String>();
10909
10910            let LineManipulationResult {
10911                new_text,
10912                line_count_before,
10913                line_count_after,
10914            } = manipulate(&text);
10915
10916            edits.push((start_point..end_point, new_text));
10917
10918            // Selections must change based on added and removed line count
10919            let start_row =
10920                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10921            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10922            new_selections.push(Selection {
10923                id: selection.id,
10924                start: start_row,
10925                end: end_row,
10926                goal: SelectionGoal::None,
10927                reversed: selection.reversed,
10928            });
10929
10930            if line_count_after > line_count_before {
10931                added_lines += line_count_after - line_count_before;
10932            } else if line_count_before > line_count_after {
10933                removed_lines += line_count_before - line_count_after;
10934            }
10935        }
10936
10937        self.transact(window, cx, |this, window, cx| {
10938            let buffer = this.buffer.update(cx, |buffer, cx| {
10939                buffer.edit(edits, None, cx);
10940                buffer.snapshot(cx)
10941            });
10942
10943            // Recalculate offsets on newly edited buffer
10944            let new_selections = new_selections
10945                .iter()
10946                .map(|s| {
10947                    let start_point = Point::new(s.start.0, 0);
10948                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10949                    Selection {
10950                        id: s.id,
10951                        start: buffer.point_to_offset(start_point),
10952                        end: buffer.point_to_offset(end_point),
10953                        goal: s.goal,
10954                        reversed: s.reversed,
10955                    }
10956                })
10957                .collect();
10958
10959            this.change_selections(Default::default(), window, cx, |s| {
10960                s.select(new_selections);
10961            });
10962
10963            this.request_autoscroll(Autoscroll::fit(), cx);
10964        });
10965    }
10966
10967    fn manipulate_immutable_lines<Fn>(
10968        &mut self,
10969        window: &mut Window,
10970        cx: &mut Context<Self>,
10971        mut callback: Fn,
10972    ) where
10973        Fn: FnMut(&mut Vec<&str>),
10974    {
10975        self.manipulate_lines(window, cx, |text| {
10976            let mut lines: Vec<&str> = text.split('\n').collect();
10977            let line_count_before = lines.len();
10978
10979            callback(&mut lines);
10980
10981            LineManipulationResult {
10982                new_text: lines.join("\n"),
10983                line_count_before,
10984                line_count_after: lines.len(),
10985            }
10986        });
10987    }
10988
10989    fn manipulate_mutable_lines<Fn>(
10990        &mut self,
10991        window: &mut Window,
10992        cx: &mut Context<Self>,
10993        mut callback: Fn,
10994    ) where
10995        Fn: FnMut(&mut Vec<Cow<'_, str>>),
10996    {
10997        self.manipulate_lines(window, cx, |text| {
10998            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
10999            let line_count_before = lines.len();
11000
11001            callback(&mut lines);
11002
11003            LineManipulationResult {
11004                new_text: lines.join("\n"),
11005                line_count_before,
11006                line_count_after: lines.len(),
11007            }
11008        });
11009    }
11010
11011    pub fn convert_indentation_to_spaces(
11012        &mut self,
11013        _: &ConvertIndentationToSpaces,
11014        window: &mut Window,
11015        cx: &mut Context<Self>,
11016    ) {
11017        let settings = self.buffer.read(cx).language_settings(cx);
11018        let tab_size = settings.tab_size.get() as usize;
11019
11020        self.manipulate_mutable_lines(window, cx, |lines| {
11021            // Allocates a reasonably sized scratch buffer once for the whole loop
11022            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11023            // Avoids recomputing spaces that could be inserted many times
11024            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11025                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11026                .collect();
11027
11028            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11029                let mut chars = line.as_ref().chars();
11030                let mut col = 0;
11031                let mut changed = false;
11032
11033                while let Some(ch) = chars.next() {
11034                    match ch {
11035                        ' ' => {
11036                            reindented_line.push(' ');
11037                            col += 1;
11038                        }
11039                        '\t' => {
11040                            // \t are converted to spaces depending on the current column
11041                            let spaces_len = tab_size - (col % tab_size);
11042                            reindented_line.extend(&space_cache[spaces_len - 1]);
11043                            col += spaces_len;
11044                            changed = true;
11045                        }
11046                        _ => {
11047                            // If we dont append before break, the character is consumed
11048                            reindented_line.push(ch);
11049                            break;
11050                        }
11051                    }
11052                }
11053
11054                if !changed {
11055                    reindented_line.clear();
11056                    continue;
11057                }
11058                // Append the rest of the line and replace old reference with new one
11059                reindented_line.extend(chars);
11060                *line = Cow::Owned(reindented_line.clone());
11061                reindented_line.clear();
11062            }
11063        });
11064    }
11065
11066    pub fn convert_indentation_to_tabs(
11067        &mut self,
11068        _: &ConvertIndentationToTabs,
11069        window: &mut Window,
11070        cx: &mut Context<Self>,
11071    ) {
11072        let settings = self.buffer.read(cx).language_settings(cx);
11073        let tab_size = settings.tab_size.get() as usize;
11074
11075        self.manipulate_mutable_lines(window, cx, |lines| {
11076            // Allocates a reasonably sized buffer once for the whole loop
11077            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11078            // Avoids recomputing spaces that could be inserted many times
11079            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11080                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11081                .collect();
11082
11083            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11084                let mut chars = line.chars();
11085                let mut spaces_count = 0;
11086                let mut first_non_indent_char = None;
11087                let mut changed = false;
11088
11089                while let Some(ch) = chars.next() {
11090                    match ch {
11091                        ' ' => {
11092                            // Keep track of spaces. Append \t when we reach tab_size
11093                            spaces_count += 1;
11094                            changed = true;
11095                            if spaces_count == tab_size {
11096                                reindented_line.push('\t');
11097                                spaces_count = 0;
11098                            }
11099                        }
11100                        '\t' => {
11101                            reindented_line.push('\t');
11102                            spaces_count = 0;
11103                        }
11104                        _ => {
11105                            // Dont append it yet, we might have remaining spaces
11106                            first_non_indent_char = Some(ch);
11107                            break;
11108                        }
11109                    }
11110                }
11111
11112                if !changed {
11113                    reindented_line.clear();
11114                    continue;
11115                }
11116                // Remaining spaces that didn't make a full tab stop
11117                if spaces_count > 0 {
11118                    reindented_line.extend(&space_cache[spaces_count - 1]);
11119                }
11120                // If we consume an extra character that was not indentation, add it back
11121                if let Some(extra_char) = first_non_indent_char {
11122                    reindented_line.push(extra_char);
11123                }
11124                // Append the rest of the line and replace old reference with new one
11125                reindented_line.extend(chars);
11126                *line = Cow::Owned(reindented_line.clone());
11127                reindented_line.clear();
11128            }
11129        });
11130    }
11131
11132    pub fn convert_to_upper_case(
11133        &mut self,
11134        _: &ConvertToUpperCase,
11135        window: &mut Window,
11136        cx: &mut Context<Self>,
11137    ) {
11138        self.manipulate_text(window, cx, |text| text.to_uppercase())
11139    }
11140
11141    pub fn convert_to_lower_case(
11142        &mut self,
11143        _: &ConvertToLowerCase,
11144        window: &mut Window,
11145        cx: &mut Context<Self>,
11146    ) {
11147        self.manipulate_text(window, cx, |text| text.to_lowercase())
11148    }
11149
11150    pub fn convert_to_title_case(
11151        &mut self,
11152        _: &ConvertToTitleCase,
11153        window: &mut Window,
11154        cx: &mut Context<Self>,
11155    ) {
11156        self.manipulate_text(window, cx, |text| {
11157            text.split('\n')
11158                .map(|line| line.to_case(Case::Title))
11159                .join("\n")
11160        })
11161    }
11162
11163    pub fn convert_to_snake_case(
11164        &mut self,
11165        _: &ConvertToSnakeCase,
11166        window: &mut Window,
11167        cx: &mut Context<Self>,
11168    ) {
11169        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11170    }
11171
11172    pub fn convert_to_kebab_case(
11173        &mut self,
11174        _: &ConvertToKebabCase,
11175        window: &mut Window,
11176        cx: &mut Context<Self>,
11177    ) {
11178        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11179    }
11180
11181    pub fn convert_to_upper_camel_case(
11182        &mut self,
11183        _: &ConvertToUpperCamelCase,
11184        window: &mut Window,
11185        cx: &mut Context<Self>,
11186    ) {
11187        self.manipulate_text(window, cx, |text| {
11188            text.split('\n')
11189                .map(|line| line.to_case(Case::UpperCamel))
11190                .join("\n")
11191        })
11192    }
11193
11194    pub fn convert_to_lower_camel_case(
11195        &mut self,
11196        _: &ConvertToLowerCamelCase,
11197        window: &mut Window,
11198        cx: &mut Context<Self>,
11199    ) {
11200        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11201    }
11202
11203    pub fn convert_to_opposite_case(
11204        &mut self,
11205        _: &ConvertToOppositeCase,
11206        window: &mut Window,
11207        cx: &mut Context<Self>,
11208    ) {
11209        self.manipulate_text(window, cx, |text| {
11210            text.chars()
11211                .fold(String::with_capacity(text.len()), |mut t, c| {
11212                    if c.is_uppercase() {
11213                        t.extend(c.to_lowercase());
11214                    } else {
11215                        t.extend(c.to_uppercase());
11216                    }
11217                    t
11218                })
11219        })
11220    }
11221
11222    pub fn convert_to_sentence_case(
11223        &mut self,
11224        _: &ConvertToSentenceCase,
11225        window: &mut Window,
11226        cx: &mut Context<Self>,
11227    ) {
11228        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11229    }
11230
11231    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11232        self.manipulate_text(window, cx, |text| {
11233            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11234            if has_upper_case_characters {
11235                text.to_lowercase()
11236            } else {
11237                text.to_uppercase()
11238            }
11239        })
11240    }
11241
11242    pub fn convert_to_rot13(
11243        &mut self,
11244        _: &ConvertToRot13,
11245        window: &mut Window,
11246        cx: &mut Context<Self>,
11247    ) {
11248        self.manipulate_text(window, cx, |text| {
11249            text.chars()
11250                .map(|c| match c {
11251                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11252                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11253                    _ => c,
11254                })
11255                .collect()
11256        })
11257    }
11258
11259    pub fn convert_to_rot47(
11260        &mut self,
11261        _: &ConvertToRot47,
11262        window: &mut Window,
11263        cx: &mut Context<Self>,
11264    ) {
11265        self.manipulate_text(window, cx, |text| {
11266            text.chars()
11267                .map(|c| {
11268                    let code_point = c as u32;
11269                    if code_point >= 33 && code_point <= 126 {
11270                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11271                    }
11272                    c
11273                })
11274                .collect()
11275        })
11276    }
11277
11278    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11279    where
11280        Fn: FnMut(&str) -> String,
11281    {
11282        let buffer = self.buffer.read(cx).snapshot(cx);
11283
11284        let mut new_selections = Vec::new();
11285        let mut edits = Vec::new();
11286        let mut selection_adjustment = 0i32;
11287
11288        for selection in self.selections.all::<usize>(cx) {
11289            let selection_is_empty = selection.is_empty();
11290
11291            let (start, end) = if selection_is_empty {
11292                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11293                (word_range.start, word_range.end)
11294            } else {
11295                (selection.start, selection.end)
11296            };
11297
11298            let text = buffer.text_for_range(start..end).collect::<String>();
11299            let old_length = text.len() as i32;
11300            let text = callback(&text);
11301
11302            new_selections.push(Selection {
11303                start: (start as i32 - selection_adjustment) as usize,
11304                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11305                goal: SelectionGoal::None,
11306                ..selection
11307            });
11308
11309            selection_adjustment += old_length - text.len() as i32;
11310
11311            edits.push((start..end, text));
11312        }
11313
11314        self.transact(window, cx, |this, window, cx| {
11315            this.buffer.update(cx, |buffer, cx| {
11316                buffer.edit(edits, None, cx);
11317            });
11318
11319            this.change_selections(Default::default(), window, cx, |s| {
11320                s.select(new_selections);
11321            });
11322
11323            this.request_autoscroll(Autoscroll::fit(), cx);
11324        });
11325    }
11326
11327    pub fn move_selection_on_drop(
11328        &mut self,
11329        selection: &Selection<Anchor>,
11330        target: DisplayPoint,
11331        is_cut: bool,
11332        window: &mut Window,
11333        cx: &mut Context<Self>,
11334    ) {
11335        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11336        let buffer = &display_map.buffer_snapshot;
11337        let mut edits = Vec::new();
11338        let insert_point = display_map
11339            .clip_point(target, Bias::Left)
11340            .to_point(&display_map);
11341        let text = buffer
11342            .text_for_range(selection.start..selection.end)
11343            .collect::<String>();
11344        if is_cut {
11345            edits.push(((selection.start..selection.end), String::new()));
11346        }
11347        let insert_anchor = buffer.anchor_before(insert_point);
11348        edits.push(((insert_anchor..insert_anchor), text));
11349        let last_edit_start = insert_anchor.bias_left(buffer);
11350        let last_edit_end = insert_anchor.bias_right(buffer);
11351        self.transact(window, cx, |this, window, cx| {
11352            this.buffer.update(cx, |buffer, cx| {
11353                buffer.edit(edits, None, cx);
11354            });
11355            this.change_selections(Default::default(), window, cx, |s| {
11356                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11357            });
11358        });
11359    }
11360
11361    pub fn clear_selection_drag_state(&mut self) {
11362        self.selection_drag_state = SelectionDragState::None;
11363    }
11364
11365    pub fn duplicate(
11366        &mut self,
11367        upwards: bool,
11368        whole_lines: bool,
11369        window: &mut Window,
11370        cx: &mut Context<Self>,
11371    ) {
11372        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11373
11374        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11375        let buffer = &display_map.buffer_snapshot;
11376        let selections = self.selections.all::<Point>(cx);
11377
11378        let mut edits = Vec::new();
11379        let mut selections_iter = selections.iter().peekable();
11380        while let Some(selection) = selections_iter.next() {
11381            let mut rows = selection.spanned_rows(false, &display_map);
11382            // duplicate line-wise
11383            if whole_lines || selection.start == selection.end {
11384                // Avoid duplicating the same lines twice.
11385                while let Some(next_selection) = selections_iter.peek() {
11386                    let next_rows = next_selection.spanned_rows(false, &display_map);
11387                    if next_rows.start < rows.end {
11388                        rows.end = next_rows.end;
11389                        selections_iter.next().unwrap();
11390                    } else {
11391                        break;
11392                    }
11393                }
11394
11395                // Copy the text from the selected row region and splice it either at the start
11396                // or end of the region.
11397                let start = Point::new(rows.start.0, 0);
11398                let end = Point::new(
11399                    rows.end.previous_row().0,
11400                    buffer.line_len(rows.end.previous_row()),
11401                );
11402                let text = buffer
11403                    .text_for_range(start..end)
11404                    .chain(Some("\n"))
11405                    .collect::<String>();
11406                let insert_location = if upwards {
11407                    Point::new(rows.end.0, 0)
11408                } else {
11409                    start
11410                };
11411                edits.push((insert_location..insert_location, text));
11412            } else {
11413                // duplicate character-wise
11414                let start = selection.start;
11415                let end = selection.end;
11416                let text = buffer.text_for_range(start..end).collect::<String>();
11417                edits.push((selection.end..selection.end, text));
11418            }
11419        }
11420
11421        self.transact(window, cx, |this, _, cx| {
11422            this.buffer.update(cx, |buffer, cx| {
11423                buffer.edit(edits, None, cx);
11424            });
11425
11426            this.request_autoscroll(Autoscroll::fit(), cx);
11427        });
11428    }
11429
11430    pub fn duplicate_line_up(
11431        &mut self,
11432        _: &DuplicateLineUp,
11433        window: &mut Window,
11434        cx: &mut Context<Self>,
11435    ) {
11436        self.duplicate(true, true, window, cx);
11437    }
11438
11439    pub fn duplicate_line_down(
11440        &mut self,
11441        _: &DuplicateLineDown,
11442        window: &mut Window,
11443        cx: &mut Context<Self>,
11444    ) {
11445        self.duplicate(false, true, window, cx);
11446    }
11447
11448    pub fn duplicate_selection(
11449        &mut self,
11450        _: &DuplicateSelection,
11451        window: &mut Window,
11452        cx: &mut Context<Self>,
11453    ) {
11454        self.duplicate(false, false, window, cx);
11455    }
11456
11457    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11458        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11459        if self.mode.is_single_line() {
11460            cx.propagate();
11461            return;
11462        }
11463
11464        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11465        let buffer = self.buffer.read(cx).snapshot(cx);
11466
11467        let mut edits = Vec::new();
11468        let mut unfold_ranges = Vec::new();
11469        let mut refold_creases = Vec::new();
11470
11471        let selections = self.selections.all::<Point>(cx);
11472        let mut selections = selections.iter().peekable();
11473        let mut contiguous_row_selections = Vec::new();
11474        let mut new_selections = Vec::new();
11475
11476        while let Some(selection) = selections.next() {
11477            // Find all the selections that span a contiguous row range
11478            let (start_row, end_row) = consume_contiguous_rows(
11479                &mut contiguous_row_selections,
11480                selection,
11481                &display_map,
11482                &mut selections,
11483            );
11484
11485            // Move the text spanned by the row range to be before the line preceding the row range
11486            if start_row.0 > 0 {
11487                let range_to_move = Point::new(
11488                    start_row.previous_row().0,
11489                    buffer.line_len(start_row.previous_row()),
11490                )
11491                    ..Point::new(
11492                        end_row.previous_row().0,
11493                        buffer.line_len(end_row.previous_row()),
11494                    );
11495                let insertion_point = display_map
11496                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11497                    .0;
11498
11499                // Don't move lines across excerpts
11500                if buffer
11501                    .excerpt_containing(insertion_point..range_to_move.end)
11502                    .is_some()
11503                {
11504                    let text = buffer
11505                        .text_for_range(range_to_move.clone())
11506                        .flat_map(|s| s.chars())
11507                        .skip(1)
11508                        .chain(['\n'])
11509                        .collect::<String>();
11510
11511                    edits.push((
11512                        buffer.anchor_after(range_to_move.start)
11513                            ..buffer.anchor_before(range_to_move.end),
11514                        String::new(),
11515                    ));
11516                    let insertion_anchor = buffer.anchor_after(insertion_point);
11517                    edits.push((insertion_anchor..insertion_anchor, text));
11518
11519                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11520
11521                    // Move selections up
11522                    new_selections.extend(contiguous_row_selections.drain(..).map(
11523                        |mut selection| {
11524                            selection.start.row -= row_delta;
11525                            selection.end.row -= row_delta;
11526                            selection
11527                        },
11528                    ));
11529
11530                    // Move folds up
11531                    unfold_ranges.push(range_to_move.clone());
11532                    for fold in display_map.folds_in_range(
11533                        buffer.anchor_before(range_to_move.start)
11534                            ..buffer.anchor_after(range_to_move.end),
11535                    ) {
11536                        let mut start = fold.range.start.to_point(&buffer);
11537                        let mut end = fold.range.end.to_point(&buffer);
11538                        start.row -= row_delta;
11539                        end.row -= row_delta;
11540                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11541                    }
11542                }
11543            }
11544
11545            // If we didn't move line(s), preserve the existing selections
11546            new_selections.append(&mut contiguous_row_selections);
11547        }
11548
11549        self.transact(window, cx, |this, window, cx| {
11550            this.unfold_ranges(&unfold_ranges, true, true, cx);
11551            this.buffer.update(cx, |buffer, cx| {
11552                for (range, text) in edits {
11553                    buffer.edit([(range, text)], None, cx);
11554                }
11555            });
11556            this.fold_creases(refold_creases, true, window, cx);
11557            this.change_selections(Default::default(), window, cx, |s| {
11558                s.select(new_selections);
11559            })
11560        });
11561    }
11562
11563    pub fn move_line_down(
11564        &mut self,
11565        _: &MoveLineDown,
11566        window: &mut Window,
11567        cx: &mut Context<Self>,
11568    ) {
11569        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11570        if self.mode.is_single_line() {
11571            cx.propagate();
11572            return;
11573        }
11574
11575        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11576        let buffer = self.buffer.read(cx).snapshot(cx);
11577
11578        let mut edits = Vec::new();
11579        let mut unfold_ranges = Vec::new();
11580        let mut refold_creases = Vec::new();
11581
11582        let selections = self.selections.all::<Point>(cx);
11583        let mut selections = selections.iter().peekable();
11584        let mut contiguous_row_selections = Vec::new();
11585        let mut new_selections = Vec::new();
11586
11587        while let Some(selection) = selections.next() {
11588            // Find all the selections that span a contiguous row range
11589            let (start_row, end_row) = consume_contiguous_rows(
11590                &mut contiguous_row_selections,
11591                selection,
11592                &display_map,
11593                &mut selections,
11594            );
11595
11596            // Move the text spanned by the row range to be after the last line of the row range
11597            if end_row.0 <= buffer.max_point().row {
11598                let range_to_move =
11599                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11600                let insertion_point = display_map
11601                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11602                    .0;
11603
11604                // Don't move lines across excerpt boundaries
11605                if buffer
11606                    .excerpt_containing(range_to_move.start..insertion_point)
11607                    .is_some()
11608                {
11609                    let mut text = String::from("\n");
11610                    text.extend(buffer.text_for_range(range_to_move.clone()));
11611                    text.pop(); // Drop trailing newline
11612                    edits.push((
11613                        buffer.anchor_after(range_to_move.start)
11614                            ..buffer.anchor_before(range_to_move.end),
11615                        String::new(),
11616                    ));
11617                    let insertion_anchor = buffer.anchor_after(insertion_point);
11618                    edits.push((insertion_anchor..insertion_anchor, text));
11619
11620                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11621
11622                    // Move selections down
11623                    new_selections.extend(contiguous_row_selections.drain(..).map(
11624                        |mut selection| {
11625                            selection.start.row += row_delta;
11626                            selection.end.row += row_delta;
11627                            selection
11628                        },
11629                    ));
11630
11631                    // Move folds down
11632                    unfold_ranges.push(range_to_move.clone());
11633                    for fold in display_map.folds_in_range(
11634                        buffer.anchor_before(range_to_move.start)
11635                            ..buffer.anchor_after(range_to_move.end),
11636                    ) {
11637                        let mut start = fold.range.start.to_point(&buffer);
11638                        let mut end = fold.range.end.to_point(&buffer);
11639                        start.row += row_delta;
11640                        end.row += row_delta;
11641                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11642                    }
11643                }
11644            }
11645
11646            // If we didn't move line(s), preserve the existing selections
11647            new_selections.append(&mut contiguous_row_selections);
11648        }
11649
11650        self.transact(window, cx, |this, window, cx| {
11651            this.unfold_ranges(&unfold_ranges, true, true, cx);
11652            this.buffer.update(cx, |buffer, cx| {
11653                for (range, text) in edits {
11654                    buffer.edit([(range, text)], None, cx);
11655                }
11656            });
11657            this.fold_creases(refold_creases, true, window, cx);
11658            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11659        });
11660    }
11661
11662    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11663        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11664        let text_layout_details = &self.text_layout_details(window);
11665        self.transact(window, cx, |this, window, cx| {
11666            let edits = this.change_selections(Default::default(), window, cx, |s| {
11667                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11668                s.move_with(|display_map, selection| {
11669                    if !selection.is_empty() {
11670                        return;
11671                    }
11672
11673                    let mut head = selection.head();
11674                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11675                    if head.column() == display_map.line_len(head.row()) {
11676                        transpose_offset = display_map
11677                            .buffer_snapshot
11678                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11679                    }
11680
11681                    if transpose_offset == 0 {
11682                        return;
11683                    }
11684
11685                    *head.column_mut() += 1;
11686                    head = display_map.clip_point(head, Bias::Right);
11687                    let goal = SelectionGoal::HorizontalPosition(
11688                        display_map
11689                            .x_for_display_point(head, text_layout_details)
11690                            .into(),
11691                    );
11692                    selection.collapse_to(head, goal);
11693
11694                    let transpose_start = display_map
11695                        .buffer_snapshot
11696                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11697                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11698                        let transpose_end = display_map
11699                            .buffer_snapshot
11700                            .clip_offset(transpose_offset + 1, Bias::Right);
11701                        if let Some(ch) =
11702                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11703                        {
11704                            edits.push((transpose_start..transpose_offset, String::new()));
11705                            edits.push((transpose_end..transpose_end, ch.to_string()));
11706                        }
11707                    }
11708                });
11709                edits
11710            });
11711            this.buffer
11712                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11713            let selections = this.selections.all::<usize>(cx);
11714            this.change_selections(Default::default(), window, cx, |s| {
11715                s.select(selections);
11716            });
11717        });
11718    }
11719
11720    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11721        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11722        if self.mode.is_single_line() {
11723            cx.propagate();
11724            return;
11725        }
11726
11727        self.rewrap_impl(RewrapOptions::default(), cx)
11728    }
11729
11730    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11731        let buffer = self.buffer.read(cx).snapshot(cx);
11732        let selections = self.selections.all::<Point>(cx);
11733
11734        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11735        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11736            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11737                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11738                .peekable();
11739
11740            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11741                row
11742            } else {
11743                return Vec::new();
11744            };
11745
11746            let language_settings = buffer.language_settings_at(selection.head(), cx);
11747            let language_scope = buffer.language_scope_at(selection.head());
11748
11749            let indent_and_prefix_for_row =
11750                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11751                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11752                    let (comment_prefix, rewrap_prefix) =
11753                        if let Some(language_scope) = &language_scope {
11754                            let indent_end = Point::new(row, indent.len);
11755                            let comment_prefix = language_scope
11756                                .line_comment_prefixes()
11757                                .iter()
11758                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11759                                .map(|prefix| prefix.to_string());
11760                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11761                            let line_text_after_indent = buffer
11762                                .text_for_range(indent_end..line_end)
11763                                .collect::<String>();
11764                            let rewrap_prefix = language_scope
11765                                .rewrap_prefixes()
11766                                .iter()
11767                                .find_map(|prefix_regex| {
11768                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11769                                        if mat.start() == 0 {
11770                                            Some(mat.as_str().to_string())
11771                                        } else {
11772                                            None
11773                                        }
11774                                    })
11775                                })
11776                                .flatten();
11777                            (comment_prefix, rewrap_prefix)
11778                        } else {
11779                            (None, None)
11780                        };
11781                    (indent, comment_prefix, rewrap_prefix)
11782                };
11783
11784            let mut ranges = Vec::new();
11785            let from_empty_selection = selection.is_empty();
11786
11787            let mut current_range_start = first_row;
11788            let mut prev_row = first_row;
11789            let (
11790                mut current_range_indent,
11791                mut current_range_comment_prefix,
11792                mut current_range_rewrap_prefix,
11793            ) = indent_and_prefix_for_row(first_row);
11794
11795            for row in non_blank_rows_iter.skip(1) {
11796                let has_paragraph_break = row > prev_row + 1;
11797
11798                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11799                    indent_and_prefix_for_row(row);
11800
11801                let has_indent_change = row_indent != current_range_indent;
11802                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11803
11804                let has_boundary_change = has_comment_change
11805                    || row_rewrap_prefix.is_some()
11806                    || (has_indent_change && current_range_comment_prefix.is_some());
11807
11808                if has_paragraph_break || has_boundary_change {
11809                    ranges.push((
11810                        language_settings.clone(),
11811                        Point::new(current_range_start, 0)
11812                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11813                        current_range_indent,
11814                        current_range_comment_prefix.clone(),
11815                        current_range_rewrap_prefix.clone(),
11816                        from_empty_selection,
11817                    ));
11818                    current_range_start = row;
11819                    current_range_indent = row_indent;
11820                    current_range_comment_prefix = row_comment_prefix;
11821                    current_range_rewrap_prefix = row_rewrap_prefix;
11822                }
11823                prev_row = row;
11824            }
11825
11826            ranges.push((
11827                language_settings.clone(),
11828                Point::new(current_range_start, 0)
11829                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11830                current_range_indent,
11831                current_range_comment_prefix,
11832                current_range_rewrap_prefix,
11833                from_empty_selection,
11834            ));
11835
11836            ranges
11837        });
11838
11839        let mut edits = Vec::new();
11840        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11841
11842        for (
11843            language_settings,
11844            wrap_range,
11845            indent_size,
11846            comment_prefix,
11847            rewrap_prefix,
11848            from_empty_selection,
11849        ) in wrap_ranges
11850        {
11851            let mut start_row = wrap_range.start.row;
11852            let mut end_row = wrap_range.end.row;
11853
11854            // Skip selections that overlap with a range that has already been rewrapped.
11855            let selection_range = start_row..end_row;
11856            if rewrapped_row_ranges
11857                .iter()
11858                .any(|range| range.overlaps(&selection_range))
11859            {
11860                continue;
11861            }
11862
11863            let tab_size = language_settings.tab_size;
11864
11865            let indent_prefix = indent_size.chars().collect::<String>();
11866            let mut line_prefix = indent_prefix.clone();
11867            let mut inside_comment = false;
11868            if let Some(prefix) = &comment_prefix {
11869                line_prefix.push_str(prefix);
11870                inside_comment = true;
11871            }
11872            if let Some(prefix) = &rewrap_prefix {
11873                line_prefix.push_str(prefix);
11874            }
11875
11876            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11877                RewrapBehavior::InComments => inside_comment,
11878                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11879                RewrapBehavior::Anywhere => true,
11880            };
11881
11882            let should_rewrap = options.override_language_settings
11883                || allow_rewrap_based_on_language
11884                || self.hard_wrap.is_some();
11885            if !should_rewrap {
11886                continue;
11887            }
11888
11889            if from_empty_selection {
11890                'expand_upwards: while start_row > 0 {
11891                    let prev_row = start_row - 1;
11892                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11893                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11894                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11895                    {
11896                        start_row = prev_row;
11897                    } else {
11898                        break 'expand_upwards;
11899                    }
11900                }
11901
11902                'expand_downwards: while end_row < buffer.max_point().row {
11903                    let next_row = end_row + 1;
11904                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11905                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11906                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11907                    {
11908                        end_row = next_row;
11909                    } else {
11910                        break 'expand_downwards;
11911                    }
11912                }
11913            }
11914
11915            let start = Point::new(start_row, 0);
11916            let start_offset = start.to_offset(&buffer);
11917            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11918            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11919            let Some(lines_without_prefixes) = selection_text
11920                .lines()
11921                .enumerate()
11922                .map(|(ix, line)| {
11923                    let line_trimmed = line.trim_start();
11924                    if rewrap_prefix.is_some() && ix > 0 {
11925                        Ok(line_trimmed)
11926                    } else {
11927                        line_trimmed
11928                            .strip_prefix(&line_prefix.trim_start())
11929                            .with_context(|| {
11930                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11931                            })
11932                    }
11933                })
11934                .collect::<Result<Vec<_>, _>>()
11935                .log_err()
11936            else {
11937                continue;
11938            };
11939
11940            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11941                buffer
11942                    .language_settings_at(Point::new(start_row, 0), cx)
11943                    .preferred_line_length as usize
11944            });
11945
11946            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11947                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11948            } else {
11949                line_prefix.clone()
11950            };
11951
11952            let wrapped_text = wrap_with_prefix(
11953                line_prefix,
11954                subsequent_lines_prefix,
11955                lines_without_prefixes.join("\n"),
11956                wrap_column,
11957                tab_size,
11958                options.preserve_existing_whitespace,
11959            );
11960
11961            // TODO: should always use char-based diff while still supporting cursor behavior that
11962            // matches vim.
11963            let mut diff_options = DiffOptions::default();
11964            if options.override_language_settings {
11965                diff_options.max_word_diff_len = 0;
11966                diff_options.max_word_diff_line_count = 0;
11967            } else {
11968                diff_options.max_word_diff_len = usize::MAX;
11969                diff_options.max_word_diff_line_count = usize::MAX;
11970            }
11971
11972            for (old_range, new_text) in
11973                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11974            {
11975                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11976                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11977                edits.push((edit_start..edit_end, new_text));
11978            }
11979
11980            rewrapped_row_ranges.push(start_row..=end_row);
11981        }
11982
11983        self.buffer
11984            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11985    }
11986
11987    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
11988        let mut text = String::new();
11989        let buffer = self.buffer.read(cx).snapshot(cx);
11990        let mut selections = self.selections.all::<Point>(cx);
11991        let mut clipboard_selections = Vec::with_capacity(selections.len());
11992        {
11993            let max_point = buffer.max_point();
11994            let mut is_first = true;
11995            for selection in &mut selections {
11996                let is_entire_line = selection.is_empty() || self.selections.line_mode;
11997                if is_entire_line {
11998                    selection.start = Point::new(selection.start.row, 0);
11999                    if !selection.is_empty() && selection.end.column == 0 {
12000                        selection.end = cmp::min(max_point, selection.end);
12001                    } else {
12002                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12003                    }
12004                    selection.goal = SelectionGoal::None;
12005                }
12006                if is_first {
12007                    is_first = false;
12008                } else {
12009                    text += "\n";
12010                }
12011                let mut len = 0;
12012                for chunk in buffer.text_for_range(selection.start..selection.end) {
12013                    text.push_str(chunk);
12014                    len += chunk.len();
12015                }
12016                clipboard_selections.push(ClipboardSelection {
12017                    len,
12018                    is_entire_line,
12019                    first_line_indent: buffer
12020                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12021                        .len,
12022                });
12023            }
12024        }
12025
12026        self.transact(window, cx, |this, window, cx| {
12027            this.change_selections(Default::default(), window, cx, |s| {
12028                s.select(selections);
12029            });
12030            this.insert("", window, cx);
12031        });
12032        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12033    }
12034
12035    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12036        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12037        let item = self.cut_common(window, cx);
12038        cx.write_to_clipboard(item);
12039    }
12040
12041    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12042        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12043        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12044            s.move_with(|snapshot, sel| {
12045                if sel.is_empty() {
12046                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
12047                }
12048            });
12049        });
12050        let item = self.cut_common(window, cx);
12051        cx.set_global(KillRing(item))
12052    }
12053
12054    pub fn kill_ring_yank(
12055        &mut self,
12056        _: &KillRingYank,
12057        window: &mut Window,
12058        cx: &mut Context<Self>,
12059    ) {
12060        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12061        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12062            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12063                (kill_ring.text().to_string(), kill_ring.metadata_json())
12064            } else {
12065                return;
12066            }
12067        } else {
12068            return;
12069        };
12070        self.do_paste(&text, metadata, false, window, cx);
12071    }
12072
12073    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12074        self.do_copy(true, cx);
12075    }
12076
12077    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12078        self.do_copy(false, cx);
12079    }
12080
12081    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12082        let selections = self.selections.all::<Point>(cx);
12083        let buffer = self.buffer.read(cx).read(cx);
12084        let mut text = String::new();
12085
12086        let mut clipboard_selections = Vec::with_capacity(selections.len());
12087        {
12088            let max_point = buffer.max_point();
12089            let mut is_first = true;
12090            for selection in &selections {
12091                let mut start = selection.start;
12092                let mut end = selection.end;
12093                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12094                if is_entire_line {
12095                    start = Point::new(start.row, 0);
12096                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12097                }
12098
12099                let mut trimmed_selections = Vec::new();
12100                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12101                    let row = MultiBufferRow(start.row);
12102                    let first_indent = buffer.indent_size_for_line(row);
12103                    if first_indent.len == 0 || start.column > first_indent.len {
12104                        trimmed_selections.push(start..end);
12105                    } else {
12106                        trimmed_selections.push(
12107                            Point::new(row.0, first_indent.len)
12108                                ..Point::new(row.0, buffer.line_len(row)),
12109                        );
12110                        for row in start.row + 1..=end.row {
12111                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12112                            if row == end.row {
12113                                line_len = end.column;
12114                            }
12115                            if line_len == 0 {
12116                                trimmed_selections
12117                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12118                                continue;
12119                            }
12120                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12121                            if row_indent_size.len >= first_indent.len {
12122                                trimmed_selections.push(
12123                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12124                                );
12125                            } else {
12126                                trimmed_selections.clear();
12127                                trimmed_selections.push(start..end);
12128                                break;
12129                            }
12130                        }
12131                    }
12132                } else {
12133                    trimmed_selections.push(start..end);
12134                }
12135
12136                for trimmed_range in trimmed_selections {
12137                    if is_first {
12138                        is_first = false;
12139                    } else {
12140                        text += "\n";
12141                    }
12142                    let mut len = 0;
12143                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12144                        text.push_str(chunk);
12145                        len += chunk.len();
12146                    }
12147                    clipboard_selections.push(ClipboardSelection {
12148                        len,
12149                        is_entire_line,
12150                        first_line_indent: buffer
12151                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12152                            .len,
12153                    });
12154                }
12155            }
12156        }
12157
12158        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12159            text,
12160            clipboard_selections,
12161        ));
12162    }
12163
12164    pub fn do_paste(
12165        &mut self,
12166        text: &String,
12167        clipboard_selections: Option<Vec<ClipboardSelection>>,
12168        handle_entire_lines: bool,
12169        window: &mut Window,
12170        cx: &mut Context<Self>,
12171    ) {
12172        if self.read_only(cx) {
12173            return;
12174        }
12175
12176        let clipboard_text = Cow::Borrowed(text);
12177
12178        self.transact(window, cx, |this, window, cx| {
12179            let had_active_edit_prediction = this.has_active_edit_prediction();
12180
12181            if let Some(mut clipboard_selections) = clipboard_selections {
12182                let old_selections = this.selections.all::<usize>(cx);
12183                let all_selections_were_entire_line =
12184                    clipboard_selections.iter().all(|s| s.is_entire_line);
12185                let first_selection_indent_column =
12186                    clipboard_selections.first().map(|s| s.first_line_indent);
12187                if clipboard_selections.len() != old_selections.len() {
12188                    clipboard_selections.drain(..);
12189                }
12190                let cursor_offset = this.selections.last::<usize>(cx).head();
12191                let mut auto_indent_on_paste = true;
12192
12193                this.buffer.update(cx, |buffer, cx| {
12194                    let snapshot = buffer.read(cx);
12195                    auto_indent_on_paste = snapshot
12196                        .language_settings_at(cursor_offset, cx)
12197                        .auto_indent_on_paste;
12198
12199                    let mut start_offset = 0;
12200                    let mut edits = Vec::new();
12201                    let mut original_indent_columns = Vec::new();
12202                    for (ix, selection) in old_selections.iter().enumerate() {
12203                        let to_insert;
12204                        let entire_line;
12205                        let original_indent_column;
12206                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12207                            let end_offset = start_offset + clipboard_selection.len;
12208                            to_insert = &clipboard_text[start_offset..end_offset];
12209                            entire_line = clipboard_selection.is_entire_line;
12210                            start_offset = end_offset + 1;
12211                            original_indent_column = Some(clipboard_selection.first_line_indent);
12212                        } else {
12213                            to_insert = clipboard_text.as_str();
12214                            entire_line = all_selections_were_entire_line;
12215                            original_indent_column = first_selection_indent_column
12216                        }
12217
12218                        // If the corresponding selection was empty when this slice of the
12219                        // clipboard text was written, then the entire line containing the
12220                        // selection was copied. If this selection is also currently empty,
12221                        // then paste the line before the current line of the buffer.
12222                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12223                            let column = selection.start.to_point(&snapshot).column as usize;
12224                            let line_start = selection.start - column;
12225                            line_start..line_start
12226                        } else {
12227                            selection.range()
12228                        };
12229
12230                        edits.push((range, to_insert));
12231                        original_indent_columns.push(original_indent_column);
12232                    }
12233                    drop(snapshot);
12234
12235                    buffer.edit(
12236                        edits,
12237                        if auto_indent_on_paste {
12238                            Some(AutoindentMode::Block {
12239                                original_indent_columns,
12240                            })
12241                        } else {
12242                            None
12243                        },
12244                        cx,
12245                    );
12246                });
12247
12248                let selections = this.selections.all::<usize>(cx);
12249                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12250            } else {
12251                this.insert(&clipboard_text, window, cx);
12252            }
12253
12254            let trigger_in_words =
12255                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12256
12257            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
12258        });
12259    }
12260
12261    pub fn diff_clipboard_with_selection(
12262        &mut self,
12263        _: &DiffClipboardWithSelection,
12264        window: &mut Window,
12265        cx: &mut Context<Self>,
12266    ) {
12267        let selections = self.selections.all::<usize>(cx);
12268
12269        if selections.is_empty() {
12270            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12271            return;
12272        };
12273
12274        let clipboard_text = match cx.read_from_clipboard() {
12275            Some(item) => match item.entries().first() {
12276                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12277                _ => None,
12278            },
12279            None => None,
12280        };
12281
12282        let Some(clipboard_text) = clipboard_text else {
12283            log::warn!("Clipboard doesn't contain text.");
12284            return;
12285        };
12286
12287        window.dispatch_action(
12288            Box::new(DiffClipboardWithSelectionData {
12289                clipboard_text,
12290                editor: cx.entity(),
12291            }),
12292            cx,
12293        );
12294    }
12295
12296    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12297        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12298        if let Some(item) = cx.read_from_clipboard() {
12299            let entries = item.entries();
12300
12301            match entries.first() {
12302                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12303                // of all the pasted entries.
12304                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12305                    .do_paste(
12306                        clipboard_string.text(),
12307                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12308                        true,
12309                        window,
12310                        cx,
12311                    ),
12312                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12313            }
12314        }
12315    }
12316
12317    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12318        if self.read_only(cx) {
12319            return;
12320        }
12321
12322        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12323
12324        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12325            if let Some((selections, _)) =
12326                self.selection_history.transaction(transaction_id).cloned()
12327            {
12328                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12329                    s.select_anchors(selections.to_vec());
12330                });
12331            } else {
12332                log::error!(
12333                    "No entry in selection_history found for undo. \
12334                     This may correspond to a bug where undo does not update the selection. \
12335                     If this is occurring, please add details to \
12336                     https://github.com/zed-industries/zed/issues/22692"
12337                );
12338            }
12339            self.request_autoscroll(Autoscroll::fit(), cx);
12340            self.unmark_text(window, cx);
12341            self.refresh_edit_prediction(true, false, window, cx);
12342            cx.emit(EditorEvent::Edited { transaction_id });
12343            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12344        }
12345    }
12346
12347    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12348        if self.read_only(cx) {
12349            return;
12350        }
12351
12352        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12353
12354        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12355            if let Some((_, Some(selections))) =
12356                self.selection_history.transaction(transaction_id).cloned()
12357            {
12358                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12359                    s.select_anchors(selections.to_vec());
12360                });
12361            } else {
12362                log::error!(
12363                    "No entry in selection_history found for redo. \
12364                     This may correspond to a bug where undo does not update the selection. \
12365                     If this is occurring, please add details to \
12366                     https://github.com/zed-industries/zed/issues/22692"
12367                );
12368            }
12369            self.request_autoscroll(Autoscroll::fit(), cx);
12370            self.unmark_text(window, cx);
12371            self.refresh_edit_prediction(true, false, window, cx);
12372            cx.emit(EditorEvent::Edited { transaction_id });
12373        }
12374    }
12375
12376    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12377        self.buffer
12378            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12379    }
12380
12381    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12382        self.buffer
12383            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12384    }
12385
12386    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12387        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12388        self.change_selections(Default::default(), window, cx, |s| {
12389            s.move_with(|map, selection| {
12390                let cursor = if selection.is_empty() {
12391                    movement::left(map, selection.start)
12392                } else {
12393                    selection.start
12394                };
12395                selection.collapse_to(cursor, SelectionGoal::None);
12396            });
12397        })
12398    }
12399
12400    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12401        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12402        self.change_selections(Default::default(), window, cx, |s| {
12403            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12404        })
12405    }
12406
12407    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12408        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12409        self.change_selections(Default::default(), window, cx, |s| {
12410            s.move_with(|map, selection| {
12411                let cursor = if selection.is_empty() {
12412                    movement::right(map, selection.end)
12413                } else {
12414                    selection.end
12415                };
12416                selection.collapse_to(cursor, SelectionGoal::None)
12417            });
12418        })
12419    }
12420
12421    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12422        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12423        self.change_selections(Default::default(), window, cx, |s| {
12424            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12425        })
12426    }
12427
12428    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12429        if self.take_rename(true, window, cx).is_some() {
12430            return;
12431        }
12432
12433        if self.mode.is_single_line() {
12434            cx.propagate();
12435            return;
12436        }
12437
12438        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12439
12440        let text_layout_details = &self.text_layout_details(window);
12441        let selection_count = self.selections.count();
12442        let first_selection = self.selections.first_anchor();
12443
12444        self.change_selections(Default::default(), window, cx, |s| {
12445            s.move_with(|map, selection| {
12446                if !selection.is_empty() {
12447                    selection.goal = SelectionGoal::None;
12448                }
12449                let (cursor, goal) = movement::up(
12450                    map,
12451                    selection.start,
12452                    selection.goal,
12453                    false,
12454                    text_layout_details,
12455                );
12456                selection.collapse_to(cursor, goal);
12457            });
12458        });
12459
12460        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12461        {
12462            cx.propagate();
12463        }
12464    }
12465
12466    pub fn move_up_by_lines(
12467        &mut self,
12468        action: &MoveUpByLines,
12469        window: &mut Window,
12470        cx: &mut Context<Self>,
12471    ) {
12472        if self.take_rename(true, window, cx).is_some() {
12473            return;
12474        }
12475
12476        if self.mode.is_single_line() {
12477            cx.propagate();
12478            return;
12479        }
12480
12481        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12482
12483        let text_layout_details = &self.text_layout_details(window);
12484
12485        self.change_selections(Default::default(), window, cx, |s| {
12486            s.move_with(|map, selection| {
12487                if !selection.is_empty() {
12488                    selection.goal = SelectionGoal::None;
12489                }
12490                let (cursor, goal) = movement::up_by_rows(
12491                    map,
12492                    selection.start,
12493                    action.lines,
12494                    selection.goal,
12495                    false,
12496                    text_layout_details,
12497                );
12498                selection.collapse_to(cursor, goal);
12499            });
12500        })
12501    }
12502
12503    pub fn move_down_by_lines(
12504        &mut self,
12505        action: &MoveDownByLines,
12506        window: &mut Window,
12507        cx: &mut Context<Self>,
12508    ) {
12509        if self.take_rename(true, window, cx).is_some() {
12510            return;
12511        }
12512
12513        if self.mode.is_single_line() {
12514            cx.propagate();
12515            return;
12516        }
12517
12518        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12519
12520        let text_layout_details = &self.text_layout_details(window);
12521
12522        self.change_selections(Default::default(), window, cx, |s| {
12523            s.move_with(|map, selection| {
12524                if !selection.is_empty() {
12525                    selection.goal = SelectionGoal::None;
12526                }
12527                let (cursor, goal) = movement::down_by_rows(
12528                    map,
12529                    selection.start,
12530                    action.lines,
12531                    selection.goal,
12532                    false,
12533                    text_layout_details,
12534                );
12535                selection.collapse_to(cursor, goal);
12536            });
12537        })
12538    }
12539
12540    pub fn select_down_by_lines(
12541        &mut self,
12542        action: &SelectDownByLines,
12543        window: &mut Window,
12544        cx: &mut Context<Self>,
12545    ) {
12546        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12547        let text_layout_details = &self.text_layout_details(window);
12548        self.change_selections(Default::default(), window, cx, |s| {
12549            s.move_heads_with(|map, head, goal| {
12550                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12551            })
12552        })
12553    }
12554
12555    pub fn select_up_by_lines(
12556        &mut self,
12557        action: &SelectUpByLines,
12558        window: &mut Window,
12559        cx: &mut Context<Self>,
12560    ) {
12561        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12562        let text_layout_details = &self.text_layout_details(window);
12563        self.change_selections(Default::default(), window, cx, |s| {
12564            s.move_heads_with(|map, head, goal| {
12565                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12566            })
12567        })
12568    }
12569
12570    pub fn select_page_up(
12571        &mut self,
12572        _: &SelectPageUp,
12573        window: &mut Window,
12574        cx: &mut Context<Self>,
12575    ) {
12576        let Some(row_count) = self.visible_row_count() else {
12577            return;
12578        };
12579
12580        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12581
12582        let text_layout_details = &self.text_layout_details(window);
12583
12584        self.change_selections(Default::default(), window, cx, |s| {
12585            s.move_heads_with(|map, head, goal| {
12586                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12587            })
12588        })
12589    }
12590
12591    pub fn move_page_up(
12592        &mut self,
12593        action: &MovePageUp,
12594        window: &mut Window,
12595        cx: &mut Context<Self>,
12596    ) {
12597        if self.take_rename(true, window, cx).is_some() {
12598            return;
12599        }
12600
12601        if self
12602            .context_menu
12603            .borrow_mut()
12604            .as_mut()
12605            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12606            .unwrap_or(false)
12607        {
12608            return;
12609        }
12610
12611        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12612            cx.propagate();
12613            return;
12614        }
12615
12616        let Some(row_count) = self.visible_row_count() else {
12617            return;
12618        };
12619
12620        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12621
12622        let effects = if action.center_cursor {
12623            SelectionEffects::scroll(Autoscroll::center())
12624        } else {
12625            SelectionEffects::default()
12626        };
12627
12628        let text_layout_details = &self.text_layout_details(window);
12629
12630        self.change_selections(effects, window, cx, |s| {
12631            s.move_with(|map, selection| {
12632                if !selection.is_empty() {
12633                    selection.goal = SelectionGoal::None;
12634                }
12635                let (cursor, goal) = movement::up_by_rows(
12636                    map,
12637                    selection.end,
12638                    row_count,
12639                    selection.goal,
12640                    false,
12641                    text_layout_details,
12642                );
12643                selection.collapse_to(cursor, goal);
12644            });
12645        });
12646    }
12647
12648    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12649        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12650        let text_layout_details = &self.text_layout_details(window);
12651        self.change_selections(Default::default(), window, cx, |s| {
12652            s.move_heads_with(|map, head, goal| {
12653                movement::up(map, head, goal, false, text_layout_details)
12654            })
12655        })
12656    }
12657
12658    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12659        self.take_rename(true, window, cx);
12660
12661        if self.mode.is_single_line() {
12662            cx.propagate();
12663            return;
12664        }
12665
12666        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12667
12668        let text_layout_details = &self.text_layout_details(window);
12669        let selection_count = self.selections.count();
12670        let first_selection = self.selections.first_anchor();
12671
12672        self.change_selections(Default::default(), window, cx, |s| {
12673            s.move_with(|map, selection| {
12674                if !selection.is_empty() {
12675                    selection.goal = SelectionGoal::None;
12676                }
12677                let (cursor, goal) = movement::down(
12678                    map,
12679                    selection.end,
12680                    selection.goal,
12681                    false,
12682                    text_layout_details,
12683                );
12684                selection.collapse_to(cursor, goal);
12685            });
12686        });
12687
12688        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12689        {
12690            cx.propagate();
12691        }
12692    }
12693
12694    pub fn select_page_down(
12695        &mut self,
12696        _: &SelectPageDown,
12697        window: &mut Window,
12698        cx: &mut Context<Self>,
12699    ) {
12700        let Some(row_count) = self.visible_row_count() else {
12701            return;
12702        };
12703
12704        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12705
12706        let text_layout_details = &self.text_layout_details(window);
12707
12708        self.change_selections(Default::default(), window, cx, |s| {
12709            s.move_heads_with(|map, head, goal| {
12710                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12711            })
12712        })
12713    }
12714
12715    pub fn move_page_down(
12716        &mut self,
12717        action: &MovePageDown,
12718        window: &mut Window,
12719        cx: &mut Context<Self>,
12720    ) {
12721        if self.take_rename(true, window, cx).is_some() {
12722            return;
12723        }
12724
12725        if self
12726            .context_menu
12727            .borrow_mut()
12728            .as_mut()
12729            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12730            .unwrap_or(false)
12731        {
12732            return;
12733        }
12734
12735        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12736            cx.propagate();
12737            return;
12738        }
12739
12740        let Some(row_count) = self.visible_row_count() else {
12741            return;
12742        };
12743
12744        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12745
12746        let effects = if action.center_cursor {
12747            SelectionEffects::scroll(Autoscroll::center())
12748        } else {
12749            SelectionEffects::default()
12750        };
12751
12752        let text_layout_details = &self.text_layout_details(window);
12753        self.change_selections(effects, window, cx, |s| {
12754            s.move_with(|map, selection| {
12755                if !selection.is_empty() {
12756                    selection.goal = SelectionGoal::None;
12757                }
12758                let (cursor, goal) = movement::down_by_rows(
12759                    map,
12760                    selection.end,
12761                    row_count,
12762                    selection.goal,
12763                    false,
12764                    text_layout_details,
12765                );
12766                selection.collapse_to(cursor, goal);
12767            });
12768        });
12769    }
12770
12771    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12772        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12773        let text_layout_details = &self.text_layout_details(window);
12774        self.change_selections(Default::default(), window, cx, |s| {
12775            s.move_heads_with(|map, head, goal| {
12776                movement::down(map, head, goal, false, text_layout_details)
12777            })
12778        });
12779    }
12780
12781    pub fn context_menu_first(
12782        &mut self,
12783        _: &ContextMenuFirst,
12784        window: &mut Window,
12785        cx: &mut Context<Self>,
12786    ) {
12787        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12788            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
12789        }
12790    }
12791
12792    pub fn context_menu_prev(
12793        &mut self,
12794        _: &ContextMenuPrevious,
12795        window: &mut Window,
12796        cx: &mut Context<Self>,
12797    ) {
12798        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12799            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
12800        }
12801    }
12802
12803    pub fn context_menu_next(
12804        &mut self,
12805        _: &ContextMenuNext,
12806        window: &mut Window,
12807        cx: &mut Context<Self>,
12808    ) {
12809        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12810            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12811        }
12812    }
12813
12814    pub fn context_menu_last(
12815        &mut self,
12816        _: &ContextMenuLast,
12817        window: &mut Window,
12818        cx: &mut Context<Self>,
12819    ) {
12820        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12821            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12822        }
12823    }
12824
12825    pub fn signature_help_prev(
12826        &mut self,
12827        _: &SignatureHelpPrevious,
12828        _: &mut Window,
12829        cx: &mut Context<Self>,
12830    ) {
12831        if let Some(popover) = self.signature_help_state.popover_mut() {
12832            if popover.current_signature == 0 {
12833                popover.current_signature = popover.signatures.len() - 1;
12834            } else {
12835                popover.current_signature -= 1;
12836            }
12837            cx.notify();
12838        }
12839    }
12840
12841    pub fn signature_help_next(
12842        &mut self,
12843        _: &SignatureHelpNext,
12844        _: &mut Window,
12845        cx: &mut Context<Self>,
12846    ) {
12847        if let Some(popover) = self.signature_help_state.popover_mut() {
12848            if popover.current_signature + 1 == popover.signatures.len() {
12849                popover.current_signature = 0;
12850            } else {
12851                popover.current_signature += 1;
12852            }
12853            cx.notify();
12854        }
12855    }
12856
12857    pub fn move_to_previous_word_start(
12858        &mut self,
12859        _: &MoveToPreviousWordStart,
12860        window: &mut Window,
12861        cx: &mut Context<Self>,
12862    ) {
12863        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12864        self.change_selections(Default::default(), window, cx, |s| {
12865            s.move_cursors_with(|map, head, _| {
12866                (
12867                    movement::previous_word_start(map, head),
12868                    SelectionGoal::None,
12869                )
12870            });
12871        })
12872    }
12873
12874    pub fn move_to_previous_subword_start(
12875        &mut self,
12876        _: &MoveToPreviousSubwordStart,
12877        window: &mut Window,
12878        cx: &mut Context<Self>,
12879    ) {
12880        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12881        self.change_selections(Default::default(), window, cx, |s| {
12882            s.move_cursors_with(|map, head, _| {
12883                (
12884                    movement::previous_subword_start(map, head),
12885                    SelectionGoal::None,
12886                )
12887            });
12888        })
12889    }
12890
12891    pub fn select_to_previous_word_start(
12892        &mut self,
12893        _: &SelectToPreviousWordStart,
12894        window: &mut Window,
12895        cx: &mut Context<Self>,
12896    ) {
12897        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12898        self.change_selections(Default::default(), window, cx, |s| {
12899            s.move_heads_with(|map, head, _| {
12900                (
12901                    movement::previous_word_start(map, head),
12902                    SelectionGoal::None,
12903                )
12904            });
12905        })
12906    }
12907
12908    pub fn select_to_previous_subword_start(
12909        &mut self,
12910        _: &SelectToPreviousSubwordStart,
12911        window: &mut Window,
12912        cx: &mut Context<Self>,
12913    ) {
12914        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12915        self.change_selections(Default::default(), window, cx, |s| {
12916            s.move_heads_with(|map, head, _| {
12917                (
12918                    movement::previous_subword_start(map, head),
12919                    SelectionGoal::None,
12920                )
12921            });
12922        })
12923    }
12924
12925    pub fn delete_to_previous_word_start(
12926        &mut self,
12927        action: &DeleteToPreviousWordStart,
12928        window: &mut Window,
12929        cx: &mut Context<Self>,
12930    ) {
12931        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12932        self.transact(window, cx, |this, window, cx| {
12933            this.select_autoclose_pair(window, cx);
12934            this.change_selections(Default::default(), window, cx, |s| {
12935                s.move_with(|map, selection| {
12936                    if selection.is_empty() {
12937                        let cursor = if action.ignore_newlines {
12938                            movement::previous_word_start(map, selection.head())
12939                        } else {
12940                            movement::previous_word_start_or_newline(map, selection.head())
12941                        };
12942                        selection.set_head(cursor, SelectionGoal::None);
12943                    }
12944                });
12945            });
12946            this.insert("", window, cx);
12947        });
12948    }
12949
12950    pub fn delete_to_previous_subword_start(
12951        &mut self,
12952        _: &DeleteToPreviousSubwordStart,
12953        window: &mut Window,
12954        cx: &mut Context<Self>,
12955    ) {
12956        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12957        self.transact(window, cx, |this, window, cx| {
12958            this.select_autoclose_pair(window, cx);
12959            this.change_selections(Default::default(), window, cx, |s| {
12960                s.move_with(|map, selection| {
12961                    if selection.is_empty() {
12962                        let cursor = movement::previous_subword_start(map, selection.head());
12963                        selection.set_head(cursor, SelectionGoal::None);
12964                    }
12965                });
12966            });
12967            this.insert("", window, cx);
12968        });
12969    }
12970
12971    pub fn move_to_next_word_end(
12972        &mut self,
12973        _: &MoveToNextWordEnd,
12974        window: &mut Window,
12975        cx: &mut Context<Self>,
12976    ) {
12977        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12978        self.change_selections(Default::default(), window, cx, |s| {
12979            s.move_cursors_with(|map, head, _| {
12980                (movement::next_word_end(map, head), SelectionGoal::None)
12981            });
12982        })
12983    }
12984
12985    pub fn move_to_next_subword_end(
12986        &mut self,
12987        _: &MoveToNextSubwordEnd,
12988        window: &mut Window,
12989        cx: &mut Context<Self>,
12990    ) {
12991        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12992        self.change_selections(Default::default(), window, cx, |s| {
12993            s.move_cursors_with(|map, head, _| {
12994                (movement::next_subword_end(map, head), SelectionGoal::None)
12995            });
12996        })
12997    }
12998
12999    pub fn select_to_next_word_end(
13000        &mut self,
13001        _: &SelectToNextWordEnd,
13002        window: &mut Window,
13003        cx: &mut Context<Self>,
13004    ) {
13005        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13006        self.change_selections(Default::default(), window, cx, |s| {
13007            s.move_heads_with(|map, head, _| {
13008                (movement::next_word_end(map, head), SelectionGoal::None)
13009            });
13010        })
13011    }
13012
13013    pub fn select_to_next_subword_end(
13014        &mut self,
13015        _: &SelectToNextSubwordEnd,
13016        window: &mut Window,
13017        cx: &mut Context<Self>,
13018    ) {
13019        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13020        self.change_selections(Default::default(), window, cx, |s| {
13021            s.move_heads_with(|map, head, _| {
13022                (movement::next_subword_end(map, head), SelectionGoal::None)
13023            });
13024        })
13025    }
13026
13027    pub fn delete_to_next_word_end(
13028        &mut self,
13029        action: &DeleteToNextWordEnd,
13030        window: &mut Window,
13031        cx: &mut Context<Self>,
13032    ) {
13033        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13034        self.transact(window, cx, |this, window, cx| {
13035            this.change_selections(Default::default(), window, cx, |s| {
13036                s.move_with(|map, selection| {
13037                    if selection.is_empty() {
13038                        let cursor = if action.ignore_newlines {
13039                            movement::next_word_end(map, selection.head())
13040                        } else {
13041                            movement::next_word_end_or_newline(map, selection.head())
13042                        };
13043                        selection.set_head(cursor, SelectionGoal::None);
13044                    }
13045                });
13046            });
13047            this.insert("", window, cx);
13048        });
13049    }
13050
13051    pub fn delete_to_next_subword_end(
13052        &mut self,
13053        _: &DeleteToNextSubwordEnd,
13054        window: &mut Window,
13055        cx: &mut Context<Self>,
13056    ) {
13057        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13058        self.transact(window, cx, |this, window, cx| {
13059            this.change_selections(Default::default(), window, cx, |s| {
13060                s.move_with(|map, selection| {
13061                    if selection.is_empty() {
13062                        let cursor = movement::next_subword_end(map, selection.head());
13063                        selection.set_head(cursor, SelectionGoal::None);
13064                    }
13065                });
13066            });
13067            this.insert("", window, cx);
13068        });
13069    }
13070
13071    pub fn move_to_beginning_of_line(
13072        &mut self,
13073        action: &MoveToBeginningOfLine,
13074        window: &mut Window,
13075        cx: &mut Context<Self>,
13076    ) {
13077        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13078        self.change_selections(Default::default(), window, cx, |s| {
13079            s.move_cursors_with(|map, head, _| {
13080                (
13081                    movement::indented_line_beginning(
13082                        map,
13083                        head,
13084                        action.stop_at_soft_wraps,
13085                        action.stop_at_indent,
13086                    ),
13087                    SelectionGoal::None,
13088                )
13089            });
13090        })
13091    }
13092
13093    pub fn select_to_beginning_of_line(
13094        &mut self,
13095        action: &SelectToBeginningOfLine,
13096        window: &mut Window,
13097        cx: &mut Context<Self>,
13098    ) {
13099        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13100        self.change_selections(Default::default(), window, cx, |s| {
13101            s.move_heads_with(|map, head, _| {
13102                (
13103                    movement::indented_line_beginning(
13104                        map,
13105                        head,
13106                        action.stop_at_soft_wraps,
13107                        action.stop_at_indent,
13108                    ),
13109                    SelectionGoal::None,
13110                )
13111            });
13112        });
13113    }
13114
13115    pub fn delete_to_beginning_of_line(
13116        &mut self,
13117        action: &DeleteToBeginningOfLine,
13118        window: &mut Window,
13119        cx: &mut Context<Self>,
13120    ) {
13121        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13122        self.transact(window, cx, |this, window, cx| {
13123            this.change_selections(Default::default(), window, cx, |s| {
13124                s.move_with(|_, selection| {
13125                    selection.reversed = true;
13126                });
13127            });
13128
13129            this.select_to_beginning_of_line(
13130                &SelectToBeginningOfLine {
13131                    stop_at_soft_wraps: false,
13132                    stop_at_indent: action.stop_at_indent,
13133                },
13134                window,
13135                cx,
13136            );
13137            this.backspace(&Backspace, window, cx);
13138        });
13139    }
13140
13141    pub fn move_to_end_of_line(
13142        &mut self,
13143        action: &MoveToEndOfLine,
13144        window: &mut Window,
13145        cx: &mut Context<Self>,
13146    ) {
13147        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13148        self.change_selections(Default::default(), window, cx, |s| {
13149            s.move_cursors_with(|map, head, _| {
13150                (
13151                    movement::line_end(map, head, action.stop_at_soft_wraps),
13152                    SelectionGoal::None,
13153                )
13154            });
13155        })
13156    }
13157
13158    pub fn select_to_end_of_line(
13159        &mut self,
13160        action: &SelectToEndOfLine,
13161        window: &mut Window,
13162        cx: &mut Context<Self>,
13163    ) {
13164        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13165        self.change_selections(Default::default(), window, cx, |s| {
13166            s.move_heads_with(|map, head, _| {
13167                (
13168                    movement::line_end(map, head, action.stop_at_soft_wraps),
13169                    SelectionGoal::None,
13170                )
13171            });
13172        })
13173    }
13174
13175    pub fn delete_to_end_of_line(
13176        &mut self,
13177        _: &DeleteToEndOfLine,
13178        window: &mut Window,
13179        cx: &mut Context<Self>,
13180    ) {
13181        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13182        self.transact(window, cx, |this, window, cx| {
13183            this.select_to_end_of_line(
13184                &SelectToEndOfLine {
13185                    stop_at_soft_wraps: false,
13186                },
13187                window,
13188                cx,
13189            );
13190            this.delete(&Delete, window, cx);
13191        });
13192    }
13193
13194    pub fn cut_to_end_of_line(
13195        &mut self,
13196        _: &CutToEndOfLine,
13197        window: &mut Window,
13198        cx: &mut Context<Self>,
13199    ) {
13200        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13201        self.transact(window, cx, |this, window, cx| {
13202            this.select_to_end_of_line(
13203                &SelectToEndOfLine {
13204                    stop_at_soft_wraps: false,
13205                },
13206                window,
13207                cx,
13208            );
13209            this.cut(&Cut, window, cx);
13210        });
13211    }
13212
13213    pub fn move_to_start_of_paragraph(
13214        &mut self,
13215        _: &MoveToStartOfParagraph,
13216        window: &mut Window,
13217        cx: &mut Context<Self>,
13218    ) {
13219        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13220            cx.propagate();
13221            return;
13222        }
13223        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13224        self.change_selections(Default::default(), window, cx, |s| {
13225            s.move_with(|map, selection| {
13226                selection.collapse_to(
13227                    movement::start_of_paragraph(map, selection.head(), 1),
13228                    SelectionGoal::None,
13229                )
13230            });
13231        })
13232    }
13233
13234    pub fn move_to_end_of_paragraph(
13235        &mut self,
13236        _: &MoveToEndOfParagraph,
13237        window: &mut Window,
13238        cx: &mut Context<Self>,
13239    ) {
13240        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13241            cx.propagate();
13242            return;
13243        }
13244        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13245        self.change_selections(Default::default(), window, cx, |s| {
13246            s.move_with(|map, selection| {
13247                selection.collapse_to(
13248                    movement::end_of_paragraph(map, selection.head(), 1),
13249                    SelectionGoal::None,
13250                )
13251            });
13252        })
13253    }
13254
13255    pub fn select_to_start_of_paragraph(
13256        &mut self,
13257        _: &SelectToStartOfParagraph,
13258        window: &mut Window,
13259        cx: &mut Context<Self>,
13260    ) {
13261        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13262            cx.propagate();
13263            return;
13264        }
13265        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13266        self.change_selections(Default::default(), window, cx, |s| {
13267            s.move_heads_with(|map, head, _| {
13268                (
13269                    movement::start_of_paragraph(map, head, 1),
13270                    SelectionGoal::None,
13271                )
13272            });
13273        })
13274    }
13275
13276    pub fn select_to_end_of_paragraph(
13277        &mut self,
13278        _: &SelectToEndOfParagraph,
13279        window: &mut Window,
13280        cx: &mut Context<Self>,
13281    ) {
13282        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13283            cx.propagate();
13284            return;
13285        }
13286        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13287        self.change_selections(Default::default(), window, cx, |s| {
13288            s.move_heads_with(|map, head, _| {
13289                (
13290                    movement::end_of_paragraph(map, head, 1),
13291                    SelectionGoal::None,
13292                )
13293            });
13294        })
13295    }
13296
13297    pub fn move_to_start_of_excerpt(
13298        &mut self,
13299        _: &MoveToStartOfExcerpt,
13300        window: &mut Window,
13301        cx: &mut Context<Self>,
13302    ) {
13303        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13304            cx.propagate();
13305            return;
13306        }
13307        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13308        self.change_selections(Default::default(), window, cx, |s| {
13309            s.move_with(|map, selection| {
13310                selection.collapse_to(
13311                    movement::start_of_excerpt(
13312                        map,
13313                        selection.head(),
13314                        workspace::searchable::Direction::Prev,
13315                    ),
13316                    SelectionGoal::None,
13317                )
13318            });
13319        })
13320    }
13321
13322    pub fn move_to_start_of_next_excerpt(
13323        &mut self,
13324        _: &MoveToStartOfNextExcerpt,
13325        window: &mut Window,
13326        cx: &mut Context<Self>,
13327    ) {
13328        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13329            cx.propagate();
13330            return;
13331        }
13332
13333        self.change_selections(Default::default(), window, cx, |s| {
13334            s.move_with(|map, selection| {
13335                selection.collapse_to(
13336                    movement::start_of_excerpt(
13337                        map,
13338                        selection.head(),
13339                        workspace::searchable::Direction::Next,
13340                    ),
13341                    SelectionGoal::None,
13342                )
13343            });
13344        })
13345    }
13346
13347    pub fn move_to_end_of_excerpt(
13348        &mut self,
13349        _: &MoveToEndOfExcerpt,
13350        window: &mut Window,
13351        cx: &mut Context<Self>,
13352    ) {
13353        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13354            cx.propagate();
13355            return;
13356        }
13357        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13358        self.change_selections(Default::default(), window, cx, |s| {
13359            s.move_with(|map, selection| {
13360                selection.collapse_to(
13361                    movement::end_of_excerpt(
13362                        map,
13363                        selection.head(),
13364                        workspace::searchable::Direction::Next,
13365                    ),
13366                    SelectionGoal::None,
13367                )
13368            });
13369        })
13370    }
13371
13372    pub fn move_to_end_of_previous_excerpt(
13373        &mut self,
13374        _: &MoveToEndOfPreviousExcerpt,
13375        window: &mut Window,
13376        cx: &mut Context<Self>,
13377    ) {
13378        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13379            cx.propagate();
13380            return;
13381        }
13382        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13383        self.change_selections(Default::default(), window, cx, |s| {
13384            s.move_with(|map, selection| {
13385                selection.collapse_to(
13386                    movement::end_of_excerpt(
13387                        map,
13388                        selection.head(),
13389                        workspace::searchable::Direction::Prev,
13390                    ),
13391                    SelectionGoal::None,
13392                )
13393            });
13394        })
13395    }
13396
13397    pub fn select_to_start_of_excerpt(
13398        &mut self,
13399        _: &SelectToStartOfExcerpt,
13400        window: &mut Window,
13401        cx: &mut Context<Self>,
13402    ) {
13403        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13404            cx.propagate();
13405            return;
13406        }
13407        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13408        self.change_selections(Default::default(), window, cx, |s| {
13409            s.move_heads_with(|map, head, _| {
13410                (
13411                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13412                    SelectionGoal::None,
13413                )
13414            });
13415        })
13416    }
13417
13418    pub fn select_to_start_of_next_excerpt(
13419        &mut self,
13420        _: &SelectToStartOfNextExcerpt,
13421        window: &mut Window,
13422        cx: &mut Context<Self>,
13423    ) {
13424        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13425            cx.propagate();
13426            return;
13427        }
13428        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13429        self.change_selections(Default::default(), window, cx, |s| {
13430            s.move_heads_with(|map, head, _| {
13431                (
13432                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13433                    SelectionGoal::None,
13434                )
13435            });
13436        })
13437    }
13438
13439    pub fn select_to_end_of_excerpt(
13440        &mut self,
13441        _: &SelectToEndOfExcerpt,
13442        window: &mut Window,
13443        cx: &mut Context<Self>,
13444    ) {
13445        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13446            cx.propagate();
13447            return;
13448        }
13449        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13450        self.change_selections(Default::default(), window, cx, |s| {
13451            s.move_heads_with(|map, head, _| {
13452                (
13453                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13454                    SelectionGoal::None,
13455                )
13456            });
13457        })
13458    }
13459
13460    pub fn select_to_end_of_previous_excerpt(
13461        &mut self,
13462        _: &SelectToEndOfPreviousExcerpt,
13463        window: &mut Window,
13464        cx: &mut Context<Self>,
13465    ) {
13466        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13467            cx.propagate();
13468            return;
13469        }
13470        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13471        self.change_selections(Default::default(), window, cx, |s| {
13472            s.move_heads_with(|map, head, _| {
13473                (
13474                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13475                    SelectionGoal::None,
13476                )
13477            });
13478        })
13479    }
13480
13481    pub fn move_to_beginning(
13482        &mut self,
13483        _: &MoveToBeginning,
13484        window: &mut Window,
13485        cx: &mut Context<Self>,
13486    ) {
13487        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13488            cx.propagate();
13489            return;
13490        }
13491        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13492        self.change_selections(Default::default(), window, cx, |s| {
13493            s.select_ranges(vec![0..0]);
13494        });
13495    }
13496
13497    pub fn select_to_beginning(
13498        &mut self,
13499        _: &SelectToBeginning,
13500        window: &mut Window,
13501        cx: &mut Context<Self>,
13502    ) {
13503        let mut selection = self.selections.last::<Point>(cx);
13504        selection.set_head(Point::zero(), SelectionGoal::None);
13505        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13506        self.change_selections(Default::default(), window, cx, |s| {
13507            s.select(vec![selection]);
13508        });
13509    }
13510
13511    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13512        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13513            cx.propagate();
13514            return;
13515        }
13516        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13517        let cursor = self.buffer.read(cx).read(cx).len();
13518        self.change_selections(Default::default(), window, cx, |s| {
13519            s.select_ranges(vec![cursor..cursor])
13520        });
13521    }
13522
13523    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13524        self.nav_history = nav_history;
13525    }
13526
13527    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13528        self.nav_history.as_ref()
13529    }
13530
13531    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13532        self.push_to_nav_history(
13533            self.selections.newest_anchor().head(),
13534            None,
13535            false,
13536            true,
13537            cx,
13538        );
13539    }
13540
13541    fn push_to_nav_history(
13542        &mut self,
13543        cursor_anchor: Anchor,
13544        new_position: Option<Point>,
13545        is_deactivate: bool,
13546        always: bool,
13547        cx: &mut Context<Self>,
13548    ) {
13549        if let Some(nav_history) = self.nav_history.as_mut() {
13550            let buffer = self.buffer.read(cx).read(cx);
13551            let cursor_position = cursor_anchor.to_point(&buffer);
13552            let scroll_state = self.scroll_manager.anchor();
13553            let scroll_top_row = scroll_state.top_row(&buffer);
13554            drop(buffer);
13555
13556            if let Some(new_position) = new_position {
13557                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13558                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13559                    return;
13560                }
13561            }
13562
13563            nav_history.push(
13564                Some(NavigationData {
13565                    cursor_anchor,
13566                    cursor_position,
13567                    scroll_anchor: scroll_state,
13568                    scroll_top_row,
13569                }),
13570                cx,
13571            );
13572            cx.emit(EditorEvent::PushedToNavHistory {
13573                anchor: cursor_anchor,
13574                is_deactivate,
13575            })
13576        }
13577    }
13578
13579    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13580        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13581        let buffer = self.buffer.read(cx).snapshot(cx);
13582        let mut selection = self.selections.first::<usize>(cx);
13583        selection.set_head(buffer.len(), SelectionGoal::None);
13584        self.change_selections(Default::default(), window, cx, |s| {
13585            s.select(vec![selection]);
13586        });
13587    }
13588
13589    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13590        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13591        let end = self.buffer.read(cx).read(cx).len();
13592        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13593            s.select_ranges(vec![0..end]);
13594        });
13595    }
13596
13597    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13598        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13599        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13600        let mut selections = self.selections.all::<Point>(cx);
13601        let max_point = display_map.buffer_snapshot.max_point();
13602        for selection in &mut selections {
13603            let rows = selection.spanned_rows(true, &display_map);
13604            selection.start = Point::new(rows.start.0, 0);
13605            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13606            selection.reversed = false;
13607        }
13608        self.change_selections(Default::default(), window, cx, |s| {
13609            s.select(selections);
13610        });
13611    }
13612
13613    pub fn split_selection_into_lines(
13614        &mut self,
13615        action: &SplitSelectionIntoLines,
13616        window: &mut Window,
13617        cx: &mut Context<Self>,
13618    ) {
13619        let selections = self
13620            .selections
13621            .all::<Point>(cx)
13622            .into_iter()
13623            .map(|selection| selection.start..selection.end)
13624            .collect::<Vec<_>>();
13625        self.unfold_ranges(&selections, true, true, cx);
13626
13627        let mut new_selection_ranges = Vec::new();
13628        {
13629            let buffer = self.buffer.read(cx).read(cx);
13630            for selection in selections {
13631                for row in selection.start.row..selection.end.row {
13632                    let line_start = Point::new(row, 0);
13633                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13634
13635                    if action.keep_selections {
13636                        // Keep the selection range for each line
13637                        let selection_start = if row == selection.start.row {
13638                            selection.start
13639                        } else {
13640                            line_start
13641                        };
13642                        new_selection_ranges.push(selection_start..line_end);
13643                    } else {
13644                        // Collapse to cursor at end of line
13645                        new_selection_ranges.push(line_end..line_end);
13646                    }
13647                }
13648
13649                let is_multiline_selection = selection.start.row != selection.end.row;
13650                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13651                // so this action feels more ergonomic when paired with other selection operations
13652                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13653                if !should_skip_last {
13654                    if action.keep_selections {
13655                        if is_multiline_selection {
13656                            let line_start = Point::new(selection.end.row, 0);
13657                            new_selection_ranges.push(line_start..selection.end);
13658                        } else {
13659                            new_selection_ranges.push(selection.start..selection.end);
13660                        }
13661                    } else {
13662                        new_selection_ranges.push(selection.end..selection.end);
13663                    }
13664                }
13665            }
13666        }
13667        self.change_selections(Default::default(), window, cx, |s| {
13668            s.select_ranges(new_selection_ranges);
13669        });
13670    }
13671
13672    pub fn add_selection_above(
13673        &mut self,
13674        _: &AddSelectionAbove,
13675        window: &mut Window,
13676        cx: &mut Context<Self>,
13677    ) {
13678        self.add_selection(true, window, cx);
13679    }
13680
13681    pub fn add_selection_below(
13682        &mut self,
13683        _: &AddSelectionBelow,
13684        window: &mut Window,
13685        cx: &mut Context<Self>,
13686    ) {
13687        self.add_selection(false, window, cx);
13688    }
13689
13690    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13691        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13692
13693        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13694        let all_selections = self.selections.all::<Point>(cx);
13695        let text_layout_details = self.text_layout_details(window);
13696
13697        let (mut columnar_selections, new_selections_to_columnarize) = {
13698            if let Some(state) = self.add_selections_state.as_ref() {
13699                let columnar_selection_ids: HashSet<_> = state
13700                    .groups
13701                    .iter()
13702                    .flat_map(|group| group.stack.iter())
13703                    .copied()
13704                    .collect();
13705
13706                all_selections
13707                    .into_iter()
13708                    .partition(|s| columnar_selection_ids.contains(&s.id))
13709            } else {
13710                (Vec::new(), all_selections)
13711            }
13712        };
13713
13714        let mut state = self
13715            .add_selections_state
13716            .take()
13717            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13718
13719        for selection in new_selections_to_columnarize {
13720            let range = selection.display_range(&display_map).sorted();
13721            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13722            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13723            let positions = start_x.min(end_x)..start_x.max(end_x);
13724            let mut stack = Vec::new();
13725            for row in range.start.row().0..=range.end.row().0 {
13726                if let Some(selection) = self.selections.build_columnar_selection(
13727                    &display_map,
13728                    DisplayRow(row),
13729                    &positions,
13730                    selection.reversed,
13731                    &text_layout_details,
13732                ) {
13733                    stack.push(selection.id);
13734                    columnar_selections.push(selection);
13735                }
13736            }
13737            if !stack.is_empty() {
13738                if above {
13739                    stack.reverse();
13740                }
13741                state.groups.push(AddSelectionsGroup { above, stack });
13742            }
13743        }
13744
13745        let mut final_selections = Vec::new();
13746        let end_row = if above {
13747            DisplayRow(0)
13748        } else {
13749            display_map.max_point().row()
13750        };
13751
13752        let mut last_added_item_per_group = HashMap::default();
13753        for group in state.groups.iter_mut() {
13754            if let Some(last_id) = group.stack.last() {
13755                last_added_item_per_group.insert(*last_id, group);
13756            }
13757        }
13758
13759        for selection in columnar_selections {
13760            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13761                if above == group.above {
13762                    let range = selection.display_range(&display_map).sorted();
13763                    debug_assert_eq!(range.start.row(), range.end.row());
13764                    let mut row = range.start.row();
13765                    let positions =
13766                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13767                            px(start)..px(end)
13768                        } else {
13769                            let start_x =
13770                                display_map.x_for_display_point(range.start, &text_layout_details);
13771                            let end_x =
13772                                display_map.x_for_display_point(range.end, &text_layout_details);
13773                            start_x.min(end_x)..start_x.max(end_x)
13774                        };
13775
13776                    let mut maybe_new_selection = None;
13777                    while row != end_row {
13778                        if above {
13779                            row.0 -= 1;
13780                        } else {
13781                            row.0 += 1;
13782                        }
13783                        if let Some(new_selection) = self.selections.build_columnar_selection(
13784                            &display_map,
13785                            row,
13786                            &positions,
13787                            selection.reversed,
13788                            &text_layout_details,
13789                        ) {
13790                            maybe_new_selection = Some(new_selection);
13791                            break;
13792                        }
13793                    }
13794
13795                    if let Some(new_selection) = maybe_new_selection {
13796                        group.stack.push(new_selection.id);
13797                        if above {
13798                            final_selections.push(new_selection);
13799                            final_selections.push(selection);
13800                        } else {
13801                            final_selections.push(selection);
13802                            final_selections.push(new_selection);
13803                        }
13804                    } else {
13805                        final_selections.push(selection);
13806                    }
13807                } else {
13808                    group.stack.pop();
13809                }
13810            } else {
13811                final_selections.push(selection);
13812            }
13813        }
13814
13815        self.change_selections(Default::default(), window, cx, |s| {
13816            s.select(final_selections);
13817        });
13818
13819        let final_selection_ids: HashSet<_> = self
13820            .selections
13821            .all::<Point>(cx)
13822            .iter()
13823            .map(|s| s.id)
13824            .collect();
13825        state.groups.retain_mut(|group| {
13826            // selections might get merged above so we remove invalid items from stacks
13827            group.stack.retain(|id| final_selection_ids.contains(id));
13828
13829            // single selection in stack can be treated as initial state
13830            group.stack.len() > 1
13831        });
13832
13833        if !state.groups.is_empty() {
13834            self.add_selections_state = Some(state);
13835        }
13836    }
13837
13838    fn select_match_ranges(
13839        &mut self,
13840        range: Range<usize>,
13841        reversed: bool,
13842        replace_newest: bool,
13843        auto_scroll: Option<Autoscroll>,
13844        window: &mut Window,
13845        cx: &mut Context<Editor>,
13846    ) {
13847        self.unfold_ranges(
13848            std::slice::from_ref(&range),
13849            false,
13850            auto_scroll.is_some(),
13851            cx,
13852        );
13853        let effects = if let Some(scroll) = auto_scroll {
13854            SelectionEffects::scroll(scroll)
13855        } else {
13856            SelectionEffects::no_scroll()
13857        };
13858        self.change_selections(effects, window, cx, |s| {
13859            if replace_newest {
13860                s.delete(s.newest_anchor().id);
13861            }
13862            if reversed {
13863                s.insert_range(range.end..range.start);
13864            } else {
13865                s.insert_range(range);
13866            }
13867        });
13868    }
13869
13870    pub fn select_next_match_internal(
13871        &mut self,
13872        display_map: &DisplaySnapshot,
13873        replace_newest: bool,
13874        autoscroll: Option<Autoscroll>,
13875        window: &mut Window,
13876        cx: &mut Context<Self>,
13877    ) -> Result<()> {
13878        let buffer = &display_map.buffer_snapshot;
13879        let mut selections = self.selections.all::<usize>(cx);
13880        if let Some(mut select_next_state) = self.select_next_state.take() {
13881            let query = &select_next_state.query;
13882            if !select_next_state.done {
13883                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13884                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13885                let mut next_selected_range = None;
13886
13887                let bytes_after_last_selection =
13888                    buffer.bytes_in_range(last_selection.end..buffer.len());
13889                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13890                let query_matches = query
13891                    .stream_find_iter(bytes_after_last_selection)
13892                    .map(|result| (last_selection.end, result))
13893                    .chain(
13894                        query
13895                            .stream_find_iter(bytes_before_first_selection)
13896                            .map(|result| (0, result)),
13897                    );
13898
13899                for (start_offset, query_match) in query_matches {
13900                    let query_match = query_match.unwrap(); // can only fail due to I/O
13901                    let offset_range =
13902                        start_offset + query_match.start()..start_offset + query_match.end();
13903
13904                    if !select_next_state.wordwise
13905                        || (!buffer.is_inside_word(offset_range.start, false)
13906                            && !buffer.is_inside_word(offset_range.end, false))
13907                    {
13908                        // TODO: This is n^2, because we might check all the selections
13909                        if !selections
13910                            .iter()
13911                            .any(|selection| selection.range().overlaps(&offset_range))
13912                        {
13913                            next_selected_range = Some(offset_range);
13914                            break;
13915                        }
13916                    }
13917                }
13918
13919                if let Some(next_selected_range) = next_selected_range {
13920                    self.select_match_ranges(
13921                        next_selected_range,
13922                        last_selection.reversed,
13923                        replace_newest,
13924                        autoscroll,
13925                        window,
13926                        cx,
13927                    );
13928                } else {
13929                    select_next_state.done = true;
13930                }
13931            }
13932
13933            self.select_next_state = Some(select_next_state);
13934        } else {
13935            let mut only_carets = true;
13936            let mut same_text_selected = true;
13937            let mut selected_text = None;
13938
13939            let mut selections_iter = selections.iter().peekable();
13940            while let Some(selection) = selections_iter.next() {
13941                if selection.start != selection.end {
13942                    only_carets = false;
13943                }
13944
13945                if same_text_selected {
13946                    if selected_text.is_none() {
13947                        selected_text =
13948                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13949                    }
13950
13951                    if let Some(next_selection) = selections_iter.peek() {
13952                        if next_selection.range().len() == selection.range().len() {
13953                            let next_selected_text = buffer
13954                                .text_for_range(next_selection.range())
13955                                .collect::<String>();
13956                            if Some(next_selected_text) != selected_text {
13957                                same_text_selected = false;
13958                                selected_text = None;
13959                            }
13960                        } else {
13961                            same_text_selected = false;
13962                            selected_text = None;
13963                        }
13964                    }
13965                }
13966            }
13967
13968            if only_carets {
13969                for selection in &mut selections {
13970                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13971                    selection.start = word_range.start;
13972                    selection.end = word_range.end;
13973                    selection.goal = SelectionGoal::None;
13974                    selection.reversed = false;
13975                    self.select_match_ranges(
13976                        selection.start..selection.end,
13977                        selection.reversed,
13978                        replace_newest,
13979                        autoscroll,
13980                        window,
13981                        cx,
13982                    );
13983                }
13984
13985                if selections.len() == 1 {
13986                    let selection = selections
13987                        .last()
13988                        .expect("ensured that there's only one selection");
13989                    let query = buffer
13990                        .text_for_range(selection.start..selection.end)
13991                        .collect::<String>();
13992                    let is_empty = query.is_empty();
13993                    let select_state = SelectNextState {
13994                        query: AhoCorasick::new(&[query])?,
13995                        wordwise: true,
13996                        done: is_empty,
13997                    };
13998                    self.select_next_state = Some(select_state);
13999                } else {
14000                    self.select_next_state = None;
14001                }
14002            } else if let Some(selected_text) = selected_text {
14003                self.select_next_state = Some(SelectNextState {
14004                    query: AhoCorasick::new(&[selected_text])?,
14005                    wordwise: false,
14006                    done: false,
14007                });
14008                self.select_next_match_internal(
14009                    display_map,
14010                    replace_newest,
14011                    autoscroll,
14012                    window,
14013                    cx,
14014                )?;
14015            }
14016        }
14017        Ok(())
14018    }
14019
14020    pub fn select_all_matches(
14021        &mut self,
14022        _action: &SelectAllMatches,
14023        window: &mut Window,
14024        cx: &mut Context<Self>,
14025    ) -> Result<()> {
14026        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14027
14028        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14029
14030        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14031        let Some(select_next_state) = self.select_next_state.as_mut() else {
14032            return Ok(());
14033        };
14034        if select_next_state.done {
14035            return Ok(());
14036        }
14037
14038        let mut new_selections = Vec::new();
14039
14040        let reversed = self.selections.oldest::<usize>(cx).reversed;
14041        let buffer = &display_map.buffer_snapshot;
14042        let query_matches = select_next_state
14043            .query
14044            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14045
14046        for query_match in query_matches.into_iter() {
14047            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14048            let offset_range = if reversed {
14049                query_match.end()..query_match.start()
14050            } else {
14051                query_match.start()..query_match.end()
14052            };
14053
14054            if !select_next_state.wordwise
14055                || (!buffer.is_inside_word(offset_range.start, false)
14056                    && !buffer.is_inside_word(offset_range.end, false))
14057            {
14058                new_selections.push(offset_range.start..offset_range.end);
14059            }
14060        }
14061
14062        select_next_state.done = true;
14063
14064        if new_selections.is_empty() {
14065            log::error!("bug: new_selections is empty in select_all_matches");
14066            return Ok(());
14067        }
14068
14069        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14070        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14071            selections.select_ranges(new_selections)
14072        });
14073
14074        Ok(())
14075    }
14076
14077    pub fn select_next(
14078        &mut self,
14079        action: &SelectNext,
14080        window: &mut Window,
14081        cx: &mut Context<Self>,
14082    ) -> Result<()> {
14083        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14084        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14085        self.select_next_match_internal(
14086            &display_map,
14087            action.replace_newest,
14088            Some(Autoscroll::newest()),
14089            window,
14090            cx,
14091        )?;
14092        Ok(())
14093    }
14094
14095    pub fn select_previous(
14096        &mut self,
14097        action: &SelectPrevious,
14098        window: &mut Window,
14099        cx: &mut Context<Self>,
14100    ) -> Result<()> {
14101        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14102        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14103        let buffer = &display_map.buffer_snapshot;
14104        let mut selections = self.selections.all::<usize>(cx);
14105        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14106            let query = &select_prev_state.query;
14107            if !select_prev_state.done {
14108                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14109                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14110                let mut next_selected_range = None;
14111                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14112                let bytes_before_last_selection =
14113                    buffer.reversed_bytes_in_range(0..last_selection.start);
14114                let bytes_after_first_selection =
14115                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14116                let query_matches = query
14117                    .stream_find_iter(bytes_before_last_selection)
14118                    .map(|result| (last_selection.start, result))
14119                    .chain(
14120                        query
14121                            .stream_find_iter(bytes_after_first_selection)
14122                            .map(|result| (buffer.len(), result)),
14123                    );
14124                for (end_offset, query_match) in query_matches {
14125                    let query_match = query_match.unwrap(); // can only fail due to I/O
14126                    let offset_range =
14127                        end_offset - query_match.end()..end_offset - query_match.start();
14128
14129                    if !select_prev_state.wordwise
14130                        || (!buffer.is_inside_word(offset_range.start, false)
14131                            && !buffer.is_inside_word(offset_range.end, false))
14132                    {
14133                        next_selected_range = Some(offset_range);
14134                        break;
14135                    }
14136                }
14137
14138                if let Some(next_selected_range) = next_selected_range {
14139                    self.select_match_ranges(
14140                        next_selected_range,
14141                        last_selection.reversed,
14142                        action.replace_newest,
14143                        Some(Autoscroll::newest()),
14144                        window,
14145                        cx,
14146                    );
14147                } else {
14148                    select_prev_state.done = true;
14149                }
14150            }
14151
14152            self.select_prev_state = Some(select_prev_state);
14153        } else {
14154            let mut only_carets = true;
14155            let mut same_text_selected = true;
14156            let mut selected_text = None;
14157
14158            let mut selections_iter = selections.iter().peekable();
14159            while let Some(selection) = selections_iter.next() {
14160                if selection.start != selection.end {
14161                    only_carets = false;
14162                }
14163
14164                if same_text_selected {
14165                    if selected_text.is_none() {
14166                        selected_text =
14167                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14168                    }
14169
14170                    if let Some(next_selection) = selections_iter.peek() {
14171                        if next_selection.range().len() == selection.range().len() {
14172                            let next_selected_text = buffer
14173                                .text_for_range(next_selection.range())
14174                                .collect::<String>();
14175                            if Some(next_selected_text) != selected_text {
14176                                same_text_selected = false;
14177                                selected_text = None;
14178                            }
14179                        } else {
14180                            same_text_selected = false;
14181                            selected_text = None;
14182                        }
14183                    }
14184                }
14185            }
14186
14187            if only_carets {
14188                for selection in &mut selections {
14189                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14190                    selection.start = word_range.start;
14191                    selection.end = word_range.end;
14192                    selection.goal = SelectionGoal::None;
14193                    selection.reversed = false;
14194                    self.select_match_ranges(
14195                        selection.start..selection.end,
14196                        selection.reversed,
14197                        action.replace_newest,
14198                        Some(Autoscroll::newest()),
14199                        window,
14200                        cx,
14201                    );
14202                }
14203                if selections.len() == 1 {
14204                    let selection = selections
14205                        .last()
14206                        .expect("ensured that there's only one selection");
14207                    let query = buffer
14208                        .text_for_range(selection.start..selection.end)
14209                        .collect::<String>();
14210                    let is_empty = query.is_empty();
14211                    let select_state = SelectNextState {
14212                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14213                        wordwise: true,
14214                        done: is_empty,
14215                    };
14216                    self.select_prev_state = Some(select_state);
14217                } else {
14218                    self.select_prev_state = None;
14219                }
14220            } else if let Some(selected_text) = selected_text {
14221                self.select_prev_state = Some(SelectNextState {
14222                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14223                    wordwise: false,
14224                    done: false,
14225                });
14226                self.select_previous(action, window, cx)?;
14227            }
14228        }
14229        Ok(())
14230    }
14231
14232    pub fn find_next_match(
14233        &mut self,
14234        _: &FindNextMatch,
14235        window: &mut Window,
14236        cx: &mut Context<Self>,
14237    ) -> Result<()> {
14238        let selections = self.selections.disjoint_anchors();
14239        match selections.first() {
14240            Some(first) if selections.len() >= 2 => {
14241                self.change_selections(Default::default(), window, cx, |s| {
14242                    s.select_ranges([first.range()]);
14243                });
14244            }
14245            _ => self.select_next(
14246                &SelectNext {
14247                    replace_newest: true,
14248                },
14249                window,
14250                cx,
14251            )?,
14252        }
14253        Ok(())
14254    }
14255
14256    pub fn find_previous_match(
14257        &mut self,
14258        _: &FindPreviousMatch,
14259        window: &mut Window,
14260        cx: &mut Context<Self>,
14261    ) -> Result<()> {
14262        let selections = self.selections.disjoint_anchors();
14263        match selections.last() {
14264            Some(last) if selections.len() >= 2 => {
14265                self.change_selections(Default::default(), window, cx, |s| {
14266                    s.select_ranges([last.range()]);
14267                });
14268            }
14269            _ => self.select_previous(
14270                &SelectPrevious {
14271                    replace_newest: true,
14272                },
14273                window,
14274                cx,
14275            )?,
14276        }
14277        Ok(())
14278    }
14279
14280    pub fn toggle_comments(
14281        &mut self,
14282        action: &ToggleComments,
14283        window: &mut Window,
14284        cx: &mut Context<Self>,
14285    ) {
14286        if self.read_only(cx) {
14287            return;
14288        }
14289        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14290        let text_layout_details = &self.text_layout_details(window);
14291        self.transact(window, cx, |this, window, cx| {
14292            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14293            let mut edits = Vec::new();
14294            let mut selection_edit_ranges = Vec::new();
14295            let mut last_toggled_row = None;
14296            let snapshot = this.buffer.read(cx).read(cx);
14297            let empty_str: Arc<str> = Arc::default();
14298            let mut suffixes_inserted = Vec::new();
14299            let ignore_indent = action.ignore_indent;
14300
14301            fn comment_prefix_range(
14302                snapshot: &MultiBufferSnapshot,
14303                row: MultiBufferRow,
14304                comment_prefix: &str,
14305                comment_prefix_whitespace: &str,
14306                ignore_indent: bool,
14307            ) -> Range<Point> {
14308                let indent_size = if ignore_indent {
14309                    0
14310                } else {
14311                    snapshot.indent_size_for_line(row).len
14312                };
14313
14314                let start = Point::new(row.0, indent_size);
14315
14316                let mut line_bytes = snapshot
14317                    .bytes_in_range(start..snapshot.max_point())
14318                    .flatten()
14319                    .copied();
14320
14321                // If this line currently begins with the line comment prefix, then record
14322                // the range containing the prefix.
14323                if line_bytes
14324                    .by_ref()
14325                    .take(comment_prefix.len())
14326                    .eq(comment_prefix.bytes())
14327                {
14328                    // Include any whitespace that matches the comment prefix.
14329                    let matching_whitespace_len = line_bytes
14330                        .zip(comment_prefix_whitespace.bytes())
14331                        .take_while(|(a, b)| a == b)
14332                        .count() as u32;
14333                    let end = Point::new(
14334                        start.row,
14335                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14336                    );
14337                    start..end
14338                } else {
14339                    start..start
14340                }
14341            }
14342
14343            fn comment_suffix_range(
14344                snapshot: &MultiBufferSnapshot,
14345                row: MultiBufferRow,
14346                comment_suffix: &str,
14347                comment_suffix_has_leading_space: bool,
14348            ) -> Range<Point> {
14349                let end = Point::new(row.0, snapshot.line_len(row));
14350                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14351
14352                let mut line_end_bytes = snapshot
14353                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14354                    .flatten()
14355                    .copied();
14356
14357                let leading_space_len = if suffix_start_column > 0
14358                    && line_end_bytes.next() == Some(b' ')
14359                    && comment_suffix_has_leading_space
14360                {
14361                    1
14362                } else {
14363                    0
14364                };
14365
14366                // If this line currently begins with the line comment prefix, then record
14367                // the range containing the prefix.
14368                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14369                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14370                    start..end
14371                } else {
14372                    end..end
14373                }
14374            }
14375
14376            // TODO: Handle selections that cross excerpts
14377            for selection in &mut selections {
14378                let start_column = snapshot
14379                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14380                    .len;
14381                let language = if let Some(language) =
14382                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14383                {
14384                    language
14385                } else {
14386                    continue;
14387                };
14388
14389                selection_edit_ranges.clear();
14390
14391                // If multiple selections contain a given row, avoid processing that
14392                // row more than once.
14393                let mut start_row = MultiBufferRow(selection.start.row);
14394                if last_toggled_row == Some(start_row) {
14395                    start_row = start_row.next_row();
14396                }
14397                let end_row =
14398                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14399                        MultiBufferRow(selection.end.row - 1)
14400                    } else {
14401                        MultiBufferRow(selection.end.row)
14402                    };
14403                last_toggled_row = Some(end_row);
14404
14405                if start_row > end_row {
14406                    continue;
14407                }
14408
14409                // If the language has line comments, toggle those.
14410                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14411
14412                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14413                if ignore_indent {
14414                    full_comment_prefixes = full_comment_prefixes
14415                        .into_iter()
14416                        .map(|s| Arc::from(s.trim_end()))
14417                        .collect();
14418                }
14419
14420                if !full_comment_prefixes.is_empty() {
14421                    let first_prefix = full_comment_prefixes
14422                        .first()
14423                        .expect("prefixes is non-empty");
14424                    let prefix_trimmed_lengths = full_comment_prefixes
14425                        .iter()
14426                        .map(|p| p.trim_end_matches(' ').len())
14427                        .collect::<SmallVec<[usize; 4]>>();
14428
14429                    let mut all_selection_lines_are_comments = true;
14430
14431                    for row in start_row.0..=end_row.0 {
14432                        let row = MultiBufferRow(row);
14433                        if start_row < end_row && snapshot.is_line_blank(row) {
14434                            continue;
14435                        }
14436
14437                        let prefix_range = full_comment_prefixes
14438                            .iter()
14439                            .zip(prefix_trimmed_lengths.iter().copied())
14440                            .map(|(prefix, trimmed_prefix_len)| {
14441                                comment_prefix_range(
14442                                    snapshot.deref(),
14443                                    row,
14444                                    &prefix[..trimmed_prefix_len],
14445                                    &prefix[trimmed_prefix_len..],
14446                                    ignore_indent,
14447                                )
14448                            })
14449                            .max_by_key(|range| range.end.column - range.start.column)
14450                            .expect("prefixes is non-empty");
14451
14452                        if prefix_range.is_empty() {
14453                            all_selection_lines_are_comments = false;
14454                        }
14455
14456                        selection_edit_ranges.push(prefix_range);
14457                    }
14458
14459                    if all_selection_lines_are_comments {
14460                        edits.extend(
14461                            selection_edit_ranges
14462                                .iter()
14463                                .cloned()
14464                                .map(|range| (range, empty_str.clone())),
14465                        );
14466                    } else {
14467                        let min_column = selection_edit_ranges
14468                            .iter()
14469                            .map(|range| range.start.column)
14470                            .min()
14471                            .unwrap_or(0);
14472                        edits.extend(selection_edit_ranges.iter().map(|range| {
14473                            let position = Point::new(range.start.row, min_column);
14474                            (position..position, first_prefix.clone())
14475                        }));
14476                    }
14477                } else if let Some(BlockCommentConfig {
14478                    start: full_comment_prefix,
14479                    end: comment_suffix,
14480                    ..
14481                }) = language.block_comment()
14482                {
14483                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14484                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14485                    let prefix_range = comment_prefix_range(
14486                        snapshot.deref(),
14487                        start_row,
14488                        comment_prefix,
14489                        comment_prefix_whitespace,
14490                        ignore_indent,
14491                    );
14492                    let suffix_range = comment_suffix_range(
14493                        snapshot.deref(),
14494                        end_row,
14495                        comment_suffix.trim_start_matches(' '),
14496                        comment_suffix.starts_with(' '),
14497                    );
14498
14499                    if prefix_range.is_empty() || suffix_range.is_empty() {
14500                        edits.push((
14501                            prefix_range.start..prefix_range.start,
14502                            full_comment_prefix.clone(),
14503                        ));
14504                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14505                        suffixes_inserted.push((end_row, comment_suffix.len()));
14506                    } else {
14507                        edits.push((prefix_range, empty_str.clone()));
14508                        edits.push((suffix_range, empty_str.clone()));
14509                    }
14510                } else {
14511                    continue;
14512                }
14513            }
14514
14515            drop(snapshot);
14516            this.buffer.update(cx, |buffer, cx| {
14517                buffer.edit(edits, None, cx);
14518            });
14519
14520            // Adjust selections so that they end before any comment suffixes that
14521            // were inserted.
14522            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14523            let mut selections = this.selections.all::<Point>(cx);
14524            let snapshot = this.buffer.read(cx).read(cx);
14525            for selection in &mut selections {
14526                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14527                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14528                        Ordering::Less => {
14529                            suffixes_inserted.next();
14530                            continue;
14531                        }
14532                        Ordering::Greater => break,
14533                        Ordering::Equal => {
14534                            if selection.end.column == snapshot.line_len(row) {
14535                                if selection.is_empty() {
14536                                    selection.start.column -= suffix_len as u32;
14537                                }
14538                                selection.end.column -= suffix_len as u32;
14539                            }
14540                            break;
14541                        }
14542                    }
14543                }
14544            }
14545
14546            drop(snapshot);
14547            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14548
14549            let selections = this.selections.all::<Point>(cx);
14550            let selections_on_single_row = selections.windows(2).all(|selections| {
14551                selections[0].start.row == selections[1].start.row
14552                    && selections[0].end.row == selections[1].end.row
14553                    && selections[0].start.row == selections[0].end.row
14554            });
14555            let selections_selecting = selections
14556                .iter()
14557                .any(|selection| selection.start != selection.end);
14558            let advance_downwards = action.advance_downwards
14559                && selections_on_single_row
14560                && !selections_selecting
14561                && !matches!(this.mode, EditorMode::SingleLine { .. });
14562
14563            if advance_downwards {
14564                let snapshot = this.buffer.read(cx).snapshot(cx);
14565
14566                this.change_selections(Default::default(), window, cx, |s| {
14567                    s.move_cursors_with(|display_snapshot, display_point, _| {
14568                        let mut point = display_point.to_point(display_snapshot);
14569                        point.row += 1;
14570                        point = snapshot.clip_point(point, Bias::Left);
14571                        let display_point = point.to_display_point(display_snapshot);
14572                        let goal = SelectionGoal::HorizontalPosition(
14573                            display_snapshot
14574                                .x_for_display_point(display_point, text_layout_details)
14575                                .into(),
14576                        );
14577                        (display_point, goal)
14578                    })
14579                });
14580            }
14581        });
14582    }
14583
14584    pub fn select_enclosing_symbol(
14585        &mut self,
14586        _: &SelectEnclosingSymbol,
14587        window: &mut Window,
14588        cx: &mut Context<Self>,
14589    ) {
14590        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14591
14592        let buffer = self.buffer.read(cx).snapshot(cx);
14593        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14594
14595        fn update_selection(
14596            selection: &Selection<usize>,
14597            buffer_snap: &MultiBufferSnapshot,
14598        ) -> Option<Selection<usize>> {
14599            let cursor = selection.head();
14600            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14601            for symbol in symbols.iter().rev() {
14602                let start = symbol.range.start.to_offset(buffer_snap);
14603                let end = symbol.range.end.to_offset(buffer_snap);
14604                let new_range = start..end;
14605                if start < selection.start || end > selection.end {
14606                    return Some(Selection {
14607                        id: selection.id,
14608                        start: new_range.start,
14609                        end: new_range.end,
14610                        goal: SelectionGoal::None,
14611                        reversed: selection.reversed,
14612                    });
14613                }
14614            }
14615            None
14616        }
14617
14618        let mut selected_larger_symbol = false;
14619        let new_selections = old_selections
14620            .iter()
14621            .map(|selection| match update_selection(selection, &buffer) {
14622                Some(new_selection) => {
14623                    if new_selection.range() != selection.range() {
14624                        selected_larger_symbol = true;
14625                    }
14626                    new_selection
14627                }
14628                None => selection.clone(),
14629            })
14630            .collect::<Vec<_>>();
14631
14632        if selected_larger_symbol {
14633            self.change_selections(Default::default(), window, cx, |s| {
14634                s.select(new_selections);
14635            });
14636        }
14637    }
14638
14639    pub fn select_larger_syntax_node(
14640        &mut self,
14641        _: &SelectLargerSyntaxNode,
14642        window: &mut Window,
14643        cx: &mut Context<Self>,
14644    ) {
14645        let Some(visible_row_count) = self.visible_row_count() else {
14646            return;
14647        };
14648        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14649        if old_selections.is_empty() {
14650            return;
14651        }
14652
14653        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14654
14655        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14656        let buffer = self.buffer.read(cx).snapshot(cx);
14657
14658        let mut selected_larger_node = false;
14659        let mut new_selections = old_selections
14660            .iter()
14661            .map(|selection| {
14662                let old_range = selection.start..selection.end;
14663
14664                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14665                    // manually select word at selection
14666                    if ["string_content", "inline"].contains(&node.kind()) {
14667                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14668                        // ignore if word is already selected
14669                        if !word_range.is_empty() && old_range != word_range {
14670                            let (last_word_range, _) =
14671                                buffer.surrounding_word(old_range.end, false);
14672                            // only select word if start and end point belongs to same word
14673                            if word_range == last_word_range {
14674                                selected_larger_node = true;
14675                                return Selection {
14676                                    id: selection.id,
14677                                    start: word_range.start,
14678                                    end: word_range.end,
14679                                    goal: SelectionGoal::None,
14680                                    reversed: selection.reversed,
14681                                };
14682                            }
14683                        }
14684                    }
14685                }
14686
14687                let mut new_range = old_range.clone();
14688                while let Some((_node, containing_range)) =
14689                    buffer.syntax_ancestor(new_range.clone())
14690                {
14691                    new_range = match containing_range {
14692                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14693                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14694                    };
14695                    if !display_map.intersects_fold(new_range.start)
14696                        && !display_map.intersects_fold(new_range.end)
14697                    {
14698                        break;
14699                    }
14700                }
14701
14702                selected_larger_node |= new_range != old_range;
14703                Selection {
14704                    id: selection.id,
14705                    start: new_range.start,
14706                    end: new_range.end,
14707                    goal: SelectionGoal::None,
14708                    reversed: selection.reversed,
14709                }
14710            })
14711            .collect::<Vec<_>>();
14712
14713        if !selected_larger_node {
14714            return; // don't put this call in the history
14715        }
14716
14717        // scroll based on transformation done to the last selection created by the user
14718        let (last_old, last_new) = old_selections
14719            .last()
14720            .zip(new_selections.last().cloned())
14721            .expect("old_selections isn't empty");
14722
14723        // revert selection
14724        let is_selection_reversed = {
14725            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14726            new_selections.last_mut().expect("checked above").reversed =
14727                should_newest_selection_be_reversed;
14728            should_newest_selection_be_reversed
14729        };
14730
14731        if selected_larger_node {
14732            self.select_syntax_node_history.disable_clearing = true;
14733            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14734                s.select(new_selections.clone());
14735            });
14736            self.select_syntax_node_history.disable_clearing = false;
14737        }
14738
14739        let start_row = last_new.start.to_display_point(&display_map).row().0;
14740        let end_row = last_new.end.to_display_point(&display_map).row().0;
14741        let selection_height = end_row - start_row + 1;
14742        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14743
14744        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14745        let scroll_behavior = if fits_on_the_screen {
14746            self.request_autoscroll(Autoscroll::fit(), cx);
14747            SelectSyntaxNodeScrollBehavior::FitSelection
14748        } else if is_selection_reversed {
14749            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14750            SelectSyntaxNodeScrollBehavior::CursorTop
14751        } else {
14752            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14753            SelectSyntaxNodeScrollBehavior::CursorBottom
14754        };
14755
14756        self.select_syntax_node_history.push((
14757            old_selections,
14758            scroll_behavior,
14759            is_selection_reversed,
14760        ));
14761    }
14762
14763    pub fn select_smaller_syntax_node(
14764        &mut self,
14765        _: &SelectSmallerSyntaxNode,
14766        window: &mut Window,
14767        cx: &mut Context<Self>,
14768    ) {
14769        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14770
14771        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14772            self.select_syntax_node_history.pop()
14773        {
14774            if let Some(selection) = selections.last_mut() {
14775                selection.reversed = is_selection_reversed;
14776            }
14777
14778            self.select_syntax_node_history.disable_clearing = true;
14779            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14780                s.select(selections.to_vec());
14781            });
14782            self.select_syntax_node_history.disable_clearing = false;
14783
14784            match scroll_behavior {
14785                SelectSyntaxNodeScrollBehavior::CursorTop => {
14786                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14787                }
14788                SelectSyntaxNodeScrollBehavior::FitSelection => {
14789                    self.request_autoscroll(Autoscroll::fit(), cx);
14790                }
14791                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14792                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14793                }
14794            }
14795        }
14796    }
14797
14798    pub fn unwrap_syntax_node(
14799        &mut self,
14800        _: &UnwrapSyntaxNode,
14801        window: &mut Window,
14802        cx: &mut Context<Self>,
14803    ) {
14804        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14805
14806        let buffer = self.buffer.read(cx).snapshot(cx);
14807        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14808
14809        let edits = old_selections
14810            .iter()
14811            // only consider the first selection for now
14812            .take(1)
14813            .map(|selection| {
14814                // Only requires two branches once if-let-chains stabilize (#53667)
14815                let selection_range = if !selection.is_empty() {
14816                    selection.range()
14817                } else if let Some((_, ancestor_range)) =
14818                    buffer.syntax_ancestor(selection.start..selection.end)
14819                {
14820                    match ancestor_range {
14821                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14822                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14823                    }
14824                } else {
14825                    selection.range()
14826                };
14827
14828                let mut new_range = selection_range.clone();
14829                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(new_range.clone()) {
14830                    new_range = match ancestor_range {
14831                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14832                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14833                    };
14834                    if new_range.start < selection_range.start
14835                        || new_range.end > selection_range.end
14836                    {
14837                        break;
14838                    }
14839                }
14840
14841                (selection, selection_range, new_range)
14842            })
14843            .collect::<Vec<_>>();
14844
14845        self.transact(window, cx, |editor, window, cx| {
14846            for (_, child, parent) in &edits {
14847                let text = buffer.text_for_range(child.clone()).collect::<String>();
14848                editor.replace_text_in_range(Some(parent.clone()), &text, window, cx);
14849            }
14850
14851            editor.change_selections(
14852                SelectionEffects::scroll(Autoscroll::fit()),
14853                window,
14854                cx,
14855                |s| {
14856                    s.select(
14857                        edits
14858                            .iter()
14859                            .map(|(s, old, new)| Selection {
14860                                id: s.id,
14861                                start: new.start,
14862                                end: new.start + old.len(),
14863                                goal: SelectionGoal::None,
14864                                reversed: s.reversed,
14865                            })
14866                            .collect(),
14867                    );
14868                },
14869            );
14870        });
14871    }
14872
14873    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14874        if !EditorSettings::get_global(cx).gutter.runnables {
14875            self.clear_tasks();
14876            return Task::ready(());
14877        }
14878        let project = self.project.as_ref().map(Entity::downgrade);
14879        let task_sources = self.lsp_task_sources(cx);
14880        let multi_buffer = self.buffer.downgrade();
14881        cx.spawn_in(window, async move |editor, cx| {
14882            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14883            let Some(project) = project.and_then(|p| p.upgrade()) else {
14884                return;
14885            };
14886            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14887                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14888            }) else {
14889                return;
14890            };
14891
14892            let hide_runnables = project
14893                .update(cx, |project, cx| {
14894                    // Do not display any test indicators in non-dev server remote projects.
14895                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14896                })
14897                .unwrap_or(true);
14898            if hide_runnables {
14899                return;
14900            }
14901            let new_rows =
14902                cx.background_spawn({
14903                    let snapshot = display_snapshot.clone();
14904                    async move {
14905                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14906                    }
14907                })
14908                    .await;
14909            let Ok(lsp_tasks) =
14910                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14911            else {
14912                return;
14913            };
14914            let lsp_tasks = lsp_tasks.await;
14915
14916            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14917                lsp_tasks
14918                    .into_iter()
14919                    .flat_map(|(kind, tasks)| {
14920                        tasks.into_iter().filter_map(move |(location, task)| {
14921                            Some((kind.clone(), location?, task))
14922                        })
14923                    })
14924                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14925                        let buffer = location.target.buffer;
14926                        let buffer_snapshot = buffer.read(cx).snapshot();
14927                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14928                            |(excerpt_id, snapshot, _)| {
14929                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14930                                    display_snapshot
14931                                        .buffer_snapshot
14932                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14933                                } else {
14934                                    None
14935                                }
14936                            },
14937                        );
14938                        if let Some(offset) = offset {
14939                            let task_buffer_range =
14940                                location.target.range.to_point(&buffer_snapshot);
14941                            let context_buffer_range =
14942                                task_buffer_range.to_offset(&buffer_snapshot);
14943                            let context_range = BufferOffset(context_buffer_range.start)
14944                                ..BufferOffset(context_buffer_range.end);
14945
14946                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14947                                .or_insert_with(|| RunnableTasks {
14948                                    templates: Vec::new(),
14949                                    offset,
14950                                    column: task_buffer_range.start.column,
14951                                    extra_variables: HashMap::default(),
14952                                    context_range,
14953                                })
14954                                .templates
14955                                .push((kind, task.original_task().clone()));
14956                        }
14957
14958                        acc
14959                    })
14960            }) else {
14961                return;
14962            };
14963
14964            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14965                buffer.language_settings(cx).tasks.prefer_lsp
14966            }) else {
14967                return;
14968            };
14969
14970            let rows = Self::runnable_rows(
14971                project,
14972                display_snapshot,
14973                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
14974                new_rows,
14975                cx.clone(),
14976            )
14977            .await;
14978            editor
14979                .update(cx, |editor, _| {
14980                    editor.clear_tasks();
14981                    for (key, mut value) in rows {
14982                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
14983                            value.templates.extend(lsp_tasks.templates);
14984                        }
14985
14986                        editor.insert_tasks(key, value);
14987                    }
14988                    for (key, value) in lsp_tasks_by_rows {
14989                        editor.insert_tasks(key, value);
14990                    }
14991                })
14992                .ok();
14993        })
14994    }
14995    fn fetch_runnable_ranges(
14996        snapshot: &DisplaySnapshot,
14997        range: Range<Anchor>,
14998    ) -> Vec<language::RunnableRange> {
14999        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15000    }
15001
15002    fn runnable_rows(
15003        project: Entity<Project>,
15004        snapshot: DisplaySnapshot,
15005        prefer_lsp: bool,
15006        runnable_ranges: Vec<RunnableRange>,
15007        cx: AsyncWindowContext,
15008    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15009        cx.spawn(async move |cx| {
15010            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15011            for mut runnable in runnable_ranges {
15012                let Some(tasks) = cx
15013                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15014                    .ok()
15015                else {
15016                    continue;
15017                };
15018                let mut tasks = tasks.await;
15019
15020                if prefer_lsp {
15021                    tasks.retain(|(task_kind, _)| {
15022                        !matches!(task_kind, TaskSourceKind::Language { .. })
15023                    });
15024                }
15025                if tasks.is_empty() {
15026                    continue;
15027                }
15028
15029                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15030                let Some(row) = snapshot
15031                    .buffer_snapshot
15032                    .buffer_line_for_row(MultiBufferRow(point.row))
15033                    .map(|(_, range)| range.start.row)
15034                else {
15035                    continue;
15036                };
15037
15038                let context_range =
15039                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15040                runnable_rows.push((
15041                    (runnable.buffer_id, row),
15042                    RunnableTasks {
15043                        templates: tasks,
15044                        offset: snapshot
15045                            .buffer_snapshot
15046                            .anchor_before(runnable.run_range.start),
15047                        context_range,
15048                        column: point.column,
15049                        extra_variables: runnable.extra_captures,
15050                    },
15051                ));
15052            }
15053            runnable_rows
15054        })
15055    }
15056
15057    fn templates_with_tags(
15058        project: &Entity<Project>,
15059        runnable: &mut Runnable,
15060        cx: &mut App,
15061    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15062        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15063            let (worktree_id, file) = project
15064                .buffer_for_id(runnable.buffer, cx)
15065                .and_then(|buffer| buffer.read(cx).file())
15066                .map(|file| (file.worktree_id(cx), file.clone()))
15067                .unzip();
15068
15069            (
15070                project.task_store().read(cx).task_inventory().cloned(),
15071                worktree_id,
15072                file,
15073            )
15074        });
15075
15076        let tags = mem::take(&mut runnable.tags);
15077        let language = runnable.language.clone();
15078        cx.spawn(async move |cx| {
15079            let mut templates_with_tags = Vec::new();
15080            if let Some(inventory) = inventory {
15081                for RunnableTag(tag) in tags {
15082                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15083                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15084                    }) else {
15085                        return templates_with_tags;
15086                    };
15087                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15088                        move |(_, template)| {
15089                            template.tags.iter().any(|source_tag| source_tag == &tag)
15090                        },
15091                    ));
15092                }
15093            }
15094            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15095
15096            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15097                // Strongest source wins; if we have worktree tag binding, prefer that to
15098                // global and language bindings;
15099                // if we have a global binding, prefer that to language binding.
15100                let first_mismatch = templates_with_tags
15101                    .iter()
15102                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15103                if let Some(index) = first_mismatch {
15104                    templates_with_tags.truncate(index);
15105                }
15106            }
15107
15108            templates_with_tags
15109        })
15110    }
15111
15112    pub fn move_to_enclosing_bracket(
15113        &mut self,
15114        _: &MoveToEnclosingBracket,
15115        window: &mut Window,
15116        cx: &mut Context<Self>,
15117    ) {
15118        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15119        self.change_selections(Default::default(), window, cx, |s| {
15120            s.move_offsets_with(|snapshot, selection| {
15121                let Some(enclosing_bracket_ranges) =
15122                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15123                else {
15124                    return;
15125                };
15126
15127                let mut best_length = usize::MAX;
15128                let mut best_inside = false;
15129                let mut best_in_bracket_range = false;
15130                let mut best_destination = None;
15131                for (open, close) in enclosing_bracket_ranges {
15132                    let close = close.to_inclusive();
15133                    let length = close.end() - open.start;
15134                    let inside = selection.start >= open.end && selection.end <= *close.start();
15135                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15136                        || close.contains(&selection.head());
15137
15138                    // If best is next to a bracket and current isn't, skip
15139                    if !in_bracket_range && best_in_bracket_range {
15140                        continue;
15141                    }
15142
15143                    // Prefer smaller lengths unless best is inside and current isn't
15144                    if length > best_length && (best_inside || !inside) {
15145                        continue;
15146                    }
15147
15148                    best_length = length;
15149                    best_inside = inside;
15150                    best_in_bracket_range = in_bracket_range;
15151                    best_destination = Some(
15152                        if close.contains(&selection.start) && close.contains(&selection.end) {
15153                            if inside { open.end } else { open.start }
15154                        } else if inside {
15155                            *close.start()
15156                        } else {
15157                            *close.end()
15158                        },
15159                    );
15160                }
15161
15162                if let Some(destination) = best_destination {
15163                    selection.collapse_to(destination, SelectionGoal::None);
15164                }
15165            })
15166        });
15167    }
15168
15169    pub fn undo_selection(
15170        &mut self,
15171        _: &UndoSelection,
15172        window: &mut Window,
15173        cx: &mut Context<Self>,
15174    ) {
15175        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15176        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15177            self.selection_history.mode = SelectionHistoryMode::Undoing;
15178            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15179                this.end_selection(window, cx);
15180                this.change_selections(
15181                    SelectionEffects::scroll(Autoscroll::newest()),
15182                    window,
15183                    cx,
15184                    |s| s.select_anchors(entry.selections.to_vec()),
15185                );
15186            });
15187            self.selection_history.mode = SelectionHistoryMode::Normal;
15188
15189            self.select_next_state = entry.select_next_state;
15190            self.select_prev_state = entry.select_prev_state;
15191            self.add_selections_state = entry.add_selections_state;
15192        }
15193    }
15194
15195    pub fn redo_selection(
15196        &mut self,
15197        _: &RedoSelection,
15198        window: &mut Window,
15199        cx: &mut Context<Self>,
15200    ) {
15201        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15202        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15203            self.selection_history.mode = SelectionHistoryMode::Redoing;
15204            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15205                this.end_selection(window, cx);
15206                this.change_selections(
15207                    SelectionEffects::scroll(Autoscroll::newest()),
15208                    window,
15209                    cx,
15210                    |s| s.select_anchors(entry.selections.to_vec()),
15211                );
15212            });
15213            self.selection_history.mode = SelectionHistoryMode::Normal;
15214
15215            self.select_next_state = entry.select_next_state;
15216            self.select_prev_state = entry.select_prev_state;
15217            self.add_selections_state = entry.add_selections_state;
15218        }
15219    }
15220
15221    pub fn expand_excerpts(
15222        &mut self,
15223        action: &ExpandExcerpts,
15224        _: &mut Window,
15225        cx: &mut Context<Self>,
15226    ) {
15227        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15228    }
15229
15230    pub fn expand_excerpts_down(
15231        &mut self,
15232        action: &ExpandExcerptsDown,
15233        _: &mut Window,
15234        cx: &mut Context<Self>,
15235    ) {
15236        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15237    }
15238
15239    pub fn expand_excerpts_up(
15240        &mut self,
15241        action: &ExpandExcerptsUp,
15242        _: &mut Window,
15243        cx: &mut Context<Self>,
15244    ) {
15245        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15246    }
15247
15248    pub fn expand_excerpts_for_direction(
15249        &mut self,
15250        lines: u32,
15251        direction: ExpandExcerptDirection,
15252
15253        cx: &mut Context<Self>,
15254    ) {
15255        let selections = self.selections.disjoint_anchors();
15256
15257        let lines = if lines == 0 {
15258            EditorSettings::get_global(cx).expand_excerpt_lines
15259        } else {
15260            lines
15261        };
15262
15263        self.buffer.update(cx, |buffer, cx| {
15264            let snapshot = buffer.snapshot(cx);
15265            let mut excerpt_ids = selections
15266                .iter()
15267                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15268                .collect::<Vec<_>>();
15269            excerpt_ids.sort();
15270            excerpt_ids.dedup();
15271            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15272        })
15273    }
15274
15275    pub fn expand_excerpt(
15276        &mut self,
15277        excerpt: ExcerptId,
15278        direction: ExpandExcerptDirection,
15279        window: &mut Window,
15280        cx: &mut Context<Self>,
15281    ) {
15282        let current_scroll_position = self.scroll_position(cx);
15283        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15284        let mut should_scroll_up = false;
15285
15286        if direction == ExpandExcerptDirection::Down {
15287            let multi_buffer = self.buffer.read(cx);
15288            let snapshot = multi_buffer.snapshot(cx);
15289            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt) {
15290                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
15291                    if let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt) {
15292                        let buffer_snapshot = buffer.read(cx).snapshot();
15293                        let excerpt_end_row =
15294                            Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15295                        let last_row = buffer_snapshot.max_point().row;
15296                        let lines_below = last_row.saturating_sub(excerpt_end_row);
15297                        should_scroll_up = lines_below >= lines_to_expand;
15298                    }
15299                }
15300            }
15301        }
15302
15303        self.buffer.update(cx, |buffer, cx| {
15304            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15305        });
15306
15307        if should_scroll_up {
15308            let new_scroll_position =
15309                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15310            self.set_scroll_position(new_scroll_position, window, cx);
15311        }
15312    }
15313
15314    pub fn go_to_singleton_buffer_point(
15315        &mut self,
15316        point: Point,
15317        window: &mut Window,
15318        cx: &mut Context<Self>,
15319    ) {
15320        self.go_to_singleton_buffer_range(point..point, window, cx);
15321    }
15322
15323    pub fn go_to_singleton_buffer_range(
15324        &mut self,
15325        range: Range<Point>,
15326        window: &mut Window,
15327        cx: &mut Context<Self>,
15328    ) {
15329        let multibuffer = self.buffer().read(cx);
15330        let Some(buffer) = multibuffer.as_singleton() else {
15331            return;
15332        };
15333        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15334            return;
15335        };
15336        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15337            return;
15338        };
15339        self.change_selections(
15340            SelectionEffects::default().nav_history(true),
15341            window,
15342            cx,
15343            |s| s.select_anchor_ranges([start..end]),
15344        );
15345    }
15346
15347    pub fn go_to_diagnostic(
15348        &mut self,
15349        action: &GoToDiagnostic,
15350        window: &mut Window,
15351        cx: &mut Context<Self>,
15352    ) {
15353        if !self.diagnostics_enabled() {
15354            return;
15355        }
15356        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15357        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15358    }
15359
15360    pub fn go_to_prev_diagnostic(
15361        &mut self,
15362        action: &GoToPreviousDiagnostic,
15363        window: &mut Window,
15364        cx: &mut Context<Self>,
15365    ) {
15366        if !self.diagnostics_enabled() {
15367            return;
15368        }
15369        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15370        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15371    }
15372
15373    pub fn go_to_diagnostic_impl(
15374        &mut self,
15375        direction: Direction,
15376        severity: GoToDiagnosticSeverityFilter,
15377        window: &mut Window,
15378        cx: &mut Context<Self>,
15379    ) {
15380        let buffer = self.buffer.read(cx).snapshot(cx);
15381        let selection = self.selections.newest::<usize>(cx);
15382
15383        let mut active_group_id = None;
15384        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics {
15385            if active_group.active_range.start.to_offset(&buffer) == selection.start {
15386                active_group_id = Some(active_group.group_id);
15387            }
15388        }
15389
15390        fn filtered(
15391            snapshot: EditorSnapshot,
15392            severity: GoToDiagnosticSeverityFilter,
15393            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15394        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15395            diagnostics
15396                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15397                .filter(|entry| entry.range.start != entry.range.end)
15398                .filter(|entry| !entry.diagnostic.is_unnecessary)
15399                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15400        }
15401
15402        let snapshot = self.snapshot(window, cx);
15403        let before = filtered(
15404            snapshot.clone(),
15405            severity,
15406            buffer
15407                .diagnostics_in_range(0..selection.start)
15408                .filter(|entry| entry.range.start <= selection.start),
15409        );
15410        let after = filtered(
15411            snapshot,
15412            severity,
15413            buffer
15414                .diagnostics_in_range(selection.start..buffer.len())
15415                .filter(|entry| entry.range.start >= selection.start),
15416        );
15417
15418        let mut found: Option<DiagnosticEntry<usize>> = None;
15419        if direction == Direction::Prev {
15420            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15421            {
15422                for diagnostic in prev_diagnostics.into_iter().rev() {
15423                    if diagnostic.range.start != selection.start
15424                        || active_group_id
15425                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15426                    {
15427                        found = Some(diagnostic);
15428                        break 'outer;
15429                    }
15430                }
15431            }
15432        } else {
15433            for diagnostic in after.chain(before) {
15434                if diagnostic.range.start != selection.start
15435                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15436                {
15437                    found = Some(diagnostic);
15438                    break;
15439                }
15440            }
15441        }
15442        let Some(next_diagnostic) = found else {
15443            return;
15444        };
15445
15446        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15447            return;
15448        };
15449        self.change_selections(Default::default(), window, cx, |s| {
15450            s.select_ranges(vec![
15451                next_diagnostic.range.start..next_diagnostic.range.start,
15452            ])
15453        });
15454        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15455        self.refresh_edit_prediction(false, true, window, cx);
15456    }
15457
15458    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15459        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15460        let snapshot = self.snapshot(window, cx);
15461        let selection = self.selections.newest::<Point>(cx);
15462        self.go_to_hunk_before_or_after_position(
15463            &snapshot,
15464            selection.head(),
15465            Direction::Next,
15466            window,
15467            cx,
15468        );
15469    }
15470
15471    pub fn go_to_hunk_before_or_after_position(
15472        &mut self,
15473        snapshot: &EditorSnapshot,
15474        position: Point,
15475        direction: Direction,
15476        window: &mut Window,
15477        cx: &mut Context<Editor>,
15478    ) {
15479        let row = if direction == Direction::Next {
15480            self.hunk_after_position(snapshot, position)
15481                .map(|hunk| hunk.row_range.start)
15482        } else {
15483            self.hunk_before_position(snapshot, position)
15484        };
15485
15486        if let Some(row) = row {
15487            let destination = Point::new(row.0, 0);
15488            let autoscroll = Autoscroll::center();
15489
15490            self.unfold_ranges(&[destination..destination], false, false, cx);
15491            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15492                s.select_ranges([destination..destination]);
15493            });
15494        }
15495    }
15496
15497    fn hunk_after_position(
15498        &mut self,
15499        snapshot: &EditorSnapshot,
15500        position: Point,
15501    ) -> Option<MultiBufferDiffHunk> {
15502        snapshot
15503            .buffer_snapshot
15504            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15505            .find(|hunk| hunk.row_range.start.0 > position.row)
15506            .or_else(|| {
15507                snapshot
15508                    .buffer_snapshot
15509                    .diff_hunks_in_range(Point::zero()..position)
15510                    .find(|hunk| hunk.row_range.end.0 < position.row)
15511            })
15512    }
15513
15514    fn go_to_prev_hunk(
15515        &mut self,
15516        _: &GoToPreviousHunk,
15517        window: &mut Window,
15518        cx: &mut Context<Self>,
15519    ) {
15520        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15521        let snapshot = self.snapshot(window, cx);
15522        let selection = self.selections.newest::<Point>(cx);
15523        self.go_to_hunk_before_or_after_position(
15524            &snapshot,
15525            selection.head(),
15526            Direction::Prev,
15527            window,
15528            cx,
15529        );
15530    }
15531
15532    fn hunk_before_position(
15533        &mut self,
15534        snapshot: &EditorSnapshot,
15535        position: Point,
15536    ) -> Option<MultiBufferRow> {
15537        snapshot
15538            .buffer_snapshot
15539            .diff_hunk_before(position)
15540            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15541    }
15542
15543    fn go_to_next_change(
15544        &mut self,
15545        _: &GoToNextChange,
15546        window: &mut Window,
15547        cx: &mut Context<Self>,
15548    ) {
15549        if let Some(selections) = self
15550            .change_list
15551            .next_change(1, Direction::Next)
15552            .map(|s| s.to_vec())
15553        {
15554            self.change_selections(Default::default(), window, cx, |s| {
15555                let map = s.display_map();
15556                s.select_display_ranges(selections.iter().map(|a| {
15557                    let point = a.to_display_point(&map);
15558                    point..point
15559                }))
15560            })
15561        }
15562    }
15563
15564    fn go_to_previous_change(
15565        &mut self,
15566        _: &GoToPreviousChange,
15567        window: &mut Window,
15568        cx: &mut Context<Self>,
15569    ) {
15570        if let Some(selections) = self
15571            .change_list
15572            .next_change(1, Direction::Prev)
15573            .map(|s| s.to_vec())
15574        {
15575            self.change_selections(Default::default(), window, cx, |s| {
15576                let map = s.display_map();
15577                s.select_display_ranges(selections.iter().map(|a| {
15578                    let point = a.to_display_point(&map);
15579                    point..point
15580                }))
15581            })
15582        }
15583    }
15584
15585    fn go_to_line<T: 'static>(
15586        &mut self,
15587        position: Anchor,
15588        highlight_color: Option<Hsla>,
15589        window: &mut Window,
15590        cx: &mut Context<Self>,
15591    ) {
15592        let snapshot = self.snapshot(window, cx).display_snapshot;
15593        let position = position.to_point(&snapshot.buffer_snapshot);
15594        let start = snapshot
15595            .buffer_snapshot
15596            .clip_point(Point::new(position.row, 0), Bias::Left);
15597        let end = start + Point::new(1, 0);
15598        let start = snapshot.buffer_snapshot.anchor_before(start);
15599        let end = snapshot.buffer_snapshot.anchor_before(end);
15600
15601        self.highlight_rows::<T>(
15602            start..end,
15603            highlight_color
15604                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15605            Default::default(),
15606            cx,
15607        );
15608
15609        if self.buffer.read(cx).is_singleton() {
15610            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15611        }
15612    }
15613
15614    pub fn go_to_definition(
15615        &mut self,
15616        _: &GoToDefinition,
15617        window: &mut Window,
15618        cx: &mut Context<Self>,
15619    ) -> Task<Result<Navigated>> {
15620        let definition =
15621            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15622        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15623        cx.spawn_in(window, async move |editor, cx| {
15624            if definition.await? == Navigated::Yes {
15625                return Ok(Navigated::Yes);
15626            }
15627            match fallback_strategy {
15628                GoToDefinitionFallback::None => Ok(Navigated::No),
15629                GoToDefinitionFallback::FindAllReferences => {
15630                    match editor.update_in(cx, |editor, window, cx| {
15631                        editor.find_all_references(&FindAllReferences, window, cx)
15632                    })? {
15633                        Some(references) => references.await,
15634                        None => Ok(Navigated::No),
15635                    }
15636                }
15637            }
15638        })
15639    }
15640
15641    pub fn go_to_declaration(
15642        &mut self,
15643        _: &GoToDeclaration,
15644        window: &mut Window,
15645        cx: &mut Context<Self>,
15646    ) -> Task<Result<Navigated>> {
15647        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15648    }
15649
15650    pub fn go_to_declaration_split(
15651        &mut self,
15652        _: &GoToDeclaration,
15653        window: &mut Window,
15654        cx: &mut Context<Self>,
15655    ) -> Task<Result<Navigated>> {
15656        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15657    }
15658
15659    pub fn go_to_implementation(
15660        &mut self,
15661        _: &GoToImplementation,
15662        window: &mut Window,
15663        cx: &mut Context<Self>,
15664    ) -> Task<Result<Navigated>> {
15665        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15666    }
15667
15668    pub fn go_to_implementation_split(
15669        &mut self,
15670        _: &GoToImplementationSplit,
15671        window: &mut Window,
15672        cx: &mut Context<Self>,
15673    ) -> Task<Result<Navigated>> {
15674        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15675    }
15676
15677    pub fn go_to_type_definition(
15678        &mut self,
15679        _: &GoToTypeDefinition,
15680        window: &mut Window,
15681        cx: &mut Context<Self>,
15682    ) -> Task<Result<Navigated>> {
15683        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15684    }
15685
15686    pub fn go_to_definition_split(
15687        &mut self,
15688        _: &GoToDefinitionSplit,
15689        window: &mut Window,
15690        cx: &mut Context<Self>,
15691    ) -> Task<Result<Navigated>> {
15692        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15693    }
15694
15695    pub fn go_to_type_definition_split(
15696        &mut self,
15697        _: &GoToTypeDefinitionSplit,
15698        window: &mut Window,
15699        cx: &mut Context<Self>,
15700    ) -> Task<Result<Navigated>> {
15701        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15702    }
15703
15704    fn go_to_definition_of_kind(
15705        &mut self,
15706        kind: GotoDefinitionKind,
15707        split: bool,
15708        window: &mut Window,
15709        cx: &mut Context<Self>,
15710    ) -> Task<Result<Navigated>> {
15711        let Some(provider) = self.semantics_provider.clone() else {
15712            return Task::ready(Ok(Navigated::No));
15713        };
15714        let head = self.selections.newest::<usize>(cx).head();
15715        let buffer = self.buffer.read(cx);
15716        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
15717            return Task::ready(Ok(Navigated::No));
15718        };
15719        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15720            return Task::ready(Ok(Navigated::No));
15721        };
15722
15723        cx.spawn_in(window, async move |editor, cx| {
15724            let definitions = definitions.await?;
15725            let navigated = editor
15726                .update_in(cx, |editor, window, cx| {
15727                    editor.navigate_to_hover_links(
15728                        Some(kind),
15729                        definitions
15730                            .into_iter()
15731                            .filter(|location| {
15732                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15733                            })
15734                            .map(HoverLink::Text)
15735                            .collect::<Vec<_>>(),
15736                        split,
15737                        window,
15738                        cx,
15739                    )
15740                })?
15741                .await?;
15742            anyhow::Ok(navigated)
15743        })
15744    }
15745
15746    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15747        let selection = self.selections.newest_anchor();
15748        let head = selection.head();
15749        let tail = selection.tail();
15750
15751        let Some((buffer, start_position)) =
15752            self.buffer.read(cx).text_anchor_for_position(head, cx)
15753        else {
15754            return;
15755        };
15756
15757        let end_position = if head != tail {
15758            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15759                return;
15760            };
15761            Some(pos)
15762        } else {
15763            None
15764        };
15765
15766        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15767            let url = if let Some(end_pos) = end_position {
15768                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15769            } else {
15770                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15771            };
15772
15773            if let Some(url) = url {
15774                editor.update(cx, |_, cx| {
15775                    cx.open_url(&url);
15776                })
15777            } else {
15778                Ok(())
15779            }
15780        });
15781
15782        url_finder.detach();
15783    }
15784
15785    pub fn open_selected_filename(
15786        &mut self,
15787        _: &OpenSelectedFilename,
15788        window: &mut Window,
15789        cx: &mut Context<Self>,
15790    ) {
15791        let Some(workspace) = self.workspace() else {
15792            return;
15793        };
15794
15795        let position = self.selections.newest_anchor().head();
15796
15797        let Some((buffer, buffer_position)) =
15798            self.buffer.read(cx).text_anchor_for_position(position, cx)
15799        else {
15800            return;
15801        };
15802
15803        let project = self.project.clone();
15804
15805        cx.spawn_in(window, async move |_, cx| {
15806            let result = find_file(&buffer, project, buffer_position, cx).await;
15807
15808            if let Some((_, path)) = result {
15809                workspace
15810                    .update_in(cx, |workspace, window, cx| {
15811                        workspace.open_resolved_path(path, window, cx)
15812                    })?
15813                    .await?;
15814            }
15815            anyhow::Ok(())
15816        })
15817        .detach();
15818    }
15819
15820    pub(crate) fn navigate_to_hover_links(
15821        &mut self,
15822        kind: Option<GotoDefinitionKind>,
15823        definitions: Vec<HoverLink>,
15824        split: bool,
15825        window: &mut Window,
15826        cx: &mut Context<Editor>,
15827    ) -> Task<Result<Navigated>> {
15828        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
15829        let mut first_url_or_file = None;
15830        let definitions: Vec<_> = definitions
15831            .into_iter()
15832            .filter_map(|def| match def {
15833                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
15834                HoverLink::InlayHint(lsp_location, server_id) => {
15835                    let computation =
15836                        self.compute_target_location(lsp_location, server_id, window, cx);
15837                    Some(cx.background_spawn(computation))
15838                }
15839                HoverLink::Url(url) => {
15840                    first_url_or_file = Some(Either::Left(url));
15841                    None
15842                }
15843                HoverLink::File(path) => {
15844                    first_url_or_file = Some(Either::Right(path));
15845                    None
15846                }
15847            })
15848            .collect();
15849
15850        let workspace = self.workspace();
15851
15852        cx.spawn_in(window, async move |editor, acx| {
15853            let mut locations: Vec<Location> = future::join_all(definitions)
15854                .await
15855                .into_iter()
15856                .filter_map(|location| location.transpose())
15857                .collect::<Result<_>>()
15858                .context("location tasks")?;
15859
15860            if locations.len() > 1 {
15861                let Some(workspace) = workspace else {
15862                    return Ok(Navigated::No);
15863                };
15864
15865                let tab_kind = match kind {
15866                    Some(GotoDefinitionKind::Implementation) => "Implementations",
15867                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
15868                    Some(GotoDefinitionKind::Declaration) => "Declarations",
15869                    Some(GotoDefinitionKind::Type) => "Types",
15870                };
15871                let title = editor
15872                    .update_in(acx, |_, _, cx| {
15873                        let target = locations
15874                            .iter()
15875                            .map(|location| {
15876                                location
15877                                    .buffer
15878                                    .read(cx)
15879                                    .text_for_range(location.range.clone())
15880                                    .collect::<String>()
15881                            })
15882                            .unique()
15883                            .take(3)
15884                            .join(", ");
15885                        format!("{tab_kind} for {target}")
15886                    })
15887                    .context("buffer title")?;
15888
15889                let opened = workspace
15890                    .update_in(acx, |workspace, window, cx| {
15891                        Self::open_locations_in_multibuffer(
15892                            workspace,
15893                            locations,
15894                            title,
15895                            split,
15896                            MultibufferSelectionMode::First,
15897                            window,
15898                            cx,
15899                        )
15900                    })
15901                    .is_ok();
15902
15903                anyhow::Ok(Navigated::from_bool(opened))
15904            } else if locations.is_empty() {
15905                // If there is one definition, just open it directly
15906                match first_url_or_file {
15907                    Some(Either::Left(url)) => {
15908                        acx.update(|_, cx| cx.open_url(&url))?;
15909                        Ok(Navigated::Yes)
15910                    }
15911                    Some(Either::Right(path)) => {
15912                        let Some(workspace) = workspace else {
15913                            return Ok(Navigated::No);
15914                        };
15915
15916                        workspace
15917                            .update_in(acx, |workspace, window, cx| {
15918                                workspace.open_resolved_path(path, window, cx)
15919                            })?
15920                            .await?;
15921                        Ok(Navigated::Yes)
15922                    }
15923                    None => Ok(Navigated::No),
15924                }
15925            } else {
15926                let Some(workspace) = workspace else {
15927                    return Ok(Navigated::No);
15928                };
15929
15930                let target = locations.pop().unwrap();
15931                editor.update_in(acx, |editor, window, cx| {
15932                    let pane = workspace.read(cx).active_pane().clone();
15933
15934                    let range = target.range.to_point(target.buffer.read(cx));
15935                    let range = editor.range_for_match(&range);
15936                    let range = collapse_multiline_range(range);
15937
15938                    if !split
15939                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15940                    {
15941                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15942                    } else {
15943                        window.defer(cx, move |window, cx| {
15944                            let target_editor: Entity<Self> =
15945                                workspace.update(cx, |workspace, cx| {
15946                                    let pane = if split {
15947                                        workspace.adjacent_pane(window, cx)
15948                                    } else {
15949                                        workspace.active_pane().clone()
15950                                    };
15951
15952                                    workspace.open_project_item(
15953                                        pane,
15954                                        target.buffer.clone(),
15955                                        true,
15956                                        true,
15957                                        window,
15958                                        cx,
15959                                    )
15960                                });
15961                            target_editor.update(cx, |target_editor, cx| {
15962                                // When selecting a definition in a different buffer, disable the nav history
15963                                // to avoid creating a history entry at the previous cursor location.
15964                                pane.update(cx, |pane, _| pane.disable_history());
15965                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15966                                pane.update(cx, |pane, _| pane.enable_history());
15967                            });
15968                        });
15969                    }
15970                    Navigated::Yes
15971                })
15972            }
15973        })
15974    }
15975
15976    fn compute_target_location(
15977        &self,
15978        lsp_location: lsp::Location,
15979        server_id: LanguageServerId,
15980        window: &mut Window,
15981        cx: &mut Context<Self>,
15982    ) -> Task<anyhow::Result<Option<Location>>> {
15983        let Some(project) = self.project.clone() else {
15984            return Task::ready(Ok(None));
15985        };
15986
15987        cx.spawn_in(window, async move |editor, cx| {
15988            let location_task = editor.update(cx, |_, cx| {
15989                project.update(cx, |project, cx| {
15990                    let language_server_name = project
15991                        .language_server_statuses(cx)
15992                        .find(|(id, _)| server_id == *id)
15993                        .map(|(_, status)| status.name.clone());
15994                    language_server_name.map(|language_server_name| {
15995                        project.open_local_buffer_via_lsp(
15996                            lsp_location.uri.clone(),
15997                            server_id,
15998                            language_server_name,
15999                            cx,
16000                        )
16001                    })
16002                })
16003            })?;
16004            let location = match location_task {
16005                Some(task) => Some({
16006                    let target_buffer_handle = task.await.context("open local buffer")?;
16007                    let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16008                        let target_start = target_buffer
16009                            .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16010                        let target_end = target_buffer
16011                            .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16012                        target_buffer.anchor_after(target_start)
16013                            ..target_buffer.anchor_before(target_end)
16014                    })?;
16015                    Location {
16016                        buffer: target_buffer_handle,
16017                        range,
16018                    }
16019                }),
16020                None => None,
16021            };
16022            Ok(location)
16023        })
16024    }
16025
16026    pub fn find_all_references(
16027        &mut self,
16028        _: &FindAllReferences,
16029        window: &mut Window,
16030        cx: &mut Context<Self>,
16031    ) -> Option<Task<Result<Navigated>>> {
16032        let selection = self.selections.newest::<usize>(cx);
16033        let multi_buffer = self.buffer.read(cx);
16034        let head = selection.head();
16035
16036        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16037        let head_anchor = multi_buffer_snapshot.anchor_at(
16038            head,
16039            if head < selection.tail() {
16040                Bias::Right
16041            } else {
16042                Bias::Left
16043            },
16044        );
16045
16046        match self
16047            .find_all_references_task_sources
16048            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16049        {
16050            Ok(_) => {
16051                log::info!(
16052                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16053                );
16054                return None;
16055            }
16056            Err(i) => {
16057                self.find_all_references_task_sources.insert(i, head_anchor);
16058            }
16059        }
16060
16061        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16062        let workspace = self.workspace()?;
16063        let project = workspace.read(cx).project().clone();
16064        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16065        Some(cx.spawn_in(window, async move |editor, cx| {
16066            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16067                if let Ok(i) = editor
16068                    .find_all_references_task_sources
16069                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16070                {
16071                    editor.find_all_references_task_sources.remove(i);
16072                }
16073            });
16074
16075            let locations = references.await?;
16076            if locations.is_empty() {
16077                return anyhow::Ok(Navigated::No);
16078            }
16079
16080            workspace.update_in(cx, |workspace, window, cx| {
16081                let target = locations
16082                    .iter()
16083                    .map(|location| {
16084                        location
16085                            .buffer
16086                            .read(cx)
16087                            .text_for_range(location.range.clone())
16088                            .collect::<String>()
16089                    })
16090                    .unique()
16091                    .take(3)
16092                    .join(", ");
16093                let title = format!("References to {target}");
16094                Self::open_locations_in_multibuffer(
16095                    workspace,
16096                    locations,
16097                    title,
16098                    false,
16099                    MultibufferSelectionMode::First,
16100                    window,
16101                    cx,
16102                );
16103                Navigated::Yes
16104            })
16105        }))
16106    }
16107
16108    /// Opens a multibuffer with the given project locations in it
16109    pub fn open_locations_in_multibuffer(
16110        workspace: &mut Workspace,
16111        mut locations: Vec<Location>,
16112        title: String,
16113        split: bool,
16114        multibuffer_selection_mode: MultibufferSelectionMode,
16115        window: &mut Window,
16116        cx: &mut Context<Workspace>,
16117    ) {
16118        if locations.is_empty() {
16119            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16120            return;
16121        }
16122
16123        // If there are multiple definitions, open them in a multibuffer
16124        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16125        let mut locations = locations.into_iter().peekable();
16126        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16127        let capability = workspace.project().read(cx).capability();
16128
16129        let excerpt_buffer = cx.new(|cx| {
16130            let mut multibuffer = MultiBuffer::new(capability);
16131            while let Some(location) = locations.next() {
16132                let buffer = location.buffer.read(cx);
16133                let mut ranges_for_buffer = Vec::new();
16134                let range = location.range.to_point(buffer);
16135                ranges_for_buffer.push(range.clone());
16136
16137                while let Some(next_location) = locations.peek() {
16138                    if next_location.buffer == location.buffer {
16139                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16140                        locations.next();
16141                    } else {
16142                        break;
16143                    }
16144                }
16145
16146                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16147                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16148                    PathKey::for_buffer(&location.buffer, cx),
16149                    location.buffer.clone(),
16150                    ranges_for_buffer,
16151                    DEFAULT_MULTIBUFFER_CONTEXT,
16152                    cx,
16153                );
16154                ranges.extend(new_ranges)
16155            }
16156
16157            multibuffer.with_title(title)
16158        });
16159
16160        let editor = cx.new(|cx| {
16161            Editor::for_multibuffer(
16162                excerpt_buffer,
16163                Some(workspace.project().clone()),
16164                window,
16165                cx,
16166            )
16167        });
16168        editor.update(cx, |editor, cx| {
16169            match multibuffer_selection_mode {
16170                MultibufferSelectionMode::First => {
16171                    if let Some(first_range) = ranges.first() {
16172                        editor.change_selections(
16173                            SelectionEffects::no_scroll(),
16174                            window,
16175                            cx,
16176                            |selections| {
16177                                selections.clear_disjoint();
16178                                selections
16179                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16180                            },
16181                        );
16182                    }
16183                    editor.highlight_background::<Self>(
16184                        &ranges,
16185                        |theme| theme.colors().editor_highlighted_line_background,
16186                        cx,
16187                    );
16188                }
16189                MultibufferSelectionMode::All => {
16190                    editor.change_selections(
16191                        SelectionEffects::no_scroll(),
16192                        window,
16193                        cx,
16194                        |selections| {
16195                            selections.clear_disjoint();
16196                            selections.select_anchor_ranges(ranges);
16197                        },
16198                    );
16199                }
16200            }
16201            editor.register_buffers_with_language_servers(cx);
16202        });
16203
16204        let item = Box::new(editor);
16205        let item_id = item.item_id();
16206
16207        if split {
16208            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
16209        } else {
16210            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16211                let (preview_item_id, preview_item_idx) =
16212                    workspace.active_pane().read_with(cx, |pane, _| {
16213                        (pane.preview_item_id(), pane.preview_item_idx())
16214                    });
16215
16216                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
16217
16218                if let Some(preview_item_id) = preview_item_id {
16219                    workspace.active_pane().update(cx, |pane, cx| {
16220                        pane.remove_item(preview_item_id, false, false, window, cx);
16221                    });
16222                }
16223            } else {
16224                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
16225            }
16226        }
16227        workspace.active_pane().update(cx, |pane, cx| {
16228            pane.set_preview_item_id(Some(item_id), cx);
16229        });
16230    }
16231
16232    pub fn rename(
16233        &mut self,
16234        _: &Rename,
16235        window: &mut Window,
16236        cx: &mut Context<Self>,
16237    ) -> Option<Task<Result<()>>> {
16238        use language::ToOffset as _;
16239
16240        let provider = self.semantics_provider.clone()?;
16241        let selection = self.selections.newest_anchor().clone();
16242        let (cursor_buffer, cursor_buffer_position) = self
16243            .buffer
16244            .read(cx)
16245            .text_anchor_for_position(selection.head(), cx)?;
16246        let (tail_buffer, cursor_buffer_position_end) = self
16247            .buffer
16248            .read(cx)
16249            .text_anchor_for_position(selection.tail(), cx)?;
16250        if tail_buffer != cursor_buffer {
16251            return None;
16252        }
16253
16254        let snapshot = cursor_buffer.read(cx).snapshot();
16255        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16256        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16257        let prepare_rename = provider
16258            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16259            .unwrap_or_else(|| Task::ready(Ok(None)));
16260        drop(snapshot);
16261
16262        Some(cx.spawn_in(window, async move |this, cx| {
16263            let rename_range = if let Some(range) = prepare_rename.await? {
16264                Some(range)
16265            } else {
16266                this.update(cx, |this, cx| {
16267                    let buffer = this.buffer.read(cx).snapshot(cx);
16268                    let mut buffer_highlights = this
16269                        .document_highlights_for_position(selection.head(), &buffer)
16270                        .filter(|highlight| {
16271                            highlight.start.excerpt_id == selection.head().excerpt_id
16272                                && highlight.end.excerpt_id == selection.head().excerpt_id
16273                        });
16274                    buffer_highlights
16275                        .next()
16276                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16277                })?
16278            };
16279            if let Some(rename_range) = rename_range {
16280                this.update_in(cx, |this, window, cx| {
16281                    let snapshot = cursor_buffer.read(cx).snapshot();
16282                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16283                    let cursor_offset_in_rename_range =
16284                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16285                    let cursor_offset_in_rename_range_end =
16286                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16287
16288                    this.take_rename(false, window, cx);
16289                    let buffer = this.buffer.read(cx).read(cx);
16290                    let cursor_offset = selection.head().to_offset(&buffer);
16291                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16292                    let rename_end = rename_start + rename_buffer_range.len();
16293                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16294                    let mut old_highlight_id = None;
16295                    let old_name: Arc<str> = buffer
16296                        .chunks(rename_start..rename_end, true)
16297                        .map(|chunk| {
16298                            if old_highlight_id.is_none() {
16299                                old_highlight_id = chunk.syntax_highlight_id;
16300                            }
16301                            chunk.text
16302                        })
16303                        .collect::<String>()
16304                        .into();
16305
16306                    drop(buffer);
16307
16308                    // Position the selection in the rename editor so that it matches the current selection.
16309                    this.show_local_selections = false;
16310                    let rename_editor = cx.new(|cx| {
16311                        let mut editor = Editor::single_line(window, cx);
16312                        editor.buffer.update(cx, |buffer, cx| {
16313                            buffer.edit([(0..0, old_name.clone())], None, cx)
16314                        });
16315                        let rename_selection_range = match cursor_offset_in_rename_range
16316                            .cmp(&cursor_offset_in_rename_range_end)
16317                        {
16318                            Ordering::Equal => {
16319                                editor.select_all(&SelectAll, window, cx);
16320                                return editor;
16321                            }
16322                            Ordering::Less => {
16323                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16324                            }
16325                            Ordering::Greater => {
16326                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16327                            }
16328                        };
16329                        if rename_selection_range.end > old_name.len() {
16330                            editor.select_all(&SelectAll, window, cx);
16331                        } else {
16332                            editor.change_selections(Default::default(), window, cx, |s| {
16333                                s.select_ranges([rename_selection_range]);
16334                            });
16335                        }
16336                        editor
16337                    });
16338                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16339                        if e == &EditorEvent::Focused {
16340                            cx.emit(EditorEvent::FocusedIn)
16341                        }
16342                    })
16343                    .detach();
16344
16345                    let write_highlights =
16346                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16347                    let read_highlights =
16348                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16349                    let ranges = write_highlights
16350                        .iter()
16351                        .flat_map(|(_, ranges)| ranges.iter())
16352                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16353                        .cloned()
16354                        .collect();
16355
16356                    this.highlight_text::<Rename>(
16357                        ranges,
16358                        HighlightStyle {
16359                            fade_out: Some(0.6),
16360                            ..Default::default()
16361                        },
16362                        cx,
16363                    );
16364                    let rename_focus_handle = rename_editor.focus_handle(cx);
16365                    window.focus(&rename_focus_handle);
16366                    let block_id = this.insert_blocks(
16367                        [BlockProperties {
16368                            style: BlockStyle::Flex,
16369                            placement: BlockPlacement::Below(range.start),
16370                            height: Some(1),
16371                            render: Arc::new({
16372                                let rename_editor = rename_editor.clone();
16373                                move |cx: &mut BlockContext| {
16374                                    let mut text_style = cx.editor_style.text.clone();
16375                                    if let Some(highlight_style) = old_highlight_id
16376                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16377                                    {
16378                                        text_style = text_style.highlight(highlight_style);
16379                                    }
16380                                    div()
16381                                        .block_mouse_except_scroll()
16382                                        .pl(cx.anchor_x)
16383                                        .child(EditorElement::new(
16384                                            &rename_editor,
16385                                            EditorStyle {
16386                                                background: cx.theme().system().transparent,
16387                                                local_player: cx.editor_style.local_player,
16388                                                text: text_style,
16389                                                scrollbar_width: cx.editor_style.scrollbar_width,
16390                                                syntax: cx.editor_style.syntax.clone(),
16391                                                status: cx.editor_style.status.clone(),
16392                                                inlay_hints_style: HighlightStyle {
16393                                                    font_weight: Some(FontWeight::BOLD),
16394                                                    ..make_inlay_hints_style(cx.app)
16395                                                },
16396                                                edit_prediction_styles: make_suggestion_styles(
16397                                                    cx.app,
16398                                                ),
16399                                                ..EditorStyle::default()
16400                                            },
16401                                        ))
16402                                        .into_any_element()
16403                                }
16404                            }),
16405                            priority: 0,
16406                        }],
16407                        Some(Autoscroll::fit()),
16408                        cx,
16409                    )[0];
16410                    this.pending_rename = Some(RenameState {
16411                        range,
16412                        old_name,
16413                        editor: rename_editor,
16414                        block_id,
16415                    });
16416                })?;
16417            }
16418
16419            Ok(())
16420        }))
16421    }
16422
16423    pub fn confirm_rename(
16424        &mut self,
16425        _: &ConfirmRename,
16426        window: &mut Window,
16427        cx: &mut Context<Self>,
16428    ) -> Option<Task<Result<()>>> {
16429        let rename = self.take_rename(false, window, cx)?;
16430        let workspace = self.workspace()?.downgrade();
16431        let (buffer, start) = self
16432            .buffer
16433            .read(cx)
16434            .text_anchor_for_position(rename.range.start, cx)?;
16435        let (end_buffer, _) = self
16436            .buffer
16437            .read(cx)
16438            .text_anchor_for_position(rename.range.end, cx)?;
16439        if buffer != end_buffer {
16440            return None;
16441        }
16442
16443        let old_name = rename.old_name;
16444        let new_name = rename.editor.read(cx).text(cx);
16445
16446        let rename = self.semantics_provider.as_ref()?.perform_rename(
16447            &buffer,
16448            start,
16449            new_name.clone(),
16450            cx,
16451        )?;
16452
16453        Some(cx.spawn_in(window, async move |editor, cx| {
16454            let project_transaction = rename.await?;
16455            Self::open_project_transaction(
16456                &editor,
16457                workspace,
16458                project_transaction,
16459                format!("Rename: {}{}", old_name, new_name),
16460                cx,
16461            )
16462            .await?;
16463
16464            editor.update(cx, |editor, cx| {
16465                editor.refresh_document_highlights(cx);
16466            })?;
16467            Ok(())
16468        }))
16469    }
16470
16471    fn take_rename(
16472        &mut self,
16473        moving_cursor: bool,
16474        window: &mut Window,
16475        cx: &mut Context<Self>,
16476    ) -> Option<RenameState> {
16477        let rename = self.pending_rename.take()?;
16478        if rename.editor.focus_handle(cx).is_focused(window) {
16479            window.focus(&self.focus_handle);
16480        }
16481
16482        self.remove_blocks(
16483            [rename.block_id].into_iter().collect(),
16484            Some(Autoscroll::fit()),
16485            cx,
16486        );
16487        self.clear_highlights::<Rename>(cx);
16488        self.show_local_selections = true;
16489
16490        if moving_cursor {
16491            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16492                editor.selections.newest::<usize>(cx).head()
16493            });
16494
16495            // Update the selection to match the position of the selection inside
16496            // the rename editor.
16497            let snapshot = self.buffer.read(cx).read(cx);
16498            let rename_range = rename.range.to_offset(&snapshot);
16499            let cursor_in_editor = snapshot
16500                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16501                .min(rename_range.end);
16502            drop(snapshot);
16503
16504            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16505                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16506            });
16507        } else {
16508            self.refresh_document_highlights(cx);
16509        }
16510
16511        Some(rename)
16512    }
16513
16514    pub fn pending_rename(&self) -> Option<&RenameState> {
16515        self.pending_rename.as_ref()
16516    }
16517
16518    fn format(
16519        &mut self,
16520        _: &Format,
16521        window: &mut Window,
16522        cx: &mut Context<Self>,
16523    ) -> Option<Task<Result<()>>> {
16524        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16525
16526        let project = match &self.project {
16527            Some(project) => project.clone(),
16528            None => return None,
16529        };
16530
16531        Some(self.perform_format(
16532            project,
16533            FormatTrigger::Manual,
16534            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16535            window,
16536            cx,
16537        ))
16538    }
16539
16540    fn format_selections(
16541        &mut self,
16542        _: &FormatSelections,
16543        window: &mut Window,
16544        cx: &mut Context<Self>,
16545    ) -> Option<Task<Result<()>>> {
16546        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16547
16548        let project = match &self.project {
16549            Some(project) => project.clone(),
16550            None => return None,
16551        };
16552
16553        let ranges = self
16554            .selections
16555            .all_adjusted(cx)
16556            .into_iter()
16557            .map(|selection| selection.range())
16558            .collect_vec();
16559
16560        Some(self.perform_format(
16561            project,
16562            FormatTrigger::Manual,
16563            FormatTarget::Ranges(ranges),
16564            window,
16565            cx,
16566        ))
16567    }
16568
16569    fn perform_format(
16570        &mut self,
16571        project: Entity<Project>,
16572        trigger: FormatTrigger,
16573        target: FormatTarget,
16574        window: &mut Window,
16575        cx: &mut Context<Self>,
16576    ) -> Task<Result<()>> {
16577        let buffer = self.buffer.clone();
16578        let (buffers, target) = match target {
16579            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16580            FormatTarget::Ranges(selection_ranges) => {
16581                let multi_buffer = buffer.read(cx);
16582                let snapshot = multi_buffer.read(cx);
16583                let mut buffers = HashSet::default();
16584                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16585                    BTreeMap::new();
16586                for selection_range in selection_ranges {
16587                    for (buffer, buffer_range, _) in
16588                        snapshot.range_to_buffer_ranges(selection_range)
16589                    {
16590                        let buffer_id = buffer.remote_id();
16591                        let start = buffer.anchor_before(buffer_range.start);
16592                        let end = buffer.anchor_after(buffer_range.end);
16593                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16594                        buffer_id_to_ranges
16595                            .entry(buffer_id)
16596                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16597                            .or_insert_with(|| vec![start..end]);
16598                    }
16599                }
16600                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16601            }
16602        };
16603
16604        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16605        let selections_prev = transaction_id_prev
16606            .and_then(|transaction_id_prev| {
16607                // default to selections as they were after the last edit, if we have them,
16608                // instead of how they are now.
16609                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16610                // will take you back to where you made the last edit, instead of staying where you scrolled
16611                self.selection_history
16612                    .transaction(transaction_id_prev)
16613                    .map(|t| t.0.clone())
16614            })
16615            .unwrap_or_else(|| {
16616                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16617                self.selections.disjoint_anchors()
16618            });
16619
16620        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16621        let format = project.update(cx, |project, cx| {
16622            project.format(buffers, target, true, trigger, cx)
16623        });
16624
16625        cx.spawn_in(window, async move |editor, cx| {
16626            let transaction = futures::select_biased! {
16627                transaction = format.log_err().fuse() => transaction,
16628                () = timeout => {
16629                    log::warn!("timed out waiting for formatting");
16630                    None
16631                }
16632            };
16633
16634            buffer
16635                .update(cx, |buffer, cx| {
16636                    if let Some(transaction) = transaction {
16637                        if !buffer.is_singleton() {
16638                            buffer.push_transaction(&transaction.0, cx);
16639                        }
16640                    }
16641                    cx.notify();
16642                })
16643                .ok();
16644
16645            if let Some(transaction_id_now) =
16646                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16647            {
16648                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16649                if has_new_transaction {
16650                    _ = editor.update(cx, |editor, _| {
16651                        editor
16652                            .selection_history
16653                            .insert_transaction(transaction_id_now, selections_prev);
16654                    });
16655                }
16656            }
16657
16658            Ok(())
16659        })
16660    }
16661
16662    fn organize_imports(
16663        &mut self,
16664        _: &OrganizeImports,
16665        window: &mut Window,
16666        cx: &mut Context<Self>,
16667    ) -> Option<Task<Result<()>>> {
16668        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16669        let project = match &self.project {
16670            Some(project) => project.clone(),
16671            None => return None,
16672        };
16673        Some(self.perform_code_action_kind(
16674            project,
16675            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16676            window,
16677            cx,
16678        ))
16679    }
16680
16681    fn perform_code_action_kind(
16682        &mut self,
16683        project: Entity<Project>,
16684        kind: CodeActionKind,
16685        window: &mut Window,
16686        cx: &mut Context<Self>,
16687    ) -> Task<Result<()>> {
16688        let buffer = self.buffer.clone();
16689        let buffers = buffer.read(cx).all_buffers();
16690        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16691        let apply_action = project.update(cx, |project, cx| {
16692            project.apply_code_action_kind(buffers, kind, true, cx)
16693        });
16694        cx.spawn_in(window, async move |_, cx| {
16695            let transaction = futures::select_biased! {
16696                () = timeout => {
16697                    log::warn!("timed out waiting for executing code action");
16698                    None
16699                }
16700                transaction = apply_action.log_err().fuse() => transaction,
16701            };
16702            buffer
16703                .update(cx, |buffer, cx| {
16704                    // check if we need this
16705                    if let Some(transaction) = transaction {
16706                        if !buffer.is_singleton() {
16707                            buffer.push_transaction(&transaction.0, cx);
16708                        }
16709                    }
16710                    cx.notify();
16711                })
16712                .ok();
16713            Ok(())
16714        })
16715    }
16716
16717    pub fn restart_language_server(
16718        &mut self,
16719        _: &RestartLanguageServer,
16720        _: &mut Window,
16721        cx: &mut Context<Self>,
16722    ) {
16723        if let Some(project) = self.project.clone() {
16724            self.buffer.update(cx, |multi_buffer, cx| {
16725                project.update(cx, |project, cx| {
16726                    project.restart_language_servers_for_buffers(
16727                        multi_buffer.all_buffers().into_iter().collect(),
16728                        HashSet::default(),
16729                        cx,
16730                    );
16731                });
16732            })
16733        }
16734    }
16735
16736    pub fn stop_language_server(
16737        &mut self,
16738        _: &StopLanguageServer,
16739        _: &mut Window,
16740        cx: &mut Context<Self>,
16741    ) {
16742        if let Some(project) = self.project.clone() {
16743            self.buffer.update(cx, |multi_buffer, cx| {
16744                project.update(cx, |project, cx| {
16745                    project.stop_language_servers_for_buffers(
16746                        multi_buffer.all_buffers().into_iter().collect(),
16747                        HashSet::default(),
16748                        cx,
16749                    );
16750                    cx.emit(project::Event::RefreshInlayHints);
16751                });
16752            });
16753        }
16754    }
16755
16756    fn cancel_language_server_work(
16757        workspace: &mut Workspace,
16758        _: &actions::CancelLanguageServerWork,
16759        _: &mut Window,
16760        cx: &mut Context<Workspace>,
16761    ) {
16762        let project = workspace.project();
16763        let buffers = workspace
16764            .active_item(cx)
16765            .and_then(|item| item.act_as::<Editor>(cx))
16766            .map_or(HashSet::default(), |editor| {
16767                editor.read(cx).buffer.read(cx).all_buffers()
16768            });
16769        project.update(cx, |project, cx| {
16770            project.cancel_language_server_work_for_buffers(buffers, cx);
16771        });
16772    }
16773
16774    fn show_character_palette(
16775        &mut self,
16776        _: &ShowCharacterPalette,
16777        window: &mut Window,
16778        _: &mut Context<Self>,
16779    ) {
16780        window.show_character_palette();
16781    }
16782
16783    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16784        if !self.diagnostics_enabled() {
16785            return;
16786        }
16787
16788        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16789            let buffer = self.buffer.read(cx).snapshot(cx);
16790            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16791            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16792            let is_valid = buffer
16793                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16794                .any(|entry| {
16795                    entry.diagnostic.is_primary
16796                        && !entry.range.is_empty()
16797                        && entry.range.start == primary_range_start
16798                        && entry.diagnostic.message == active_diagnostics.active_message
16799                });
16800
16801            if !is_valid {
16802                self.dismiss_diagnostics(cx);
16803            }
16804        }
16805    }
16806
16807    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16808        match &self.active_diagnostics {
16809            ActiveDiagnostic::Group(group) => Some(group),
16810            _ => None,
16811        }
16812    }
16813
16814    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16815        if !self.diagnostics_enabled() {
16816            return;
16817        }
16818        self.dismiss_diagnostics(cx);
16819        self.active_diagnostics = ActiveDiagnostic::All;
16820    }
16821
16822    fn activate_diagnostics(
16823        &mut self,
16824        buffer_id: BufferId,
16825        diagnostic: DiagnosticEntry<usize>,
16826        window: &mut Window,
16827        cx: &mut Context<Self>,
16828    ) {
16829        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16830            return;
16831        }
16832        self.dismiss_diagnostics(cx);
16833        let snapshot = self.snapshot(window, cx);
16834        let buffer = self.buffer.read(cx).snapshot(cx);
16835        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16836            return;
16837        };
16838
16839        let diagnostic_group = buffer
16840            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16841            .collect::<Vec<_>>();
16842
16843        let blocks =
16844            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16845
16846        let blocks = self.display_map.update(cx, |display_map, cx| {
16847            display_map.insert_blocks(blocks, cx).into_iter().collect()
16848        });
16849        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16850            active_range: buffer.anchor_before(diagnostic.range.start)
16851                ..buffer.anchor_after(diagnostic.range.end),
16852            active_message: diagnostic.diagnostic.message.clone(),
16853            group_id: diagnostic.diagnostic.group_id,
16854            blocks,
16855        });
16856        cx.notify();
16857    }
16858
16859    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16860        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16861            return;
16862        };
16863
16864        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16865        if let ActiveDiagnostic::Group(group) = prev {
16866            self.display_map.update(cx, |display_map, cx| {
16867                display_map.remove_blocks(group.blocks, cx);
16868            });
16869            cx.notify();
16870        }
16871    }
16872
16873    /// Disable inline diagnostics rendering for this editor.
16874    pub fn disable_inline_diagnostics(&mut self) {
16875        self.inline_diagnostics_enabled = false;
16876        self.inline_diagnostics_update = Task::ready(());
16877        self.inline_diagnostics.clear();
16878    }
16879
16880    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16881        self.diagnostics_enabled = false;
16882        self.dismiss_diagnostics(cx);
16883        self.inline_diagnostics_update = Task::ready(());
16884        self.inline_diagnostics.clear();
16885    }
16886
16887    pub fn diagnostics_enabled(&self) -> bool {
16888        self.diagnostics_enabled && self.mode.is_full()
16889    }
16890
16891    pub fn inline_diagnostics_enabled(&self) -> bool {
16892        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16893    }
16894
16895    pub fn show_inline_diagnostics(&self) -> bool {
16896        self.show_inline_diagnostics
16897    }
16898
16899    pub fn toggle_inline_diagnostics(
16900        &mut self,
16901        _: &ToggleInlineDiagnostics,
16902        window: &mut Window,
16903        cx: &mut Context<Editor>,
16904    ) {
16905        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16906        self.refresh_inline_diagnostics(false, window, cx);
16907    }
16908
16909    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16910        self.diagnostics_max_severity = severity;
16911        self.display_map.update(cx, |display_map, _| {
16912            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16913        });
16914    }
16915
16916    pub fn toggle_diagnostics(
16917        &mut self,
16918        _: &ToggleDiagnostics,
16919        window: &mut Window,
16920        cx: &mut Context<Editor>,
16921    ) {
16922        if !self.diagnostics_enabled() {
16923            return;
16924        }
16925
16926        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16927            EditorSettings::get_global(cx)
16928                .diagnostics_max_severity
16929                .filter(|severity| severity != &DiagnosticSeverity::Off)
16930                .unwrap_or(DiagnosticSeverity::Hint)
16931        } else {
16932            DiagnosticSeverity::Off
16933        };
16934        self.set_max_diagnostics_severity(new_severity, cx);
16935        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16936            self.active_diagnostics = ActiveDiagnostic::None;
16937            self.inline_diagnostics_update = Task::ready(());
16938            self.inline_diagnostics.clear();
16939        } else {
16940            self.refresh_inline_diagnostics(false, window, cx);
16941        }
16942
16943        cx.notify();
16944    }
16945
16946    pub fn toggle_minimap(
16947        &mut self,
16948        _: &ToggleMinimap,
16949        window: &mut Window,
16950        cx: &mut Context<Editor>,
16951    ) {
16952        if self.supports_minimap(cx) {
16953            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16954        }
16955    }
16956
16957    fn refresh_inline_diagnostics(
16958        &mut self,
16959        debounce: bool,
16960        window: &mut Window,
16961        cx: &mut Context<Self>,
16962    ) {
16963        let max_severity = ProjectSettings::get_global(cx)
16964            .diagnostics
16965            .inline
16966            .max_severity
16967            .unwrap_or(self.diagnostics_max_severity);
16968
16969        if !self.inline_diagnostics_enabled()
16970            || !self.show_inline_diagnostics
16971            || max_severity == DiagnosticSeverity::Off
16972        {
16973            self.inline_diagnostics_update = Task::ready(());
16974            self.inline_diagnostics.clear();
16975            return;
16976        }
16977
16978        let debounce_ms = ProjectSettings::get_global(cx)
16979            .diagnostics
16980            .inline
16981            .update_debounce_ms;
16982        let debounce = if debounce && debounce_ms > 0 {
16983            Some(Duration::from_millis(debounce_ms))
16984        } else {
16985            None
16986        };
16987        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
16988            if let Some(debounce) = debounce {
16989                cx.background_executor().timer(debounce).await;
16990            }
16991            let Some(snapshot) = editor.upgrade().and_then(|editor| {
16992                editor
16993                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
16994                    .ok()
16995            }) else {
16996                return;
16997            };
16998
16999            let new_inline_diagnostics = cx
17000                .background_spawn(async move {
17001                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17002                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17003                        let message = diagnostic_entry
17004                            .diagnostic
17005                            .message
17006                            .split_once('\n')
17007                            .map(|(line, _)| line)
17008                            .map(SharedString::new)
17009                            .unwrap_or_else(|| {
17010                                SharedString::from(diagnostic_entry.diagnostic.message)
17011                            });
17012                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17013                        let (Ok(i) | Err(i)) = inline_diagnostics
17014                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17015                        inline_diagnostics.insert(
17016                            i,
17017                            (
17018                                start_anchor,
17019                                InlineDiagnostic {
17020                                    message,
17021                                    group_id: diagnostic_entry.diagnostic.group_id,
17022                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17023                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17024                                    severity: diagnostic_entry.diagnostic.severity,
17025                                },
17026                            ),
17027                        );
17028                    }
17029                    inline_diagnostics
17030                })
17031                .await;
17032
17033            editor
17034                .update(cx, |editor, cx| {
17035                    editor.inline_diagnostics = new_inline_diagnostics;
17036                    cx.notify();
17037                })
17038                .ok();
17039        });
17040    }
17041
17042    fn pull_diagnostics(
17043        &mut self,
17044        buffer_id: Option<BufferId>,
17045        window: &Window,
17046        cx: &mut Context<Self>,
17047    ) -> Option<()> {
17048        if !self.mode().is_full() {
17049            return None;
17050        }
17051        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17052            .diagnostics
17053            .lsp_pull_diagnostics;
17054        if !pull_diagnostics_settings.enabled {
17055            return None;
17056        }
17057        let project = self.project.as_ref()?.downgrade();
17058        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17059        let mut buffers = self.buffer.read(cx).all_buffers();
17060        if let Some(buffer_id) = buffer_id {
17061            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17062        }
17063
17064        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17065            cx.background_executor().timer(debounce).await;
17066
17067            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17068                buffers
17069                    .into_iter()
17070                    .filter_map(|buffer| {
17071                        project
17072                            .update(cx, |project, cx| {
17073                                project.lsp_store().update(cx, |lsp_store, cx| {
17074                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17075                                })
17076                            })
17077                            .ok()
17078                    })
17079                    .collect::<FuturesUnordered<_>>()
17080            }) else {
17081                return;
17082            };
17083
17084            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17085                match pull_task {
17086                    Ok(()) => {
17087                        if editor
17088                            .update_in(cx, |editor, window, cx| {
17089                                editor.update_diagnostics_state(window, cx);
17090                            })
17091                            .is_err()
17092                        {
17093                            return;
17094                        }
17095                    }
17096                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17097                }
17098            }
17099        });
17100
17101        Some(())
17102    }
17103
17104    pub fn set_selections_from_remote(
17105        &mut self,
17106        selections: Vec<Selection<Anchor>>,
17107        pending_selection: Option<Selection<Anchor>>,
17108        window: &mut Window,
17109        cx: &mut Context<Self>,
17110    ) {
17111        let old_cursor_position = self.selections.newest_anchor().head();
17112        self.selections.change_with(cx, |s| {
17113            s.select_anchors(selections);
17114            if let Some(pending_selection) = pending_selection {
17115                s.set_pending(pending_selection, SelectMode::Character);
17116            } else {
17117                s.clear_pending();
17118            }
17119        });
17120        self.selections_did_change(
17121            false,
17122            &old_cursor_position,
17123            SelectionEffects::default(),
17124            window,
17125            cx,
17126        );
17127    }
17128
17129    pub fn transact(
17130        &mut self,
17131        window: &mut Window,
17132        cx: &mut Context<Self>,
17133        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17134    ) -> Option<TransactionId> {
17135        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17136            this.start_transaction_at(Instant::now(), window, cx);
17137            update(this, window, cx);
17138            this.end_transaction_at(Instant::now(), cx)
17139        })
17140    }
17141
17142    pub fn start_transaction_at(
17143        &mut self,
17144        now: Instant,
17145        window: &mut Window,
17146        cx: &mut Context<Self>,
17147    ) -> Option<TransactionId> {
17148        self.end_selection(window, cx);
17149        if let Some(tx_id) = self
17150            .buffer
17151            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17152        {
17153            self.selection_history
17154                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17155            cx.emit(EditorEvent::TransactionBegun {
17156                transaction_id: tx_id,
17157            });
17158            Some(tx_id)
17159        } else {
17160            None
17161        }
17162    }
17163
17164    pub fn end_transaction_at(
17165        &mut self,
17166        now: Instant,
17167        cx: &mut Context<Self>,
17168    ) -> Option<TransactionId> {
17169        if let Some(transaction_id) = self
17170            .buffer
17171            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17172        {
17173            if let Some((_, end_selections)) =
17174                self.selection_history.transaction_mut(transaction_id)
17175            {
17176                *end_selections = Some(self.selections.disjoint_anchors());
17177            } else {
17178                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17179            }
17180
17181            cx.emit(EditorEvent::Edited { transaction_id });
17182            Some(transaction_id)
17183        } else {
17184            None
17185        }
17186    }
17187
17188    pub fn modify_transaction_selection_history(
17189        &mut self,
17190        transaction_id: TransactionId,
17191        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17192    ) -> bool {
17193        self.selection_history
17194            .transaction_mut(transaction_id)
17195            .map(modify)
17196            .is_some()
17197    }
17198
17199    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17200        if self.selection_mark_mode {
17201            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17202                s.move_with(|_, sel| {
17203                    sel.collapse_to(sel.head(), SelectionGoal::None);
17204                });
17205            })
17206        }
17207        self.selection_mark_mode = true;
17208        cx.notify();
17209    }
17210
17211    pub fn swap_selection_ends(
17212        &mut self,
17213        _: &actions::SwapSelectionEnds,
17214        window: &mut Window,
17215        cx: &mut Context<Self>,
17216    ) {
17217        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17218            s.move_with(|_, sel| {
17219                if sel.start != sel.end {
17220                    sel.reversed = !sel.reversed
17221                }
17222            });
17223        });
17224        self.request_autoscroll(Autoscroll::newest(), cx);
17225        cx.notify();
17226    }
17227
17228    pub fn toggle_focus(
17229        workspace: &mut Workspace,
17230        _: &actions::ToggleFocus,
17231        window: &mut Window,
17232        cx: &mut Context<Workspace>,
17233    ) {
17234        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17235            return;
17236        };
17237        workspace.activate_item(&item, true, true, window, cx);
17238    }
17239
17240    pub fn toggle_fold(
17241        &mut self,
17242        _: &actions::ToggleFold,
17243        window: &mut Window,
17244        cx: &mut Context<Self>,
17245    ) {
17246        if self.is_singleton(cx) {
17247            let selection = self.selections.newest::<Point>(cx);
17248
17249            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17250            let range = if selection.is_empty() {
17251                let point = selection.head().to_display_point(&display_map);
17252                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17253                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17254                    .to_point(&display_map);
17255                start..end
17256            } else {
17257                selection.range()
17258            };
17259            if display_map.folds_in_range(range).next().is_some() {
17260                self.unfold_lines(&Default::default(), window, cx)
17261            } else {
17262                self.fold(&Default::default(), window, cx)
17263            }
17264        } else {
17265            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17266            let buffer_ids: HashSet<_> = self
17267                .selections
17268                .disjoint_anchor_ranges()
17269                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17270                .collect();
17271
17272            let should_unfold = buffer_ids
17273                .iter()
17274                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17275
17276            for buffer_id in buffer_ids {
17277                if should_unfold {
17278                    self.unfold_buffer(buffer_id, cx);
17279                } else {
17280                    self.fold_buffer(buffer_id, cx);
17281                }
17282            }
17283        }
17284    }
17285
17286    pub fn toggle_fold_recursive(
17287        &mut self,
17288        _: &actions::ToggleFoldRecursive,
17289        window: &mut Window,
17290        cx: &mut Context<Self>,
17291    ) {
17292        let selection = self.selections.newest::<Point>(cx);
17293
17294        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17295        let range = if selection.is_empty() {
17296            let point = selection.head().to_display_point(&display_map);
17297            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17298            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17299                .to_point(&display_map);
17300            start..end
17301        } else {
17302            selection.range()
17303        };
17304        if display_map.folds_in_range(range).next().is_some() {
17305            self.unfold_recursive(&Default::default(), window, cx)
17306        } else {
17307            self.fold_recursive(&Default::default(), window, cx)
17308        }
17309    }
17310
17311    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17312        if self.is_singleton(cx) {
17313            let mut to_fold = Vec::new();
17314            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17315            let selections = self.selections.all_adjusted(cx);
17316
17317            for selection in selections {
17318                let range = selection.range().sorted();
17319                let buffer_start_row = range.start.row;
17320
17321                if range.start.row != range.end.row {
17322                    let mut found = false;
17323                    let mut row = range.start.row;
17324                    while row <= range.end.row {
17325                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17326                        {
17327                            found = true;
17328                            row = crease.range().end.row + 1;
17329                            to_fold.push(crease);
17330                        } else {
17331                            row += 1
17332                        }
17333                    }
17334                    if found {
17335                        continue;
17336                    }
17337                }
17338
17339                for row in (0..=range.start.row).rev() {
17340                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17341                        if crease.range().end.row >= buffer_start_row {
17342                            to_fold.push(crease);
17343                            if row <= range.start.row {
17344                                break;
17345                            }
17346                        }
17347                    }
17348                }
17349            }
17350
17351            self.fold_creases(to_fold, true, window, cx);
17352        } else {
17353            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17354            let buffer_ids = self
17355                .selections
17356                .disjoint_anchor_ranges()
17357                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17358                .collect::<HashSet<_>>();
17359            for buffer_id in buffer_ids {
17360                self.fold_buffer(buffer_id, cx);
17361            }
17362        }
17363    }
17364
17365    pub fn toggle_fold_all(
17366        &mut self,
17367        _: &actions::ToggleFoldAll,
17368        window: &mut Window,
17369        cx: &mut Context<Self>,
17370    ) {
17371        if self.buffer.read(cx).is_singleton() {
17372            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17373            let has_folds = display_map
17374                .folds_in_range(0..display_map.buffer_snapshot.len())
17375                .next()
17376                .is_some();
17377
17378            if has_folds {
17379                self.unfold_all(&actions::UnfoldAll, window, cx);
17380            } else {
17381                self.fold_all(&actions::FoldAll, window, cx);
17382            }
17383        } else {
17384            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17385            let should_unfold = buffer_ids
17386                .iter()
17387                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17388
17389            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17390                editor
17391                    .update_in(cx, |editor, _, cx| {
17392                        for buffer_id in buffer_ids {
17393                            if should_unfold {
17394                                editor.unfold_buffer(buffer_id, cx);
17395                            } else {
17396                                editor.fold_buffer(buffer_id, cx);
17397                            }
17398                        }
17399                    })
17400                    .ok();
17401            });
17402        }
17403    }
17404
17405    fn fold_at_level(
17406        &mut self,
17407        fold_at: &FoldAtLevel,
17408        window: &mut Window,
17409        cx: &mut Context<Self>,
17410    ) {
17411        if !self.buffer.read(cx).is_singleton() {
17412            return;
17413        }
17414
17415        let fold_at_level = fold_at.0;
17416        let snapshot = self.buffer.read(cx).snapshot(cx);
17417        let mut to_fold = Vec::new();
17418        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17419
17420        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17421            while start_row < end_row {
17422                match self
17423                    .snapshot(window, cx)
17424                    .crease_for_buffer_row(MultiBufferRow(start_row))
17425                {
17426                    Some(crease) => {
17427                        let nested_start_row = crease.range().start.row + 1;
17428                        let nested_end_row = crease.range().end.row;
17429
17430                        if current_level < fold_at_level {
17431                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17432                        } else if current_level == fold_at_level {
17433                            to_fold.push(crease);
17434                        }
17435
17436                        start_row = nested_end_row + 1;
17437                    }
17438                    None => start_row += 1,
17439                }
17440            }
17441        }
17442
17443        self.fold_creases(to_fold, true, window, cx);
17444    }
17445
17446    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17447        if self.buffer.read(cx).is_singleton() {
17448            let mut fold_ranges = Vec::new();
17449            let snapshot = self.buffer.read(cx).snapshot(cx);
17450
17451            for row in 0..snapshot.max_row().0 {
17452                if let Some(foldable_range) = self
17453                    .snapshot(window, cx)
17454                    .crease_for_buffer_row(MultiBufferRow(row))
17455                {
17456                    fold_ranges.push(foldable_range);
17457                }
17458            }
17459
17460            self.fold_creases(fold_ranges, true, window, cx);
17461        } else {
17462            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17463                editor
17464                    .update_in(cx, |editor, _, cx| {
17465                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17466                            editor.fold_buffer(buffer_id, cx);
17467                        }
17468                    })
17469                    .ok();
17470            });
17471        }
17472    }
17473
17474    pub fn fold_function_bodies(
17475        &mut self,
17476        _: &actions::FoldFunctionBodies,
17477        window: &mut Window,
17478        cx: &mut Context<Self>,
17479    ) {
17480        let snapshot = self.buffer.read(cx).snapshot(cx);
17481
17482        let ranges = snapshot
17483            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17484            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17485            .collect::<Vec<_>>();
17486
17487        let creases = ranges
17488            .into_iter()
17489            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17490            .collect();
17491
17492        self.fold_creases(creases, true, window, cx);
17493    }
17494
17495    pub fn fold_recursive(
17496        &mut self,
17497        _: &actions::FoldRecursive,
17498        window: &mut Window,
17499        cx: &mut Context<Self>,
17500    ) {
17501        let mut to_fold = Vec::new();
17502        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17503        let selections = self.selections.all_adjusted(cx);
17504
17505        for selection in selections {
17506            let range = selection.range().sorted();
17507            let buffer_start_row = range.start.row;
17508
17509            if range.start.row != range.end.row {
17510                let mut found = false;
17511                for row in range.start.row..=range.end.row {
17512                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17513                        found = true;
17514                        to_fold.push(crease);
17515                    }
17516                }
17517                if found {
17518                    continue;
17519                }
17520            }
17521
17522            for row in (0..=range.start.row).rev() {
17523                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17524                    if crease.range().end.row >= buffer_start_row {
17525                        to_fold.push(crease);
17526                    } else {
17527                        break;
17528                    }
17529                }
17530            }
17531        }
17532
17533        self.fold_creases(to_fold, true, window, cx);
17534    }
17535
17536    pub fn fold_at(
17537        &mut self,
17538        buffer_row: MultiBufferRow,
17539        window: &mut Window,
17540        cx: &mut Context<Self>,
17541    ) {
17542        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17543
17544        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17545            let autoscroll = self
17546                .selections
17547                .all::<Point>(cx)
17548                .iter()
17549                .any(|selection| crease.range().overlaps(&selection.range()));
17550
17551            self.fold_creases(vec![crease], autoscroll, window, cx);
17552        }
17553    }
17554
17555    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17556        if self.is_singleton(cx) {
17557            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17558            let buffer = &display_map.buffer_snapshot;
17559            let selections = self.selections.all::<Point>(cx);
17560            let ranges = selections
17561                .iter()
17562                .map(|s| {
17563                    let range = s.display_range(&display_map).sorted();
17564                    let mut start = range.start.to_point(&display_map);
17565                    let mut end = range.end.to_point(&display_map);
17566                    start.column = 0;
17567                    end.column = buffer.line_len(MultiBufferRow(end.row));
17568                    start..end
17569                })
17570                .collect::<Vec<_>>();
17571
17572            self.unfold_ranges(&ranges, true, true, cx);
17573        } else {
17574            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17575            let buffer_ids = self
17576                .selections
17577                .disjoint_anchor_ranges()
17578                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17579                .collect::<HashSet<_>>();
17580            for buffer_id in buffer_ids {
17581                self.unfold_buffer(buffer_id, cx);
17582            }
17583        }
17584    }
17585
17586    pub fn unfold_recursive(
17587        &mut self,
17588        _: &UnfoldRecursive,
17589        _window: &mut Window,
17590        cx: &mut Context<Self>,
17591    ) {
17592        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17593        let selections = self.selections.all::<Point>(cx);
17594        let ranges = selections
17595            .iter()
17596            .map(|s| {
17597                let mut range = s.display_range(&display_map).sorted();
17598                *range.start.column_mut() = 0;
17599                *range.end.column_mut() = display_map.line_len(range.end.row());
17600                let start = range.start.to_point(&display_map);
17601                let end = range.end.to_point(&display_map);
17602                start..end
17603            })
17604            .collect::<Vec<_>>();
17605
17606        self.unfold_ranges(&ranges, true, true, cx);
17607    }
17608
17609    pub fn unfold_at(
17610        &mut self,
17611        buffer_row: MultiBufferRow,
17612        _window: &mut Window,
17613        cx: &mut Context<Self>,
17614    ) {
17615        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17616
17617        let intersection_range = Point::new(buffer_row.0, 0)
17618            ..Point::new(
17619                buffer_row.0,
17620                display_map.buffer_snapshot.line_len(buffer_row),
17621            );
17622
17623        let autoscroll = self
17624            .selections
17625            .all::<Point>(cx)
17626            .iter()
17627            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17628
17629        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17630    }
17631
17632    pub fn unfold_all(
17633        &mut self,
17634        _: &actions::UnfoldAll,
17635        _window: &mut Window,
17636        cx: &mut Context<Self>,
17637    ) {
17638        if self.buffer.read(cx).is_singleton() {
17639            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17640            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17641        } else {
17642            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17643                editor
17644                    .update(cx, |editor, cx| {
17645                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17646                            editor.unfold_buffer(buffer_id, cx);
17647                        }
17648                    })
17649                    .ok();
17650            });
17651        }
17652    }
17653
17654    pub fn fold_selected_ranges(
17655        &mut self,
17656        _: &FoldSelectedRanges,
17657        window: &mut Window,
17658        cx: &mut Context<Self>,
17659    ) {
17660        let selections = self.selections.all_adjusted(cx);
17661        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17662        let ranges = selections
17663            .into_iter()
17664            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17665            .collect::<Vec<_>>();
17666        self.fold_creases(ranges, true, window, cx);
17667    }
17668
17669    pub fn fold_ranges<T: ToOffset + Clone>(
17670        &mut self,
17671        ranges: Vec<Range<T>>,
17672        auto_scroll: bool,
17673        window: &mut Window,
17674        cx: &mut Context<Self>,
17675    ) {
17676        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17677        let ranges = ranges
17678            .into_iter()
17679            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17680            .collect::<Vec<_>>();
17681        self.fold_creases(ranges, auto_scroll, window, cx);
17682    }
17683
17684    pub fn fold_creases<T: ToOffset + Clone>(
17685        &mut self,
17686        creases: Vec<Crease<T>>,
17687        auto_scroll: bool,
17688        _window: &mut Window,
17689        cx: &mut Context<Self>,
17690    ) {
17691        if creases.is_empty() {
17692            return;
17693        }
17694
17695        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17696
17697        if auto_scroll {
17698            self.request_autoscroll(Autoscroll::fit(), cx);
17699        }
17700
17701        cx.notify();
17702
17703        self.scrollbar_marker_state.dirty = true;
17704        self.folds_did_change(cx);
17705    }
17706
17707    /// Removes any folds whose ranges intersect any of the given ranges.
17708    pub fn unfold_ranges<T: ToOffset + Clone>(
17709        &mut self,
17710        ranges: &[Range<T>],
17711        inclusive: bool,
17712        auto_scroll: bool,
17713        cx: &mut Context<Self>,
17714    ) {
17715        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17716            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17717        });
17718        self.folds_did_change(cx);
17719    }
17720
17721    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17722        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17723            return;
17724        }
17725        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17726        self.display_map.update(cx, |display_map, cx| {
17727            display_map.fold_buffers([buffer_id], cx)
17728        });
17729        cx.emit(EditorEvent::BufferFoldToggled {
17730            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17731            folded: true,
17732        });
17733        cx.notify();
17734    }
17735
17736    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17737        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17738            return;
17739        }
17740        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17741        self.display_map.update(cx, |display_map, cx| {
17742            display_map.unfold_buffers([buffer_id], cx);
17743        });
17744        cx.emit(EditorEvent::BufferFoldToggled {
17745            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17746            folded: false,
17747        });
17748        cx.notify();
17749    }
17750
17751    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17752        self.display_map.read(cx).is_buffer_folded(buffer)
17753    }
17754
17755    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17756        self.display_map.read(cx).folded_buffers()
17757    }
17758
17759    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17760        self.display_map.update(cx, |display_map, cx| {
17761            display_map.disable_header_for_buffer(buffer_id, cx);
17762        });
17763        cx.notify();
17764    }
17765
17766    /// Removes any folds with the given ranges.
17767    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17768        &mut self,
17769        ranges: &[Range<T>],
17770        type_id: TypeId,
17771        auto_scroll: bool,
17772        cx: &mut Context<Self>,
17773    ) {
17774        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17775            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17776        });
17777        self.folds_did_change(cx);
17778    }
17779
17780    fn remove_folds_with<T: ToOffset + Clone>(
17781        &mut self,
17782        ranges: &[Range<T>],
17783        auto_scroll: bool,
17784        cx: &mut Context<Self>,
17785        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17786    ) {
17787        if ranges.is_empty() {
17788            return;
17789        }
17790
17791        let mut buffers_affected = HashSet::default();
17792        let multi_buffer = self.buffer().read(cx);
17793        for range in ranges {
17794            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17795                buffers_affected.insert(buffer.read(cx).remote_id());
17796            };
17797        }
17798
17799        self.display_map.update(cx, update);
17800
17801        if auto_scroll {
17802            self.request_autoscroll(Autoscroll::fit(), cx);
17803        }
17804
17805        cx.notify();
17806        self.scrollbar_marker_state.dirty = true;
17807        self.active_indent_guides_state.dirty = true;
17808    }
17809
17810    pub fn update_renderer_widths(
17811        &mut self,
17812        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17813        cx: &mut Context<Self>,
17814    ) -> bool {
17815        self.display_map
17816            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17817    }
17818
17819    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17820        self.display_map.read(cx).fold_placeholder.clone()
17821    }
17822
17823    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17824        self.buffer.update(cx, |buffer, cx| {
17825            buffer.set_all_diff_hunks_expanded(cx);
17826        });
17827    }
17828
17829    pub fn expand_all_diff_hunks(
17830        &mut self,
17831        _: &ExpandAllDiffHunks,
17832        _window: &mut Window,
17833        cx: &mut Context<Self>,
17834    ) {
17835        self.buffer.update(cx, |buffer, cx| {
17836            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17837        });
17838    }
17839
17840    pub fn toggle_selected_diff_hunks(
17841        &mut self,
17842        _: &ToggleSelectedDiffHunks,
17843        _window: &mut Window,
17844        cx: &mut Context<Self>,
17845    ) {
17846        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17847        self.toggle_diff_hunks_in_ranges(ranges, cx);
17848    }
17849
17850    pub fn diff_hunks_in_ranges<'a>(
17851        &'a self,
17852        ranges: &'a [Range<Anchor>],
17853        buffer: &'a MultiBufferSnapshot,
17854    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17855        ranges.iter().flat_map(move |range| {
17856            let end_excerpt_id = range.end.excerpt_id;
17857            let range = range.to_point(buffer);
17858            let mut peek_end = range.end;
17859            if range.end.row < buffer.max_row().0 {
17860                peek_end = Point::new(range.end.row + 1, 0);
17861            }
17862            buffer
17863                .diff_hunks_in_range(range.start..peek_end)
17864                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17865        })
17866    }
17867
17868    pub fn has_stageable_diff_hunks_in_ranges(
17869        &self,
17870        ranges: &[Range<Anchor>],
17871        snapshot: &MultiBufferSnapshot,
17872    ) -> bool {
17873        let mut hunks = self.diff_hunks_in_ranges(ranges, &snapshot);
17874        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17875    }
17876
17877    pub fn toggle_staged_selected_diff_hunks(
17878        &mut self,
17879        _: &::git::ToggleStaged,
17880        _: &mut Window,
17881        cx: &mut Context<Self>,
17882    ) {
17883        let snapshot = self.buffer.read(cx).snapshot(cx);
17884        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17885        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17886        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17887    }
17888
17889    pub fn set_render_diff_hunk_controls(
17890        &mut self,
17891        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17892        cx: &mut Context<Self>,
17893    ) {
17894        self.render_diff_hunk_controls = render_diff_hunk_controls;
17895        cx.notify();
17896    }
17897
17898    pub fn stage_and_next(
17899        &mut self,
17900        _: &::git::StageAndNext,
17901        window: &mut Window,
17902        cx: &mut Context<Self>,
17903    ) {
17904        self.do_stage_or_unstage_and_next(true, window, cx);
17905    }
17906
17907    pub fn unstage_and_next(
17908        &mut self,
17909        _: &::git::UnstageAndNext,
17910        window: &mut Window,
17911        cx: &mut Context<Self>,
17912    ) {
17913        self.do_stage_or_unstage_and_next(false, window, cx);
17914    }
17915
17916    pub fn stage_or_unstage_diff_hunks(
17917        &mut self,
17918        stage: bool,
17919        ranges: Vec<Range<Anchor>>,
17920        cx: &mut Context<Self>,
17921    ) {
17922        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17923        cx.spawn(async move |this, cx| {
17924            task.await?;
17925            this.update(cx, |this, cx| {
17926                let snapshot = this.buffer.read(cx).snapshot(cx);
17927                let chunk_by = this
17928                    .diff_hunks_in_ranges(&ranges, &snapshot)
17929                    .chunk_by(|hunk| hunk.buffer_id);
17930                for (buffer_id, hunks) in &chunk_by {
17931                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17932                }
17933            })
17934        })
17935        .detach_and_log_err(cx);
17936    }
17937
17938    fn save_buffers_for_ranges_if_needed(
17939        &mut self,
17940        ranges: &[Range<Anchor>],
17941        cx: &mut Context<Editor>,
17942    ) -> Task<Result<()>> {
17943        let multibuffer = self.buffer.read(cx);
17944        let snapshot = multibuffer.read(cx);
17945        let buffer_ids: HashSet<_> = ranges
17946            .iter()
17947            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17948            .collect();
17949        drop(snapshot);
17950
17951        let mut buffers = HashSet::default();
17952        for buffer_id in buffer_ids {
17953            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17954                let buffer = buffer_entity.read(cx);
17955                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17956                {
17957                    buffers.insert(buffer_entity);
17958                }
17959            }
17960        }
17961
17962        if let Some(project) = &self.project {
17963            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17964        } else {
17965            Task::ready(Ok(()))
17966        }
17967    }
17968
17969    fn do_stage_or_unstage_and_next(
17970        &mut self,
17971        stage: bool,
17972        window: &mut Window,
17973        cx: &mut Context<Self>,
17974    ) {
17975        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17976
17977        if ranges.iter().any(|range| range.start != range.end) {
17978            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17979            return;
17980        }
17981
17982        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17983        let snapshot = self.snapshot(window, cx);
17984        let position = self.selections.newest::<Point>(cx).head();
17985        let mut row = snapshot
17986            .buffer_snapshot
17987            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
17988            .find(|hunk| hunk.row_range.start.0 > position.row)
17989            .map(|hunk| hunk.row_range.start);
17990
17991        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
17992        // Outside of the project diff editor, wrap around to the beginning.
17993        if !all_diff_hunks_expanded {
17994            row = row.or_else(|| {
17995                snapshot
17996                    .buffer_snapshot
17997                    .diff_hunks_in_range(Point::zero()..position)
17998                    .find(|hunk| hunk.row_range.end.0 < position.row)
17999                    .map(|hunk| hunk.row_range.start)
18000            });
18001        }
18002
18003        if let Some(row) = row {
18004            let destination = Point::new(row.0, 0);
18005            let autoscroll = Autoscroll::center();
18006
18007            self.unfold_ranges(&[destination..destination], false, false, cx);
18008            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18009                s.select_ranges([destination..destination]);
18010            });
18011        }
18012    }
18013
18014    fn do_stage_or_unstage(
18015        &self,
18016        stage: bool,
18017        buffer_id: BufferId,
18018        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18019        cx: &mut App,
18020    ) -> Option<()> {
18021        let project = self.project.as_ref()?;
18022        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18023        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18024        let buffer_snapshot = buffer.read(cx).snapshot();
18025        let file_exists = buffer_snapshot
18026            .file()
18027            .is_some_and(|file| file.disk_state().exists());
18028        diff.update(cx, |diff, cx| {
18029            diff.stage_or_unstage_hunks(
18030                stage,
18031                &hunks
18032                    .map(|hunk| buffer_diff::DiffHunk {
18033                        buffer_range: hunk.buffer_range,
18034                        diff_base_byte_range: hunk.diff_base_byte_range,
18035                        secondary_status: hunk.secondary_status,
18036                        range: Point::zero()..Point::zero(), // unused
18037                    })
18038                    .collect::<Vec<_>>(),
18039                &buffer_snapshot,
18040                file_exists,
18041                cx,
18042            )
18043        });
18044        None
18045    }
18046
18047    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18048        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18049        self.buffer
18050            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18051    }
18052
18053    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18054        self.buffer.update(cx, |buffer, cx| {
18055            let ranges = vec![Anchor::min()..Anchor::max()];
18056            if !buffer.all_diff_hunks_expanded()
18057                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18058            {
18059                buffer.collapse_diff_hunks(ranges, cx);
18060                true
18061            } else {
18062                false
18063            }
18064        })
18065    }
18066
18067    fn toggle_diff_hunks_in_ranges(
18068        &mut self,
18069        ranges: Vec<Range<Anchor>>,
18070        cx: &mut Context<Editor>,
18071    ) {
18072        self.buffer.update(cx, |buffer, cx| {
18073            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18074            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18075        })
18076    }
18077
18078    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18079        self.buffer.update(cx, |buffer, cx| {
18080            let snapshot = buffer.snapshot(cx);
18081            let excerpt_id = range.end.excerpt_id;
18082            let point_range = range.to_point(&snapshot);
18083            let expand = !buffer.single_hunk_is_expanded(range, cx);
18084            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18085        })
18086    }
18087
18088    pub(crate) fn apply_all_diff_hunks(
18089        &mut self,
18090        _: &ApplyAllDiffHunks,
18091        window: &mut Window,
18092        cx: &mut Context<Self>,
18093    ) {
18094        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18095
18096        let buffers = self.buffer.read(cx).all_buffers();
18097        for branch_buffer in buffers {
18098            branch_buffer.update(cx, |branch_buffer, cx| {
18099                branch_buffer.merge_into_base(Vec::new(), cx);
18100            });
18101        }
18102
18103        if let Some(project) = self.project.clone() {
18104            self.save(
18105                SaveOptions {
18106                    format: true,
18107                    autosave: false,
18108                },
18109                project,
18110                window,
18111                cx,
18112            )
18113            .detach_and_log_err(cx);
18114        }
18115    }
18116
18117    pub(crate) fn apply_selected_diff_hunks(
18118        &mut self,
18119        _: &ApplyDiffHunk,
18120        window: &mut Window,
18121        cx: &mut Context<Self>,
18122    ) {
18123        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18124        let snapshot = self.snapshot(window, cx);
18125        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18126        let mut ranges_by_buffer = HashMap::default();
18127        self.transact(window, cx, |editor, _window, cx| {
18128            for hunk in hunks {
18129                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18130                    ranges_by_buffer
18131                        .entry(buffer.clone())
18132                        .or_insert_with(Vec::new)
18133                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18134                }
18135            }
18136
18137            for (buffer, ranges) in ranges_by_buffer {
18138                buffer.update(cx, |buffer, cx| {
18139                    buffer.merge_into_base(ranges, cx);
18140                });
18141            }
18142        });
18143
18144        if let Some(project) = self.project.clone() {
18145            self.save(
18146                SaveOptions {
18147                    format: true,
18148                    autosave: false,
18149                },
18150                project,
18151                window,
18152                cx,
18153            )
18154            .detach_and_log_err(cx);
18155        }
18156    }
18157
18158    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18159        if hovered != self.gutter_hovered {
18160            self.gutter_hovered = hovered;
18161            cx.notify();
18162        }
18163    }
18164
18165    pub fn insert_blocks(
18166        &mut self,
18167        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18168        autoscroll: Option<Autoscroll>,
18169        cx: &mut Context<Self>,
18170    ) -> Vec<CustomBlockId> {
18171        let blocks = self
18172            .display_map
18173            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18174        if let Some(autoscroll) = autoscroll {
18175            self.request_autoscroll(autoscroll, cx);
18176        }
18177        cx.notify();
18178        blocks
18179    }
18180
18181    pub fn resize_blocks(
18182        &mut self,
18183        heights: HashMap<CustomBlockId, u32>,
18184        autoscroll: Option<Autoscroll>,
18185        cx: &mut Context<Self>,
18186    ) {
18187        self.display_map
18188            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18189        if let Some(autoscroll) = autoscroll {
18190            self.request_autoscroll(autoscroll, cx);
18191        }
18192        cx.notify();
18193    }
18194
18195    pub fn replace_blocks(
18196        &mut self,
18197        renderers: HashMap<CustomBlockId, RenderBlock>,
18198        autoscroll: Option<Autoscroll>,
18199        cx: &mut Context<Self>,
18200    ) {
18201        self.display_map
18202            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18203        if let Some(autoscroll) = autoscroll {
18204            self.request_autoscroll(autoscroll, cx);
18205        }
18206        cx.notify();
18207    }
18208
18209    pub fn remove_blocks(
18210        &mut self,
18211        block_ids: HashSet<CustomBlockId>,
18212        autoscroll: Option<Autoscroll>,
18213        cx: &mut Context<Self>,
18214    ) {
18215        self.display_map.update(cx, |display_map, cx| {
18216            display_map.remove_blocks(block_ids, cx)
18217        });
18218        if let Some(autoscroll) = autoscroll {
18219            self.request_autoscroll(autoscroll, cx);
18220        }
18221        cx.notify();
18222    }
18223
18224    pub fn row_for_block(
18225        &self,
18226        block_id: CustomBlockId,
18227        cx: &mut Context<Self>,
18228    ) -> Option<DisplayRow> {
18229        self.display_map
18230            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18231    }
18232
18233    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18234        self.focused_block = Some(focused_block);
18235    }
18236
18237    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18238        self.focused_block.take()
18239    }
18240
18241    pub fn insert_creases(
18242        &mut self,
18243        creases: impl IntoIterator<Item = Crease<Anchor>>,
18244        cx: &mut Context<Self>,
18245    ) -> Vec<CreaseId> {
18246        self.display_map
18247            .update(cx, |map, cx| map.insert_creases(creases, cx))
18248    }
18249
18250    pub fn remove_creases(
18251        &mut self,
18252        ids: impl IntoIterator<Item = CreaseId>,
18253        cx: &mut Context<Self>,
18254    ) -> Vec<(CreaseId, Range<Anchor>)> {
18255        self.display_map
18256            .update(cx, |map, cx| map.remove_creases(ids, cx))
18257    }
18258
18259    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18260        self.display_map
18261            .update(cx, |map, cx| map.snapshot(cx))
18262            .longest_row()
18263    }
18264
18265    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18266        self.display_map
18267            .update(cx, |map, cx| map.snapshot(cx))
18268            .max_point()
18269    }
18270
18271    pub fn text(&self, cx: &App) -> String {
18272        self.buffer.read(cx).read(cx).text()
18273    }
18274
18275    pub fn is_empty(&self, cx: &App) -> bool {
18276        self.buffer.read(cx).read(cx).is_empty()
18277    }
18278
18279    pub fn text_option(&self, cx: &App) -> Option<String> {
18280        let text = self.text(cx);
18281        let text = text.trim();
18282
18283        if text.is_empty() {
18284            return None;
18285        }
18286
18287        Some(text.to_string())
18288    }
18289
18290    pub fn set_text(
18291        &mut self,
18292        text: impl Into<Arc<str>>,
18293        window: &mut Window,
18294        cx: &mut Context<Self>,
18295    ) {
18296        self.transact(window, cx, |this, _, cx| {
18297            this.buffer
18298                .read(cx)
18299                .as_singleton()
18300                .expect("you can only call set_text on editors for singleton buffers")
18301                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18302        });
18303    }
18304
18305    pub fn display_text(&self, cx: &mut App) -> String {
18306        self.display_map
18307            .update(cx, |map, cx| map.snapshot(cx))
18308            .text()
18309    }
18310
18311    fn create_minimap(
18312        &self,
18313        minimap_settings: MinimapSettings,
18314        window: &mut Window,
18315        cx: &mut Context<Self>,
18316    ) -> Option<Entity<Self>> {
18317        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18318            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18319    }
18320
18321    fn initialize_new_minimap(
18322        &self,
18323        minimap_settings: MinimapSettings,
18324        window: &mut Window,
18325        cx: &mut Context<Self>,
18326    ) -> Entity<Self> {
18327        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18328
18329        let mut minimap = Editor::new_internal(
18330            EditorMode::Minimap {
18331                parent: cx.weak_entity(),
18332            },
18333            self.buffer.clone(),
18334            None,
18335            Some(self.display_map.clone()),
18336            window,
18337            cx,
18338        );
18339        minimap.scroll_manager.clone_state(&self.scroll_manager);
18340        minimap.set_text_style_refinement(TextStyleRefinement {
18341            font_size: Some(MINIMAP_FONT_SIZE),
18342            font_weight: Some(MINIMAP_FONT_WEIGHT),
18343            ..Default::default()
18344        });
18345        minimap.update_minimap_configuration(minimap_settings, cx);
18346        cx.new(|_| minimap)
18347    }
18348
18349    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18350        let current_line_highlight = minimap_settings
18351            .current_line_highlight
18352            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18353        self.set_current_line_highlight(Some(current_line_highlight));
18354    }
18355
18356    pub fn minimap(&self) -> Option<&Entity<Self>> {
18357        self.minimap
18358            .as_ref()
18359            .filter(|_| self.minimap_visibility.visible())
18360    }
18361
18362    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18363        let mut wrap_guides = smallvec![];
18364
18365        if self.show_wrap_guides == Some(false) {
18366            return wrap_guides;
18367        }
18368
18369        let settings = self.buffer.read(cx).language_settings(cx);
18370        if settings.show_wrap_guides {
18371            match self.soft_wrap_mode(cx) {
18372                SoftWrap::Column(soft_wrap) => {
18373                    wrap_guides.push((soft_wrap as usize, true));
18374                }
18375                SoftWrap::Bounded(soft_wrap) => {
18376                    wrap_guides.push((soft_wrap as usize, true));
18377                }
18378                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18379            }
18380            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18381        }
18382
18383        wrap_guides
18384    }
18385
18386    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18387        let settings = self.buffer.read(cx).language_settings(cx);
18388        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18389        match mode {
18390            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18391                SoftWrap::None
18392            }
18393            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18394            language_settings::SoftWrap::PreferredLineLength => {
18395                SoftWrap::Column(settings.preferred_line_length)
18396            }
18397            language_settings::SoftWrap::Bounded => {
18398                SoftWrap::Bounded(settings.preferred_line_length)
18399            }
18400        }
18401    }
18402
18403    pub fn set_soft_wrap_mode(
18404        &mut self,
18405        mode: language_settings::SoftWrap,
18406
18407        cx: &mut Context<Self>,
18408    ) {
18409        self.soft_wrap_mode_override = Some(mode);
18410        cx.notify();
18411    }
18412
18413    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18414        self.hard_wrap = hard_wrap;
18415        cx.notify();
18416    }
18417
18418    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18419        self.text_style_refinement = Some(style);
18420    }
18421
18422    /// called by the Element so we know what style we were most recently rendered with.
18423    pub(crate) fn set_style(
18424        &mut self,
18425        style: EditorStyle,
18426        window: &mut Window,
18427        cx: &mut Context<Self>,
18428    ) {
18429        // We intentionally do not inform the display map about the minimap style
18430        // so that wrapping is not recalculated and stays consistent for the editor
18431        // and its linked minimap.
18432        if !self.mode.is_minimap() {
18433            let rem_size = window.rem_size();
18434            self.display_map.update(cx, |map, cx| {
18435                map.set_font(
18436                    style.text.font(),
18437                    style.text.font_size.to_pixels(rem_size),
18438                    cx,
18439                )
18440            });
18441        }
18442        self.style = Some(style);
18443    }
18444
18445    pub fn style(&self) -> Option<&EditorStyle> {
18446        self.style.as_ref()
18447    }
18448
18449    // Called by the element. This method is not designed to be called outside of the editor
18450    // element's layout code because it does not notify when rewrapping is computed synchronously.
18451    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18452        self.display_map
18453            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18454    }
18455
18456    pub fn set_soft_wrap(&mut self) {
18457        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18458    }
18459
18460    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18461        if self.soft_wrap_mode_override.is_some() {
18462            self.soft_wrap_mode_override.take();
18463        } else {
18464            let soft_wrap = match self.soft_wrap_mode(cx) {
18465                SoftWrap::GitDiff => return,
18466                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18467                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18468                    language_settings::SoftWrap::None
18469                }
18470            };
18471            self.soft_wrap_mode_override = Some(soft_wrap);
18472        }
18473        cx.notify();
18474    }
18475
18476    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18477        let Some(workspace) = self.workspace() else {
18478            return;
18479        };
18480        let fs = workspace.read(cx).app_state().fs.clone();
18481        let current_show = TabBarSettings::get_global(cx).show;
18482        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18483            setting.show = Some(!current_show);
18484        });
18485    }
18486
18487    pub fn toggle_indent_guides(
18488        &mut self,
18489        _: &ToggleIndentGuides,
18490        _: &mut Window,
18491        cx: &mut Context<Self>,
18492    ) {
18493        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18494            self.buffer
18495                .read(cx)
18496                .language_settings(cx)
18497                .indent_guides
18498                .enabled
18499        });
18500        self.show_indent_guides = Some(!currently_enabled);
18501        cx.notify();
18502    }
18503
18504    fn should_show_indent_guides(&self) -> Option<bool> {
18505        self.show_indent_guides
18506    }
18507
18508    pub fn toggle_line_numbers(
18509        &mut self,
18510        _: &ToggleLineNumbers,
18511        _: &mut Window,
18512        cx: &mut Context<Self>,
18513    ) {
18514        let mut editor_settings = EditorSettings::get_global(cx).clone();
18515        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18516        EditorSettings::override_global(editor_settings, cx);
18517    }
18518
18519    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18520        if let Some(show_line_numbers) = self.show_line_numbers {
18521            return show_line_numbers;
18522        }
18523        EditorSettings::get_global(cx).gutter.line_numbers
18524    }
18525
18526    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18527        self.use_relative_line_numbers
18528            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18529    }
18530
18531    pub fn toggle_relative_line_numbers(
18532        &mut self,
18533        _: &ToggleRelativeLineNumbers,
18534        _: &mut Window,
18535        cx: &mut Context<Self>,
18536    ) {
18537        let is_relative = self.should_use_relative_line_numbers(cx);
18538        self.set_relative_line_number(Some(!is_relative), cx)
18539    }
18540
18541    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18542        self.use_relative_line_numbers = is_relative;
18543        cx.notify();
18544    }
18545
18546    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18547        self.show_gutter = show_gutter;
18548        cx.notify();
18549    }
18550
18551    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18552        self.show_scrollbars = ScrollbarAxes {
18553            horizontal: show,
18554            vertical: show,
18555        };
18556        cx.notify();
18557    }
18558
18559    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18560        self.show_scrollbars.vertical = show;
18561        cx.notify();
18562    }
18563
18564    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18565        self.show_scrollbars.horizontal = show;
18566        cx.notify();
18567    }
18568
18569    pub fn set_minimap_visibility(
18570        &mut self,
18571        minimap_visibility: MinimapVisibility,
18572        window: &mut Window,
18573        cx: &mut Context<Self>,
18574    ) {
18575        if self.minimap_visibility != minimap_visibility {
18576            if minimap_visibility.visible() && self.minimap.is_none() {
18577                let minimap_settings = EditorSettings::get_global(cx).minimap;
18578                self.minimap =
18579                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18580            }
18581            self.minimap_visibility = minimap_visibility;
18582            cx.notify();
18583        }
18584    }
18585
18586    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18587        self.set_show_scrollbars(false, cx);
18588        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18589    }
18590
18591    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18592        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18593    }
18594
18595    /// Normally the text in full mode and auto height editors is padded on the
18596    /// left side by roughly half a character width for improved hit testing.
18597    ///
18598    /// Use this method to disable this for cases where this is not wanted (e.g.
18599    /// if you want to align the editor text with some other text above or below)
18600    /// or if you want to add this padding to single-line editors.
18601    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18602        self.offset_content = offset_content;
18603        cx.notify();
18604    }
18605
18606    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18607        self.show_line_numbers = Some(show_line_numbers);
18608        cx.notify();
18609    }
18610
18611    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18612        self.disable_expand_excerpt_buttons = true;
18613        cx.notify();
18614    }
18615
18616    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18617        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18618        cx.notify();
18619    }
18620
18621    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18622        self.show_code_actions = Some(show_code_actions);
18623        cx.notify();
18624    }
18625
18626    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18627        self.show_runnables = Some(show_runnables);
18628        cx.notify();
18629    }
18630
18631    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18632        self.show_breakpoints = Some(show_breakpoints);
18633        cx.notify();
18634    }
18635
18636    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18637        if self.display_map.read(cx).masked != masked {
18638            self.display_map.update(cx, |map, _| map.masked = masked);
18639        }
18640        cx.notify()
18641    }
18642
18643    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18644        self.show_wrap_guides = Some(show_wrap_guides);
18645        cx.notify();
18646    }
18647
18648    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18649        self.show_indent_guides = Some(show_indent_guides);
18650        cx.notify();
18651    }
18652
18653    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18654        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18655            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local()) {
18656                if let Some(dir) = file.abs_path(cx).parent() {
18657                    return Some(dir.to_owned());
18658                }
18659            }
18660
18661            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18662                return Some(project_path.path.to_path_buf());
18663            }
18664        }
18665
18666        None
18667    }
18668
18669    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18670        self.active_excerpt(cx)?
18671            .1
18672            .read(cx)
18673            .file()
18674            .and_then(|f| f.as_local())
18675    }
18676
18677    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18678        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18679            let buffer = buffer.read(cx);
18680            if let Some(project_path) = buffer.project_path(cx) {
18681                let project = self.project.as_ref()?.read(cx);
18682                project.absolute_path(&project_path, cx)
18683            } else {
18684                buffer
18685                    .file()
18686                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18687            }
18688        })
18689    }
18690
18691    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18692        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18693            let project_path = buffer.read(cx).project_path(cx)?;
18694            let project = self.project.as_ref()?.read(cx);
18695            let entry = project.entry_for_path(&project_path, cx)?;
18696            let path = entry.path.to_path_buf();
18697            Some(path)
18698        })
18699    }
18700
18701    pub fn reveal_in_finder(
18702        &mut self,
18703        _: &RevealInFileManager,
18704        _window: &mut Window,
18705        cx: &mut Context<Self>,
18706    ) {
18707        if let Some(target) = self.target_file(cx) {
18708            cx.reveal_path(&target.abs_path(cx));
18709        }
18710    }
18711
18712    pub fn copy_path(
18713        &mut self,
18714        _: &zed_actions::workspace::CopyPath,
18715        _window: &mut Window,
18716        cx: &mut Context<Self>,
18717    ) {
18718        if let Some(path) = self.target_file_abs_path(cx) {
18719            if let Some(path) = path.to_str() {
18720                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18721            }
18722        }
18723    }
18724
18725    pub fn copy_relative_path(
18726        &mut self,
18727        _: &zed_actions::workspace::CopyRelativePath,
18728        _window: &mut Window,
18729        cx: &mut Context<Self>,
18730    ) {
18731        if let Some(path) = self.target_file_path(cx) {
18732            if let Some(path) = path.to_str() {
18733                cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18734            }
18735        }
18736    }
18737
18738    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18739        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18740            buffer.read(cx).project_path(cx)
18741        } else {
18742            None
18743        }
18744    }
18745
18746    // Returns true if the editor handled a go-to-line request
18747    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18748        maybe!({
18749            let breakpoint_store = self.breakpoint_store.as_ref()?;
18750
18751            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18752            else {
18753                self.clear_row_highlights::<ActiveDebugLine>();
18754                return None;
18755            };
18756
18757            let position = active_stack_frame.position;
18758            let buffer_id = position.buffer_id?;
18759            let snapshot = self
18760                .project
18761                .as_ref()?
18762                .read(cx)
18763                .buffer_for_id(buffer_id, cx)?
18764                .read(cx)
18765                .snapshot();
18766
18767            let mut handled = false;
18768            for (id, ExcerptRange { context, .. }) in
18769                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18770            {
18771                if context.start.cmp(&position, &snapshot).is_ge()
18772                    || context.end.cmp(&position, &snapshot).is_lt()
18773                {
18774                    continue;
18775                }
18776                let snapshot = self.buffer.read(cx).snapshot(cx);
18777                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18778
18779                handled = true;
18780                self.clear_row_highlights::<ActiveDebugLine>();
18781
18782                self.go_to_line::<ActiveDebugLine>(
18783                    multibuffer_anchor,
18784                    Some(cx.theme().colors().editor_debugger_active_line_background),
18785                    window,
18786                    cx,
18787                );
18788
18789                cx.notify();
18790            }
18791
18792            handled.then_some(())
18793        })
18794        .is_some()
18795    }
18796
18797    pub fn copy_file_name_without_extension(
18798        &mut self,
18799        _: &CopyFileNameWithoutExtension,
18800        _: &mut Window,
18801        cx: &mut Context<Self>,
18802    ) {
18803        if let Some(file) = self.target_file(cx) {
18804            if let Some(file_stem) = file.path().file_stem() {
18805                if let Some(name) = file_stem.to_str() {
18806                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18807                }
18808            }
18809        }
18810    }
18811
18812    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18813        if let Some(file) = self.target_file(cx) {
18814            if let Some(file_name) = file.path().file_name() {
18815                if let Some(name) = file_name.to_str() {
18816                    cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18817                }
18818            }
18819        }
18820    }
18821
18822    pub fn toggle_git_blame(
18823        &mut self,
18824        _: &::git::Blame,
18825        window: &mut Window,
18826        cx: &mut Context<Self>,
18827    ) {
18828        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18829
18830        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18831            self.start_git_blame(true, window, cx);
18832        }
18833
18834        cx.notify();
18835    }
18836
18837    pub fn toggle_git_blame_inline(
18838        &mut self,
18839        _: &ToggleGitBlameInline,
18840        window: &mut Window,
18841        cx: &mut Context<Self>,
18842    ) {
18843        self.toggle_git_blame_inline_internal(true, window, cx);
18844        cx.notify();
18845    }
18846
18847    pub fn open_git_blame_commit(
18848        &mut self,
18849        _: &OpenGitBlameCommit,
18850        window: &mut Window,
18851        cx: &mut Context<Self>,
18852    ) {
18853        self.open_git_blame_commit_internal(window, cx);
18854    }
18855
18856    fn open_git_blame_commit_internal(
18857        &mut self,
18858        window: &mut Window,
18859        cx: &mut Context<Self>,
18860    ) -> Option<()> {
18861        let blame = self.blame.as_ref()?;
18862        let snapshot = self.snapshot(window, cx);
18863        let cursor = self.selections.newest::<Point>(cx).head();
18864        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18865        let blame_entry = blame
18866            .update(cx, |blame, cx| {
18867                blame
18868                    .blame_for_rows(
18869                        &[RowInfo {
18870                            buffer_id: Some(buffer.remote_id()),
18871                            buffer_row: Some(point.row),
18872                            ..Default::default()
18873                        }],
18874                        cx,
18875                    )
18876                    .next()
18877            })
18878            .flatten()?;
18879        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18880        let repo = blame.read(cx).repository(cx)?;
18881        let workspace = self.workspace()?.downgrade();
18882        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18883        None
18884    }
18885
18886    pub fn git_blame_inline_enabled(&self) -> bool {
18887        self.git_blame_inline_enabled
18888    }
18889
18890    pub fn toggle_selection_menu(
18891        &mut self,
18892        _: &ToggleSelectionMenu,
18893        _: &mut Window,
18894        cx: &mut Context<Self>,
18895    ) {
18896        self.show_selection_menu = self
18897            .show_selection_menu
18898            .map(|show_selections_menu| !show_selections_menu)
18899            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18900
18901        cx.notify();
18902    }
18903
18904    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18905        self.show_selection_menu
18906            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18907    }
18908
18909    fn start_git_blame(
18910        &mut self,
18911        user_triggered: bool,
18912        window: &mut Window,
18913        cx: &mut Context<Self>,
18914    ) {
18915        if let Some(project) = self.project.as_ref() {
18916            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18917                return;
18918            };
18919
18920            if buffer.read(cx).file().is_none() {
18921                return;
18922            }
18923
18924            let focused = self.focus_handle(cx).contains_focused(window, cx);
18925
18926            let project = project.clone();
18927            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18928            self.blame_subscription =
18929                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18930            self.blame = Some(blame);
18931        }
18932    }
18933
18934    fn toggle_git_blame_inline_internal(
18935        &mut self,
18936        user_triggered: bool,
18937        window: &mut Window,
18938        cx: &mut Context<Self>,
18939    ) {
18940        if self.git_blame_inline_enabled {
18941            self.git_blame_inline_enabled = false;
18942            self.show_git_blame_inline = false;
18943            self.show_git_blame_inline_delay_task.take();
18944        } else {
18945            self.git_blame_inline_enabled = true;
18946            self.start_git_blame_inline(user_triggered, window, cx);
18947        }
18948
18949        cx.notify();
18950    }
18951
18952    fn start_git_blame_inline(
18953        &mut self,
18954        user_triggered: bool,
18955        window: &mut Window,
18956        cx: &mut Context<Self>,
18957    ) {
18958        self.start_git_blame(user_triggered, window, cx);
18959
18960        if ProjectSettings::get_global(cx)
18961            .git
18962            .inline_blame_delay()
18963            .is_some()
18964        {
18965            self.start_inline_blame_timer(window, cx);
18966        } else {
18967            self.show_git_blame_inline = true
18968        }
18969    }
18970
18971    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18972        self.blame.as_ref()
18973    }
18974
18975    pub fn show_git_blame_gutter(&self) -> bool {
18976        self.show_git_blame_gutter
18977    }
18978
18979    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
18980        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
18981    }
18982
18983    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
18984        self.show_git_blame_inline
18985            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
18986            && !self.newest_selection_head_on_empty_line(cx)
18987            && self.has_blame_entries(cx)
18988    }
18989
18990    fn has_blame_entries(&self, cx: &App) -> bool {
18991        self.blame()
18992            .map_or(false, |blame| blame.read(cx).has_generated_entries())
18993    }
18994
18995    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
18996        let cursor_anchor = self.selections.newest_anchor().head();
18997
18998        let snapshot = self.buffer.read(cx).snapshot(cx);
18999        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19000
19001        snapshot.line_len(buffer_row) == 0
19002    }
19003
19004    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19005        let buffer_and_selection = maybe!({
19006            let selection = self.selections.newest::<Point>(cx);
19007            let selection_range = selection.range();
19008
19009            let multi_buffer = self.buffer().read(cx);
19010            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19011            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19012
19013            let (buffer, range, _) = if selection.reversed {
19014                buffer_ranges.first()
19015            } else {
19016                buffer_ranges.last()
19017            }?;
19018
19019            let selection = text::ToPoint::to_point(&range.start, &buffer).row
19020                ..text::ToPoint::to_point(&range.end, &buffer).row;
19021            Some((
19022                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
19023                selection,
19024            ))
19025        });
19026
19027        let Some((buffer, selection)) = buffer_and_selection else {
19028            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19029        };
19030
19031        let Some(project) = self.project.as_ref() else {
19032            return Task::ready(Err(anyhow!("editor does not have project")));
19033        };
19034
19035        project.update(cx, |project, cx| {
19036            project.get_permalink_to_line(&buffer, selection, cx)
19037        })
19038    }
19039
19040    pub fn copy_permalink_to_line(
19041        &mut self,
19042        _: &CopyPermalinkToLine,
19043        window: &mut Window,
19044        cx: &mut Context<Self>,
19045    ) {
19046        let permalink_task = self.get_permalink_to_line(cx);
19047        let workspace = self.workspace();
19048
19049        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19050            Ok(permalink) => {
19051                cx.update(|_, cx| {
19052                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19053                })
19054                .ok();
19055            }
19056            Err(err) => {
19057                let message = format!("Failed to copy permalink: {err}");
19058
19059                anyhow::Result::<()>::Err(err).log_err();
19060
19061                if let Some(workspace) = workspace {
19062                    workspace
19063                        .update_in(cx, |workspace, _, cx| {
19064                            struct CopyPermalinkToLine;
19065
19066                            workspace.show_toast(
19067                                Toast::new(
19068                                    NotificationId::unique::<CopyPermalinkToLine>(),
19069                                    message,
19070                                ),
19071                                cx,
19072                            )
19073                        })
19074                        .ok();
19075                }
19076            }
19077        })
19078        .detach();
19079    }
19080
19081    pub fn copy_file_location(
19082        &mut self,
19083        _: &CopyFileLocation,
19084        _: &mut Window,
19085        cx: &mut Context<Self>,
19086    ) {
19087        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19088        if let Some(file) = self.target_file(cx) {
19089            if let Some(path) = file.path().to_str() {
19090                cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19091            }
19092        }
19093    }
19094
19095    pub fn open_permalink_to_line(
19096        &mut self,
19097        _: &OpenPermalinkToLine,
19098        window: &mut Window,
19099        cx: &mut Context<Self>,
19100    ) {
19101        let permalink_task = self.get_permalink_to_line(cx);
19102        let workspace = self.workspace();
19103
19104        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19105            Ok(permalink) => {
19106                cx.update(|_, cx| {
19107                    cx.open_url(permalink.as_ref());
19108                })
19109                .ok();
19110            }
19111            Err(err) => {
19112                let message = format!("Failed to open permalink: {err}");
19113
19114                anyhow::Result::<()>::Err(err).log_err();
19115
19116                if let Some(workspace) = workspace {
19117                    workspace
19118                        .update(cx, |workspace, cx| {
19119                            struct OpenPermalinkToLine;
19120
19121                            workspace.show_toast(
19122                                Toast::new(
19123                                    NotificationId::unique::<OpenPermalinkToLine>(),
19124                                    message,
19125                                ),
19126                                cx,
19127                            )
19128                        })
19129                        .ok();
19130                }
19131            }
19132        })
19133        .detach();
19134    }
19135
19136    pub fn insert_uuid_v4(
19137        &mut self,
19138        _: &InsertUuidV4,
19139        window: &mut Window,
19140        cx: &mut Context<Self>,
19141    ) {
19142        self.insert_uuid(UuidVersion::V4, window, cx);
19143    }
19144
19145    pub fn insert_uuid_v7(
19146        &mut self,
19147        _: &InsertUuidV7,
19148        window: &mut Window,
19149        cx: &mut Context<Self>,
19150    ) {
19151        self.insert_uuid(UuidVersion::V7, window, cx);
19152    }
19153
19154    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19155        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19156        self.transact(window, cx, |this, window, cx| {
19157            let edits = this
19158                .selections
19159                .all::<Point>(cx)
19160                .into_iter()
19161                .map(|selection| {
19162                    let uuid = match version {
19163                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19164                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19165                    };
19166
19167                    (selection.range(), uuid.to_string())
19168                });
19169            this.edit(edits, cx);
19170            this.refresh_edit_prediction(true, false, window, cx);
19171        });
19172    }
19173
19174    pub fn open_selections_in_multibuffer(
19175        &mut self,
19176        _: &OpenSelectionsInMultibuffer,
19177        window: &mut Window,
19178        cx: &mut Context<Self>,
19179    ) {
19180        let multibuffer = self.buffer.read(cx);
19181
19182        let Some(buffer) = multibuffer.as_singleton() else {
19183            return;
19184        };
19185
19186        let Some(workspace) = self.workspace() else {
19187            return;
19188        };
19189
19190        let title = multibuffer.title(cx).to_string();
19191
19192        let locations = self
19193            .selections
19194            .all_anchors(cx)
19195            .into_iter()
19196            .map(|selection| Location {
19197                buffer: buffer.clone(),
19198                range: selection.start.text_anchor..selection.end.text_anchor,
19199            })
19200            .collect::<Vec<_>>();
19201
19202        cx.spawn_in(window, async move |_, cx| {
19203            workspace.update_in(cx, |workspace, window, cx| {
19204                Self::open_locations_in_multibuffer(
19205                    workspace,
19206                    locations,
19207                    format!("Selections for '{title}'"),
19208                    false,
19209                    MultibufferSelectionMode::All,
19210                    window,
19211                    cx,
19212                );
19213            })
19214        })
19215        .detach();
19216    }
19217
19218    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19219    /// last highlight added will be used.
19220    ///
19221    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19222    pub fn highlight_rows<T: 'static>(
19223        &mut self,
19224        range: Range<Anchor>,
19225        color: Hsla,
19226        options: RowHighlightOptions,
19227        cx: &mut Context<Self>,
19228    ) {
19229        let snapshot = self.buffer().read(cx).snapshot(cx);
19230        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19231        let ix = row_highlights.binary_search_by(|highlight| {
19232            Ordering::Equal
19233                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19234                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19235        });
19236
19237        if let Err(mut ix) = ix {
19238            let index = post_inc(&mut self.highlight_order);
19239
19240            // If this range intersects with the preceding highlight, then merge it with
19241            // the preceding highlight. Otherwise insert a new highlight.
19242            let mut merged = false;
19243            if ix > 0 {
19244                let prev_highlight = &mut row_highlights[ix - 1];
19245                if prev_highlight
19246                    .range
19247                    .end
19248                    .cmp(&range.start, &snapshot)
19249                    .is_ge()
19250                {
19251                    ix -= 1;
19252                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19253                        prev_highlight.range.end = range.end;
19254                    }
19255                    merged = true;
19256                    prev_highlight.index = index;
19257                    prev_highlight.color = color;
19258                    prev_highlight.options = options;
19259                }
19260            }
19261
19262            if !merged {
19263                row_highlights.insert(
19264                    ix,
19265                    RowHighlight {
19266                        range: range.clone(),
19267                        index,
19268                        color,
19269                        options,
19270                        type_id: TypeId::of::<T>(),
19271                    },
19272                );
19273            }
19274
19275            // If any of the following highlights intersect with this one, merge them.
19276            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19277                let highlight = &row_highlights[ix];
19278                if next_highlight
19279                    .range
19280                    .start
19281                    .cmp(&highlight.range.end, &snapshot)
19282                    .is_le()
19283                {
19284                    if next_highlight
19285                        .range
19286                        .end
19287                        .cmp(&highlight.range.end, &snapshot)
19288                        .is_gt()
19289                    {
19290                        row_highlights[ix].range.end = next_highlight.range.end;
19291                    }
19292                    row_highlights.remove(ix + 1);
19293                } else {
19294                    break;
19295                }
19296            }
19297        }
19298    }
19299
19300    /// Remove any highlighted row ranges of the given type that intersect the
19301    /// given ranges.
19302    pub fn remove_highlighted_rows<T: 'static>(
19303        &mut self,
19304        ranges_to_remove: Vec<Range<Anchor>>,
19305        cx: &mut Context<Self>,
19306    ) {
19307        let snapshot = self.buffer().read(cx).snapshot(cx);
19308        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19309        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19310        row_highlights.retain(|highlight| {
19311            while let Some(range_to_remove) = ranges_to_remove.peek() {
19312                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19313                    Ordering::Less | Ordering::Equal => {
19314                        ranges_to_remove.next();
19315                    }
19316                    Ordering::Greater => {
19317                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19318                            Ordering::Less | Ordering::Equal => {
19319                                return false;
19320                            }
19321                            Ordering::Greater => break,
19322                        }
19323                    }
19324                }
19325            }
19326
19327            true
19328        })
19329    }
19330
19331    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19332    pub fn clear_row_highlights<T: 'static>(&mut self) {
19333        self.highlighted_rows.remove(&TypeId::of::<T>());
19334    }
19335
19336    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19337    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19338        self.highlighted_rows
19339            .get(&TypeId::of::<T>())
19340            .map_or(&[] as &[_], |vec| vec.as_slice())
19341            .iter()
19342            .map(|highlight| (highlight.range.clone(), highlight.color))
19343    }
19344
19345    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19346    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19347    /// Allows to ignore certain kinds of highlights.
19348    pub fn highlighted_display_rows(
19349        &self,
19350        window: &mut Window,
19351        cx: &mut App,
19352    ) -> BTreeMap<DisplayRow, LineHighlight> {
19353        let snapshot = self.snapshot(window, cx);
19354        let mut used_highlight_orders = HashMap::default();
19355        self.highlighted_rows
19356            .iter()
19357            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19358            .fold(
19359                BTreeMap::<DisplayRow, LineHighlight>::new(),
19360                |mut unique_rows, highlight| {
19361                    let start = highlight.range.start.to_display_point(&snapshot);
19362                    let end = highlight.range.end.to_display_point(&snapshot);
19363                    let start_row = start.row().0;
19364                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19365                        && end.column() == 0
19366                    {
19367                        end.row().0.saturating_sub(1)
19368                    } else {
19369                        end.row().0
19370                    };
19371                    for row in start_row..=end_row {
19372                        let used_index =
19373                            used_highlight_orders.entry(row).or_insert(highlight.index);
19374                        if highlight.index >= *used_index {
19375                            *used_index = highlight.index;
19376                            unique_rows.insert(
19377                                DisplayRow(row),
19378                                LineHighlight {
19379                                    include_gutter: highlight.options.include_gutter,
19380                                    border: None,
19381                                    background: highlight.color.into(),
19382                                    type_id: Some(highlight.type_id),
19383                                },
19384                            );
19385                        }
19386                    }
19387                    unique_rows
19388                },
19389            )
19390    }
19391
19392    pub fn highlighted_display_row_for_autoscroll(
19393        &self,
19394        snapshot: &DisplaySnapshot,
19395    ) -> Option<DisplayRow> {
19396        self.highlighted_rows
19397            .values()
19398            .flat_map(|highlighted_rows| highlighted_rows.iter())
19399            .filter_map(|highlight| {
19400                if highlight.options.autoscroll {
19401                    Some(highlight.range.start.to_display_point(snapshot).row())
19402                } else {
19403                    None
19404                }
19405            })
19406            .min()
19407    }
19408
19409    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19410        self.highlight_background::<SearchWithinRange>(
19411            ranges,
19412            |colors| colors.colors().editor_document_highlight_read_background,
19413            cx,
19414        )
19415    }
19416
19417    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19418        self.breadcrumb_header = Some(new_header);
19419    }
19420
19421    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19422        self.clear_background_highlights::<SearchWithinRange>(cx);
19423    }
19424
19425    pub fn highlight_background<T: 'static>(
19426        &mut self,
19427        ranges: &[Range<Anchor>],
19428        color_fetcher: fn(&Theme) -> Hsla,
19429        cx: &mut Context<Self>,
19430    ) {
19431        self.background_highlights.insert(
19432            HighlightKey::Type(TypeId::of::<T>()),
19433            (color_fetcher, Arc::from(ranges)),
19434        );
19435        self.scrollbar_marker_state.dirty = true;
19436        cx.notify();
19437    }
19438
19439    pub fn highlight_background_key<T: 'static>(
19440        &mut self,
19441        key: usize,
19442        ranges: &[Range<Anchor>],
19443        color_fetcher: fn(&Theme) -> Hsla,
19444        cx: &mut Context<Self>,
19445    ) {
19446        self.background_highlights.insert(
19447            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19448            (color_fetcher, Arc::from(ranges)),
19449        );
19450        self.scrollbar_marker_state.dirty = true;
19451        cx.notify();
19452    }
19453
19454    pub fn clear_background_highlights<T: 'static>(
19455        &mut self,
19456        cx: &mut Context<Self>,
19457    ) -> Option<BackgroundHighlight> {
19458        let text_highlights = self
19459            .background_highlights
19460            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19461        if !text_highlights.1.is_empty() {
19462            self.scrollbar_marker_state.dirty = true;
19463            cx.notify();
19464        }
19465        Some(text_highlights)
19466    }
19467
19468    pub fn highlight_gutter<T: 'static>(
19469        &mut self,
19470        ranges: impl Into<Vec<Range<Anchor>>>,
19471        color_fetcher: fn(&App) -> Hsla,
19472        cx: &mut Context<Self>,
19473    ) {
19474        self.gutter_highlights
19475            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19476        cx.notify();
19477    }
19478
19479    pub fn clear_gutter_highlights<T: 'static>(
19480        &mut self,
19481        cx: &mut Context<Self>,
19482    ) -> Option<GutterHighlight> {
19483        cx.notify();
19484        self.gutter_highlights.remove(&TypeId::of::<T>())
19485    }
19486
19487    pub fn insert_gutter_highlight<T: 'static>(
19488        &mut self,
19489        range: Range<Anchor>,
19490        color_fetcher: fn(&App) -> Hsla,
19491        cx: &mut Context<Self>,
19492    ) {
19493        let snapshot = self.buffer().read(cx).snapshot(cx);
19494        let mut highlights = self
19495            .gutter_highlights
19496            .remove(&TypeId::of::<T>())
19497            .map(|(_, highlights)| highlights)
19498            .unwrap_or_default();
19499        let ix = highlights.binary_search_by(|highlight| {
19500            Ordering::Equal
19501                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19502                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19503        });
19504        if let Err(ix) = ix {
19505            highlights.insert(ix, range);
19506        }
19507        self.gutter_highlights
19508            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19509    }
19510
19511    pub fn remove_gutter_highlights<T: 'static>(
19512        &mut self,
19513        ranges_to_remove: Vec<Range<Anchor>>,
19514        cx: &mut Context<Self>,
19515    ) {
19516        let snapshot = self.buffer().read(cx).snapshot(cx);
19517        let Some((color_fetcher, mut gutter_highlights)) =
19518            self.gutter_highlights.remove(&TypeId::of::<T>())
19519        else {
19520            return;
19521        };
19522        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19523        gutter_highlights.retain(|highlight| {
19524            while let Some(range_to_remove) = ranges_to_remove.peek() {
19525                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19526                    Ordering::Less | Ordering::Equal => {
19527                        ranges_to_remove.next();
19528                    }
19529                    Ordering::Greater => {
19530                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19531                            Ordering::Less | Ordering::Equal => {
19532                                return false;
19533                            }
19534                            Ordering::Greater => break,
19535                        }
19536                    }
19537                }
19538            }
19539
19540            true
19541        });
19542        self.gutter_highlights
19543            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19544    }
19545
19546    #[cfg(feature = "test-support")]
19547    pub fn all_text_highlights(
19548        &self,
19549        window: &mut Window,
19550        cx: &mut Context<Self>,
19551    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19552        let snapshot = self.snapshot(window, cx);
19553        self.display_map.update(cx, |display_map, _| {
19554            display_map
19555                .all_text_highlights()
19556                .map(|highlight| {
19557                    let (style, ranges) = highlight.as_ref();
19558                    (
19559                        *style,
19560                        ranges
19561                            .iter()
19562                            .map(|range| range.clone().to_display_points(&snapshot))
19563                            .collect(),
19564                    )
19565                })
19566                .collect()
19567        })
19568    }
19569
19570    #[cfg(feature = "test-support")]
19571    pub fn all_text_background_highlights(
19572        &self,
19573        window: &mut Window,
19574        cx: &mut Context<Self>,
19575    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19576        let snapshot = self.snapshot(window, cx);
19577        let buffer = &snapshot.buffer_snapshot;
19578        let start = buffer.anchor_before(0);
19579        let end = buffer.anchor_after(buffer.len());
19580        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19581    }
19582
19583    #[cfg(feature = "test-support")]
19584    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19585        let snapshot = self.buffer().read(cx).snapshot(cx);
19586
19587        let highlights = self
19588            .background_highlights
19589            .get(&HighlightKey::Type(TypeId::of::<
19590                items::BufferSearchHighlights,
19591            >()));
19592
19593        if let Some((_color, ranges)) = highlights {
19594            ranges
19595                .iter()
19596                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19597                .collect_vec()
19598        } else {
19599            vec![]
19600        }
19601    }
19602
19603    fn document_highlights_for_position<'a>(
19604        &'a self,
19605        position: Anchor,
19606        buffer: &'a MultiBufferSnapshot,
19607    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19608        let read_highlights = self
19609            .background_highlights
19610            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19611            .map(|h| &h.1);
19612        let write_highlights = self
19613            .background_highlights
19614            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19615            .map(|h| &h.1);
19616        let left_position = position.bias_left(buffer);
19617        let right_position = position.bias_right(buffer);
19618        read_highlights
19619            .into_iter()
19620            .chain(write_highlights)
19621            .flat_map(move |ranges| {
19622                let start_ix = match ranges.binary_search_by(|probe| {
19623                    let cmp = probe.end.cmp(&left_position, buffer);
19624                    if cmp.is_ge() {
19625                        Ordering::Greater
19626                    } else {
19627                        Ordering::Less
19628                    }
19629                }) {
19630                    Ok(i) | Err(i) => i,
19631                };
19632
19633                ranges[start_ix..]
19634                    .iter()
19635                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19636            })
19637    }
19638
19639    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19640        self.background_highlights
19641            .get(&HighlightKey::Type(TypeId::of::<T>()))
19642            .map_or(false, |(_, highlights)| !highlights.is_empty())
19643    }
19644
19645    pub fn background_highlights_in_range(
19646        &self,
19647        search_range: Range<Anchor>,
19648        display_snapshot: &DisplaySnapshot,
19649        theme: &Theme,
19650    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19651        let mut results = Vec::new();
19652        for (color_fetcher, ranges) in self.background_highlights.values() {
19653            let color = color_fetcher(theme);
19654            let start_ix = match ranges.binary_search_by(|probe| {
19655                let cmp = probe
19656                    .end
19657                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19658                if cmp.is_gt() {
19659                    Ordering::Greater
19660                } else {
19661                    Ordering::Less
19662                }
19663            }) {
19664                Ok(i) | Err(i) => i,
19665            };
19666            for range in &ranges[start_ix..] {
19667                if range
19668                    .start
19669                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19670                    .is_ge()
19671                {
19672                    break;
19673                }
19674
19675                let start = range.start.to_display_point(display_snapshot);
19676                let end = range.end.to_display_point(display_snapshot);
19677                results.push((start..end, color))
19678            }
19679        }
19680        results
19681    }
19682
19683    pub fn background_highlight_row_ranges<T: 'static>(
19684        &self,
19685        search_range: Range<Anchor>,
19686        display_snapshot: &DisplaySnapshot,
19687        count: usize,
19688    ) -> Vec<RangeInclusive<DisplayPoint>> {
19689        let mut results = Vec::new();
19690        let Some((_, ranges)) = self
19691            .background_highlights
19692            .get(&HighlightKey::Type(TypeId::of::<T>()))
19693        else {
19694            return vec![];
19695        };
19696
19697        let start_ix = match ranges.binary_search_by(|probe| {
19698            let cmp = probe
19699                .end
19700                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19701            if cmp.is_gt() {
19702                Ordering::Greater
19703            } else {
19704                Ordering::Less
19705            }
19706        }) {
19707            Ok(i) | Err(i) => i,
19708        };
19709        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19710            if let (Some(start_display), Some(end_display)) = (start, end) {
19711                results.push(
19712                    start_display.to_display_point(display_snapshot)
19713                        ..=end_display.to_display_point(display_snapshot),
19714                );
19715            }
19716        };
19717        let mut start_row: Option<Point> = None;
19718        let mut end_row: Option<Point> = None;
19719        if ranges.len() > count {
19720            return Vec::new();
19721        }
19722        for range in &ranges[start_ix..] {
19723            if range
19724                .start
19725                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19726                .is_ge()
19727            {
19728                break;
19729            }
19730            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19731            if let Some(current_row) = &end_row {
19732                if end.row == current_row.row {
19733                    continue;
19734                }
19735            }
19736            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19737            if start_row.is_none() {
19738                assert_eq!(end_row, None);
19739                start_row = Some(start);
19740                end_row = Some(end);
19741                continue;
19742            }
19743            if let Some(current_end) = end_row.as_mut() {
19744                if start.row > current_end.row + 1 {
19745                    push_region(start_row, end_row);
19746                    start_row = Some(start);
19747                    end_row = Some(end);
19748                } else {
19749                    // Merge two hunks.
19750                    *current_end = end;
19751                }
19752            } else {
19753                unreachable!();
19754            }
19755        }
19756        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19757        push_region(start_row, end_row);
19758        results
19759    }
19760
19761    pub fn gutter_highlights_in_range(
19762        &self,
19763        search_range: Range<Anchor>,
19764        display_snapshot: &DisplaySnapshot,
19765        cx: &App,
19766    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19767        let mut results = Vec::new();
19768        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19769            let color = color_fetcher(cx);
19770            let start_ix = match ranges.binary_search_by(|probe| {
19771                let cmp = probe
19772                    .end
19773                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19774                if cmp.is_gt() {
19775                    Ordering::Greater
19776                } else {
19777                    Ordering::Less
19778                }
19779            }) {
19780                Ok(i) | Err(i) => i,
19781            };
19782            for range in &ranges[start_ix..] {
19783                if range
19784                    .start
19785                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19786                    .is_ge()
19787                {
19788                    break;
19789                }
19790
19791                let start = range.start.to_display_point(display_snapshot);
19792                let end = range.end.to_display_point(display_snapshot);
19793                results.push((start..end, color))
19794            }
19795        }
19796        results
19797    }
19798
19799    /// Get the text ranges corresponding to the redaction query
19800    pub fn redacted_ranges(
19801        &self,
19802        search_range: Range<Anchor>,
19803        display_snapshot: &DisplaySnapshot,
19804        cx: &App,
19805    ) -> Vec<Range<DisplayPoint>> {
19806        display_snapshot
19807            .buffer_snapshot
19808            .redacted_ranges(search_range, |file| {
19809                if let Some(file) = file {
19810                    file.is_private()
19811                        && EditorSettings::get(
19812                            Some(SettingsLocation {
19813                                worktree_id: file.worktree_id(cx),
19814                                path: file.path().as_ref(),
19815                            }),
19816                            cx,
19817                        )
19818                        .redact_private_values
19819                } else {
19820                    false
19821                }
19822            })
19823            .map(|range| {
19824                range.start.to_display_point(display_snapshot)
19825                    ..range.end.to_display_point(display_snapshot)
19826            })
19827            .collect()
19828    }
19829
19830    pub fn highlight_text_key<T: 'static>(
19831        &mut self,
19832        key: usize,
19833        ranges: Vec<Range<Anchor>>,
19834        style: HighlightStyle,
19835        cx: &mut Context<Self>,
19836    ) {
19837        self.display_map.update(cx, |map, _| {
19838            map.highlight_text(
19839                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19840                ranges,
19841                style,
19842            );
19843        });
19844        cx.notify();
19845    }
19846
19847    pub fn highlight_text<T: 'static>(
19848        &mut self,
19849        ranges: Vec<Range<Anchor>>,
19850        style: HighlightStyle,
19851        cx: &mut Context<Self>,
19852    ) {
19853        self.display_map.update(cx, |map, _| {
19854            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19855        });
19856        cx.notify();
19857    }
19858
19859    pub(crate) fn highlight_inlays<T: 'static>(
19860        &mut self,
19861        highlights: Vec<InlayHighlight>,
19862        style: HighlightStyle,
19863        cx: &mut Context<Self>,
19864    ) {
19865        self.display_map.update(cx, |map, _| {
19866            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19867        });
19868        cx.notify();
19869    }
19870
19871    pub fn text_highlights<'a, T: 'static>(
19872        &'a self,
19873        cx: &'a App,
19874    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19875        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19876    }
19877
19878    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19879        let cleared = self
19880            .display_map
19881            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19882        if cleared {
19883            cx.notify();
19884        }
19885    }
19886
19887    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19888        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19889            && self.focus_handle.is_focused(window)
19890    }
19891
19892    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19893        self.show_cursor_when_unfocused = is_enabled;
19894        cx.notify();
19895    }
19896
19897    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19898        cx.notify();
19899    }
19900
19901    fn on_debug_session_event(
19902        &mut self,
19903        _session: Entity<Session>,
19904        event: &SessionEvent,
19905        cx: &mut Context<Self>,
19906    ) {
19907        match event {
19908            SessionEvent::InvalidateInlineValue => {
19909                self.refresh_inline_values(cx);
19910            }
19911            _ => {}
19912        }
19913    }
19914
19915    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19916        let Some(project) = self.project.clone() else {
19917            return;
19918        };
19919
19920        if !self.inline_value_cache.enabled {
19921            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19922            self.splice_inlays(&inlays, Vec::new(), cx);
19923            return;
19924        }
19925
19926        let current_execution_position = self
19927            .highlighted_rows
19928            .get(&TypeId::of::<ActiveDebugLine>())
19929            .and_then(|lines| lines.last().map(|line| line.range.end));
19930
19931        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19932            let inline_values = editor
19933                .update(cx, |editor, cx| {
19934                    let Some(current_execution_position) = current_execution_position else {
19935                        return Some(Task::ready(Ok(Vec::new())));
19936                    };
19937
19938                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19939                        let snapshot = buffer.snapshot(cx);
19940
19941                        let excerpt = snapshot.excerpt_containing(
19942                            current_execution_position..current_execution_position,
19943                        )?;
19944
19945                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19946                    })?;
19947
19948                    let range =
19949                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19950
19951                    project.inline_values(buffer, range, cx)
19952                })
19953                .ok()
19954                .flatten()?
19955                .await
19956                .context("refreshing debugger inlays")
19957                .log_err()?;
19958
19959            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19960
19961            for (buffer_id, inline_value) in inline_values
19962                .into_iter()
19963                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19964            {
19965                buffer_inline_values
19966                    .entry(buffer_id)
19967                    .or_default()
19968                    .push(inline_value);
19969            }
19970
19971            editor
19972                .update(cx, |editor, cx| {
19973                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19974                    let mut new_inlays = Vec::default();
19975
19976                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19977                        let buffer_id = buffer_snapshot.remote_id();
19978                        buffer_inline_values
19979                            .get(&buffer_id)
19980                            .into_iter()
19981                            .flatten()
19982                            .for_each(|hint| {
19983                                let inlay = Inlay::debugger(
19984                                    post_inc(&mut editor.next_inlay_id),
19985                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
19986                                    hint.text(),
19987                                );
19988                                if !inlay.text.chars().contains(&'\n') {
19989                                    new_inlays.push(inlay);
19990                                }
19991                            });
19992                    }
19993
19994                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
19995                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
19996
19997                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
19998                })
19999                .ok()?;
20000            Some(())
20001        });
20002    }
20003
20004    fn on_buffer_event(
20005        &mut self,
20006        multibuffer: &Entity<MultiBuffer>,
20007        event: &multi_buffer::Event,
20008        window: &mut Window,
20009        cx: &mut Context<Self>,
20010    ) {
20011        match event {
20012            multi_buffer::Event::Edited {
20013                singleton_buffer_edited,
20014                edited_buffer,
20015            } => {
20016                self.scrollbar_marker_state.dirty = true;
20017                self.active_indent_guides_state.dirty = true;
20018                self.refresh_active_diagnostics(cx);
20019                self.refresh_code_actions(window, cx);
20020                self.refresh_selected_text_highlights(true, window, cx);
20021                self.refresh_single_line_folds(window, cx);
20022                refresh_matching_bracket_highlights(self, window, cx);
20023                if self.has_active_edit_prediction() {
20024                    self.update_visible_edit_prediction(window, cx);
20025                }
20026                if let Some(project) = self.project.as_ref() {
20027                    if let Some(edited_buffer) = edited_buffer {
20028                        project.update(cx, |project, cx| {
20029                            self.registered_buffers
20030                                .entry(edited_buffer.read(cx).remote_id())
20031                                .or_insert_with(|| {
20032                                    project
20033                                        .register_buffer_with_language_servers(&edited_buffer, cx)
20034                                });
20035                        });
20036                    }
20037                }
20038                cx.emit(EditorEvent::BufferEdited);
20039                cx.emit(SearchEvent::MatchesInvalidated);
20040
20041                if let Some(buffer) = edited_buffer {
20042                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20043                }
20044
20045                if *singleton_buffer_edited {
20046                    if let Some(buffer) = edited_buffer {
20047                        if buffer.read(cx).file().is_none() {
20048                            cx.emit(EditorEvent::TitleChanged);
20049                        }
20050                    }
20051                    if let Some(project) = &self.project {
20052                        #[allow(clippy::mutable_key_type)]
20053                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20054                            multibuffer
20055                                .all_buffers()
20056                                .into_iter()
20057                                .filter_map(|buffer| {
20058                                    buffer.update(cx, |buffer, cx| {
20059                                        let language = buffer.language()?;
20060                                        let should_discard = project.update(cx, |project, cx| {
20061                                            project.is_local()
20062                                                && !project.has_language_servers_for(buffer, cx)
20063                                        });
20064                                        should_discard.not().then_some(language.clone())
20065                                    })
20066                                })
20067                                .collect::<HashSet<_>>()
20068                        });
20069                        if !languages_affected.is_empty() {
20070                            self.refresh_inlay_hints(
20071                                InlayHintRefreshReason::BufferEdited(languages_affected),
20072                                cx,
20073                            );
20074                        }
20075                    }
20076                }
20077
20078                let Some(project) = &self.project else { return };
20079                let (telemetry, is_via_ssh) = {
20080                    let project = project.read(cx);
20081                    let telemetry = project.client().telemetry().clone();
20082                    let is_via_ssh = project.is_via_ssh();
20083                    (telemetry, is_via_ssh)
20084                };
20085                refresh_linked_ranges(self, window, cx);
20086                telemetry.log_edit_event("editor", is_via_ssh);
20087            }
20088            multi_buffer::Event::ExcerptsAdded {
20089                buffer,
20090                predecessor,
20091                excerpts,
20092            } => {
20093                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20094                let buffer_id = buffer.read(cx).remote_id();
20095                if self.buffer.read(cx).diff_for(buffer_id).is_none() {
20096                    if let Some(project) = &self.project {
20097                        update_uncommitted_diff_for_buffer(
20098                            cx.entity(),
20099                            project,
20100                            [buffer.clone()],
20101                            self.buffer.clone(),
20102                            cx,
20103                        )
20104                        .detach();
20105                    }
20106                }
20107                self.update_lsp_data(false, Some(buffer_id), window, cx);
20108                cx.emit(EditorEvent::ExcerptsAdded {
20109                    buffer: buffer.clone(),
20110                    predecessor: *predecessor,
20111                    excerpts: excerpts.clone(),
20112                });
20113                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20114            }
20115            multi_buffer::Event::ExcerptsRemoved {
20116                ids,
20117                removed_buffer_ids,
20118            } => {
20119                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20120                let buffer = self.buffer.read(cx);
20121                self.registered_buffers
20122                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20123                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20124                cx.emit(EditorEvent::ExcerptsRemoved {
20125                    ids: ids.clone(),
20126                    removed_buffer_ids: removed_buffer_ids.clone(),
20127                });
20128            }
20129            multi_buffer::Event::ExcerptsEdited {
20130                excerpt_ids,
20131                buffer_ids,
20132            } => {
20133                self.display_map.update(cx, |map, cx| {
20134                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20135                });
20136                cx.emit(EditorEvent::ExcerptsEdited {
20137                    ids: excerpt_ids.clone(),
20138                });
20139            }
20140            multi_buffer::Event::ExcerptsExpanded { ids } => {
20141                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20142                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20143            }
20144            multi_buffer::Event::Reparsed(buffer_id) => {
20145                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20146                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20147
20148                cx.emit(EditorEvent::Reparsed(*buffer_id));
20149            }
20150            multi_buffer::Event::DiffHunksToggled => {
20151                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20152            }
20153            multi_buffer::Event::LanguageChanged(buffer_id) => {
20154                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20155                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20156                cx.emit(EditorEvent::Reparsed(*buffer_id));
20157                cx.notify();
20158            }
20159            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20160            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20161            multi_buffer::Event::FileHandleChanged
20162            | multi_buffer::Event::Reloaded
20163            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20164            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20165            multi_buffer::Event::DiagnosticsUpdated => {
20166                self.update_diagnostics_state(window, cx);
20167            }
20168            _ => {}
20169        };
20170    }
20171
20172    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20173        if !self.diagnostics_enabled() {
20174            return;
20175        }
20176        self.refresh_active_diagnostics(cx);
20177        self.refresh_inline_diagnostics(true, window, cx);
20178        self.scrollbar_marker_state.dirty = true;
20179        cx.notify();
20180    }
20181
20182    pub fn start_temporary_diff_override(&mut self) {
20183        self.load_diff_task.take();
20184        self.temporary_diff_override = true;
20185    }
20186
20187    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20188        self.temporary_diff_override = false;
20189        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20190        self.buffer.update(cx, |buffer, cx| {
20191            buffer.set_all_diff_hunks_collapsed(cx);
20192        });
20193
20194        if let Some(project) = self.project.clone() {
20195            self.load_diff_task = Some(
20196                update_uncommitted_diff_for_buffer(
20197                    cx.entity(),
20198                    &project,
20199                    self.buffer.read(cx).all_buffers(),
20200                    self.buffer.clone(),
20201                    cx,
20202                )
20203                .shared(),
20204            );
20205        }
20206    }
20207
20208    fn on_display_map_changed(
20209        &mut self,
20210        _: Entity<DisplayMap>,
20211        _: &mut Window,
20212        cx: &mut Context<Self>,
20213    ) {
20214        cx.notify();
20215    }
20216
20217    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20218        if self.diagnostics_enabled() {
20219            let new_severity = EditorSettings::get_global(cx)
20220                .diagnostics_max_severity
20221                .unwrap_or(DiagnosticSeverity::Hint);
20222            self.set_max_diagnostics_severity(new_severity, cx);
20223        }
20224        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20225        self.update_edit_prediction_settings(cx);
20226        self.refresh_edit_prediction(true, false, window, cx);
20227        self.refresh_inline_values(cx);
20228        self.refresh_inlay_hints(
20229            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20230                self.selections.newest_anchor().head(),
20231                &self.buffer.read(cx).snapshot(cx),
20232                cx,
20233            )),
20234            cx,
20235        );
20236
20237        let old_cursor_shape = self.cursor_shape;
20238        let old_show_breadcrumbs = self.show_breadcrumbs;
20239
20240        {
20241            let editor_settings = EditorSettings::get_global(cx);
20242            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20243            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20244            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20245            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20246        }
20247
20248        if old_cursor_shape != self.cursor_shape {
20249            cx.emit(EditorEvent::CursorShapeChanged);
20250        }
20251
20252        if old_show_breadcrumbs != self.show_breadcrumbs {
20253            cx.emit(EditorEvent::BreadcrumbsChanged);
20254        }
20255
20256        let project_settings = ProjectSettings::get_global(cx);
20257        self.serialize_dirty_buffers =
20258            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20259
20260        if self.mode.is_full() {
20261            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20262            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20263            if self.show_inline_diagnostics != show_inline_diagnostics {
20264                self.show_inline_diagnostics = show_inline_diagnostics;
20265                self.refresh_inline_diagnostics(false, window, cx);
20266            }
20267
20268            if self.git_blame_inline_enabled != inline_blame_enabled {
20269                self.toggle_git_blame_inline_internal(false, window, cx);
20270            }
20271
20272            let minimap_settings = EditorSettings::get_global(cx).minimap;
20273            if self.minimap_visibility != MinimapVisibility::Disabled {
20274                if self.minimap_visibility.settings_visibility()
20275                    != minimap_settings.minimap_enabled()
20276                {
20277                    self.set_minimap_visibility(
20278                        MinimapVisibility::for_mode(self.mode(), cx),
20279                        window,
20280                        cx,
20281                    );
20282                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20283                    minimap_entity.update(cx, |minimap_editor, cx| {
20284                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20285                    })
20286                }
20287            }
20288        }
20289
20290        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20291            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20292        }) {
20293            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20294                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20295            }
20296            self.refresh_colors(false, None, window, cx);
20297        }
20298
20299        cx.notify();
20300    }
20301
20302    pub fn set_searchable(&mut self, searchable: bool) {
20303        self.searchable = searchable;
20304    }
20305
20306    pub fn searchable(&self) -> bool {
20307        self.searchable
20308    }
20309
20310    fn open_proposed_changes_editor(
20311        &mut self,
20312        _: &OpenProposedChangesEditor,
20313        window: &mut Window,
20314        cx: &mut Context<Self>,
20315    ) {
20316        let Some(workspace) = self.workspace() else {
20317            cx.propagate();
20318            return;
20319        };
20320
20321        let selections = self.selections.all::<usize>(cx);
20322        let multi_buffer = self.buffer.read(cx);
20323        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20324        let mut new_selections_by_buffer = HashMap::default();
20325        for selection in selections {
20326            for (buffer, range, _) in
20327                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20328            {
20329                let mut range = range.to_point(buffer);
20330                range.start.column = 0;
20331                range.end.column = buffer.line_len(range.end.row);
20332                new_selections_by_buffer
20333                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20334                    .or_insert(Vec::new())
20335                    .push(range)
20336            }
20337        }
20338
20339        let proposed_changes_buffers = new_selections_by_buffer
20340            .into_iter()
20341            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20342            .collect::<Vec<_>>();
20343        let proposed_changes_editor = cx.new(|cx| {
20344            ProposedChangesEditor::new(
20345                "Proposed changes",
20346                proposed_changes_buffers,
20347                self.project.clone(),
20348                window,
20349                cx,
20350            )
20351        });
20352
20353        window.defer(cx, move |window, cx| {
20354            workspace.update(cx, |workspace, cx| {
20355                workspace.active_pane().update(cx, |pane, cx| {
20356                    pane.add_item(
20357                        Box::new(proposed_changes_editor),
20358                        true,
20359                        true,
20360                        None,
20361                        window,
20362                        cx,
20363                    );
20364                });
20365            });
20366        });
20367    }
20368
20369    pub fn open_excerpts_in_split(
20370        &mut self,
20371        _: &OpenExcerptsSplit,
20372        window: &mut Window,
20373        cx: &mut Context<Self>,
20374    ) {
20375        self.open_excerpts_common(None, true, window, cx)
20376    }
20377
20378    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20379        self.open_excerpts_common(None, false, window, cx)
20380    }
20381
20382    fn open_excerpts_common(
20383        &mut self,
20384        jump_data: Option<JumpData>,
20385        split: bool,
20386        window: &mut Window,
20387        cx: &mut Context<Self>,
20388    ) {
20389        let Some(workspace) = self.workspace() else {
20390            cx.propagate();
20391            return;
20392        };
20393
20394        if self.buffer.read(cx).is_singleton() {
20395            cx.propagate();
20396            return;
20397        }
20398
20399        let mut new_selections_by_buffer = HashMap::default();
20400        match &jump_data {
20401            Some(JumpData::MultiBufferPoint {
20402                excerpt_id,
20403                position,
20404                anchor,
20405                line_offset_from_top,
20406            }) => {
20407                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20408                if let Some(buffer) = multi_buffer_snapshot
20409                    .buffer_id_for_excerpt(*excerpt_id)
20410                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20411                {
20412                    let buffer_snapshot = buffer.read(cx).snapshot();
20413                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20414                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20415                    } else {
20416                        buffer_snapshot.clip_point(*position, Bias::Left)
20417                    };
20418                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20419                    new_selections_by_buffer.insert(
20420                        buffer,
20421                        (
20422                            vec![jump_to_offset..jump_to_offset],
20423                            Some(*line_offset_from_top),
20424                        ),
20425                    );
20426                }
20427            }
20428            Some(JumpData::MultiBufferRow {
20429                row,
20430                line_offset_from_top,
20431            }) => {
20432                let point = MultiBufferPoint::new(row.0, 0);
20433                if let Some((buffer, buffer_point, _)) =
20434                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20435                {
20436                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20437                    new_selections_by_buffer
20438                        .entry(buffer)
20439                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20440                        .0
20441                        .push(buffer_offset..buffer_offset)
20442                }
20443            }
20444            None => {
20445                let selections = self.selections.all::<usize>(cx);
20446                let multi_buffer = self.buffer.read(cx);
20447                for selection in selections {
20448                    for (snapshot, range, _, anchor) in multi_buffer
20449                        .snapshot(cx)
20450                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20451                    {
20452                        if let Some(anchor) = anchor {
20453                            // selection is in a deleted hunk
20454                            let Some(buffer_id) = anchor.buffer_id else {
20455                                continue;
20456                            };
20457                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20458                                continue;
20459                            };
20460                            let offset = text::ToOffset::to_offset(
20461                                &anchor.text_anchor,
20462                                &buffer_handle.read(cx).snapshot(),
20463                            );
20464                            let range = offset..offset;
20465                            new_selections_by_buffer
20466                                .entry(buffer_handle)
20467                                .or_insert((Vec::new(), None))
20468                                .0
20469                                .push(range)
20470                        } else {
20471                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20472                            else {
20473                                continue;
20474                            };
20475                            new_selections_by_buffer
20476                                .entry(buffer_handle)
20477                                .or_insert((Vec::new(), None))
20478                                .0
20479                                .push(range)
20480                        }
20481                    }
20482                }
20483            }
20484        }
20485
20486        new_selections_by_buffer
20487            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20488
20489        if new_selections_by_buffer.is_empty() {
20490            return;
20491        }
20492
20493        // We defer the pane interaction because we ourselves are a workspace item
20494        // and activating a new item causes the pane to call a method on us reentrantly,
20495        // which panics if we're on the stack.
20496        window.defer(cx, move |window, cx| {
20497            workspace.update(cx, |workspace, cx| {
20498                let pane = if split {
20499                    workspace.adjacent_pane(window, cx)
20500                } else {
20501                    workspace.active_pane().clone()
20502                };
20503
20504                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20505                    let editor = buffer
20506                        .read(cx)
20507                        .file()
20508                        .is_none()
20509                        .then(|| {
20510                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20511                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20512                            // Instead, we try to activate the existing editor in the pane first.
20513                            let (editor, pane_item_index) =
20514                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20515                                    let editor = item.downcast::<Editor>()?;
20516                                    let singleton_buffer =
20517                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20518                                    if singleton_buffer == buffer {
20519                                        Some((editor, i))
20520                                    } else {
20521                                        None
20522                                    }
20523                                })?;
20524                            pane.update(cx, |pane, cx| {
20525                                pane.activate_item(pane_item_index, true, true, window, cx)
20526                            });
20527                            Some(editor)
20528                        })
20529                        .flatten()
20530                        .unwrap_or_else(|| {
20531                            workspace.open_project_item::<Self>(
20532                                pane.clone(),
20533                                buffer,
20534                                true,
20535                                true,
20536                                window,
20537                                cx,
20538                            )
20539                        });
20540
20541                    editor.update(cx, |editor, cx| {
20542                        let autoscroll = match scroll_offset {
20543                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20544                            None => Autoscroll::newest(),
20545                        };
20546                        let nav_history = editor.nav_history.take();
20547                        editor.change_selections(
20548                            SelectionEffects::scroll(autoscroll),
20549                            window,
20550                            cx,
20551                            |s| {
20552                                s.select_ranges(ranges);
20553                            },
20554                        );
20555                        editor.nav_history = nav_history;
20556                    });
20557                }
20558            })
20559        });
20560    }
20561
20562    // For now, don't allow opening excerpts in buffers that aren't backed by
20563    // regular project files.
20564    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20565        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20566    }
20567
20568    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20569        let snapshot = self.buffer.read(cx).read(cx);
20570        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20571        Some(
20572            ranges
20573                .iter()
20574                .map(move |range| {
20575                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20576                })
20577                .collect(),
20578        )
20579    }
20580
20581    fn selection_replacement_ranges(
20582        &self,
20583        range: Range<OffsetUtf16>,
20584        cx: &mut App,
20585    ) -> Vec<Range<OffsetUtf16>> {
20586        let selections = self.selections.all::<OffsetUtf16>(cx);
20587        let newest_selection = selections
20588            .iter()
20589            .max_by_key(|selection| selection.id)
20590            .unwrap();
20591        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20592        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20593        let snapshot = self.buffer.read(cx).read(cx);
20594        selections
20595            .into_iter()
20596            .map(|mut selection| {
20597                selection.start.0 =
20598                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20599                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20600                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20601                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20602            })
20603            .collect()
20604    }
20605
20606    fn report_editor_event(
20607        &self,
20608        reported_event: ReportEditorEvent,
20609        file_extension: Option<String>,
20610        cx: &App,
20611    ) {
20612        if cfg!(any(test, feature = "test-support")) {
20613            return;
20614        }
20615
20616        let Some(project) = &self.project else { return };
20617
20618        // If None, we are in a file without an extension
20619        let file = self
20620            .buffer
20621            .read(cx)
20622            .as_singleton()
20623            .and_then(|b| b.read(cx).file());
20624        let file_extension = file_extension.or(file
20625            .as_ref()
20626            .and_then(|file| Path::new(file.file_name(cx)).extension())
20627            .and_then(|e| e.to_str())
20628            .map(|a| a.to_string()));
20629
20630        let vim_mode = vim_enabled(cx);
20631
20632        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20633        let copilot_enabled = edit_predictions_provider
20634            == language::language_settings::EditPredictionProvider::Copilot;
20635        let copilot_enabled_for_language = self
20636            .buffer
20637            .read(cx)
20638            .language_settings(cx)
20639            .show_edit_predictions;
20640
20641        let project = project.read(cx);
20642        let event_type = reported_event.event_type();
20643
20644        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
20645            telemetry::event!(
20646                event_type,
20647                type = if auto_saved {"autosave"} else {"manual"},
20648                file_extension,
20649                vim_mode,
20650                copilot_enabled,
20651                copilot_enabled_for_language,
20652                edit_predictions_provider,
20653                is_via_ssh = project.is_via_ssh(),
20654            );
20655        } else {
20656            telemetry::event!(
20657                event_type,
20658                file_extension,
20659                vim_mode,
20660                copilot_enabled,
20661                copilot_enabled_for_language,
20662                edit_predictions_provider,
20663                is_via_ssh = project.is_via_ssh(),
20664            );
20665        };
20666    }
20667
20668    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20669    /// with each line being an array of {text, highlight} objects.
20670    fn copy_highlight_json(
20671        &mut self,
20672        _: &CopyHighlightJson,
20673        window: &mut Window,
20674        cx: &mut Context<Self>,
20675    ) {
20676        #[derive(Serialize)]
20677        struct Chunk<'a> {
20678            text: String,
20679            highlight: Option<&'a str>,
20680        }
20681
20682        let snapshot = self.buffer.read(cx).snapshot(cx);
20683        let range = self
20684            .selected_text_range(false, window, cx)
20685            .and_then(|selection| {
20686                if selection.range.is_empty() {
20687                    None
20688                } else {
20689                    Some(selection.range)
20690                }
20691            })
20692            .unwrap_or_else(|| 0..snapshot.len());
20693
20694        let chunks = snapshot.chunks(range, true);
20695        let mut lines = Vec::new();
20696        let mut line: VecDeque<Chunk> = VecDeque::new();
20697
20698        let Some(style) = self.style.as_ref() else {
20699            return;
20700        };
20701
20702        for chunk in chunks {
20703            let highlight = chunk
20704                .syntax_highlight_id
20705                .and_then(|id| id.name(&style.syntax));
20706            let mut chunk_lines = chunk.text.split('\n').peekable();
20707            while let Some(text) = chunk_lines.next() {
20708                let mut merged_with_last_token = false;
20709                if let Some(last_token) = line.back_mut() {
20710                    if last_token.highlight == highlight {
20711                        last_token.text.push_str(text);
20712                        merged_with_last_token = true;
20713                    }
20714                }
20715
20716                if !merged_with_last_token {
20717                    line.push_back(Chunk {
20718                        text: text.into(),
20719                        highlight,
20720                    });
20721                }
20722
20723                if chunk_lines.peek().is_some() {
20724                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20725                        line.pop_front();
20726                    }
20727                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20728                        line.pop_back();
20729                    }
20730
20731                    lines.push(mem::take(&mut line));
20732                }
20733            }
20734        }
20735
20736        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20737            return;
20738        };
20739        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20740    }
20741
20742    pub fn open_context_menu(
20743        &mut self,
20744        _: &OpenContextMenu,
20745        window: &mut Window,
20746        cx: &mut Context<Self>,
20747    ) {
20748        self.request_autoscroll(Autoscroll::newest(), cx);
20749        let position = self.selections.newest_display(cx).start;
20750        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20751    }
20752
20753    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20754        &self.inlay_hint_cache
20755    }
20756
20757    pub fn replay_insert_event(
20758        &mut self,
20759        text: &str,
20760        relative_utf16_range: Option<Range<isize>>,
20761        window: &mut Window,
20762        cx: &mut Context<Self>,
20763    ) {
20764        if !self.input_enabled {
20765            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20766            return;
20767        }
20768        if let Some(relative_utf16_range) = relative_utf16_range {
20769            let selections = self.selections.all::<OffsetUtf16>(cx);
20770            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20771                let new_ranges = selections.into_iter().map(|range| {
20772                    let start = OffsetUtf16(
20773                        range
20774                            .head()
20775                            .0
20776                            .saturating_add_signed(relative_utf16_range.start),
20777                    );
20778                    let end = OffsetUtf16(
20779                        range
20780                            .head()
20781                            .0
20782                            .saturating_add_signed(relative_utf16_range.end),
20783                    );
20784                    start..end
20785                });
20786                s.select_ranges(new_ranges);
20787            });
20788        }
20789
20790        self.handle_input(text, window, cx);
20791    }
20792
20793    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20794        let Some(provider) = self.semantics_provider.as_ref() else {
20795            return false;
20796        };
20797
20798        let mut supports = false;
20799        self.buffer().update(cx, |this, cx| {
20800            this.for_each_buffer(|buffer| {
20801                supports |= provider.supports_inlay_hints(buffer, cx);
20802            });
20803        });
20804
20805        supports
20806    }
20807
20808    pub fn is_focused(&self, window: &Window) -> bool {
20809        self.focus_handle.is_focused(window)
20810    }
20811
20812    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20813        cx.emit(EditorEvent::Focused);
20814
20815        if let Some(descendant) = self
20816            .last_focused_descendant
20817            .take()
20818            .and_then(|descendant| descendant.upgrade())
20819        {
20820            window.focus(&descendant);
20821        } else {
20822            if let Some(blame) = self.blame.as_ref() {
20823                blame.update(cx, GitBlame::focus)
20824            }
20825
20826            self.blink_manager.update(cx, BlinkManager::enable);
20827            self.show_cursor_names(window, cx);
20828            self.buffer.update(cx, |buffer, cx| {
20829                buffer.finalize_last_transaction(cx);
20830                if self.leader_id.is_none() {
20831                    buffer.set_active_selections(
20832                        &self.selections.disjoint_anchors(),
20833                        self.selections.line_mode,
20834                        self.cursor_shape,
20835                        cx,
20836                    );
20837                }
20838            });
20839        }
20840    }
20841
20842    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20843        cx.emit(EditorEvent::FocusedIn)
20844    }
20845
20846    fn handle_focus_out(
20847        &mut self,
20848        event: FocusOutEvent,
20849        _window: &mut Window,
20850        cx: &mut Context<Self>,
20851    ) {
20852        if event.blurred != self.focus_handle {
20853            self.last_focused_descendant = Some(event.blurred);
20854        }
20855        self.selection_drag_state = SelectionDragState::None;
20856        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20857    }
20858
20859    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20860        self.blink_manager.update(cx, BlinkManager::disable);
20861        self.buffer
20862            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20863
20864        if let Some(blame) = self.blame.as_ref() {
20865            blame.update(cx, GitBlame::blur)
20866        }
20867        if !self.hover_state.focused(window, cx) {
20868            hide_hover(self, cx);
20869        }
20870        if !self
20871            .context_menu
20872            .borrow()
20873            .as_ref()
20874            .is_some_and(|context_menu| context_menu.focused(window, cx))
20875        {
20876            self.hide_context_menu(window, cx);
20877        }
20878        self.discard_edit_prediction(false, cx);
20879        cx.emit(EditorEvent::Blurred);
20880        cx.notify();
20881    }
20882
20883    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20884        let mut pending: String = window
20885            .pending_input_keystrokes()
20886            .into_iter()
20887            .flatten()
20888            .filter_map(|keystroke| {
20889                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20890                    keystroke.key_char.clone()
20891                } else {
20892                    None
20893                }
20894            })
20895            .collect();
20896
20897        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20898            pending = "".to_string();
20899        }
20900
20901        let existing_pending = self
20902            .text_highlights::<PendingInput>(cx)
20903            .map(|(_, ranges)| ranges.iter().cloned().collect::<Vec<_>>());
20904        if existing_pending.is_none() && pending.is_empty() {
20905            return;
20906        }
20907        let transaction =
20908            self.transact(window, cx, |this, window, cx| {
20909                let selections = this.selections.all::<usize>(cx);
20910                let edits = selections
20911                    .iter()
20912                    .map(|selection| (selection.end..selection.end, pending.clone()));
20913                this.edit(edits, cx);
20914                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20915                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20916                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20917                    }));
20918                });
20919                if let Some(existing_ranges) = existing_pending {
20920                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20921                    this.edit(edits, cx);
20922                }
20923            });
20924
20925        let snapshot = self.snapshot(window, cx);
20926        let ranges = self
20927            .selections
20928            .all::<usize>(cx)
20929            .into_iter()
20930            .map(|selection| {
20931                snapshot.buffer_snapshot.anchor_after(selection.end)
20932                    ..snapshot
20933                        .buffer_snapshot
20934                        .anchor_before(selection.end + pending.len())
20935            })
20936            .collect();
20937
20938        if pending.is_empty() {
20939            self.clear_highlights::<PendingInput>(cx);
20940        } else {
20941            self.highlight_text::<PendingInput>(
20942                ranges,
20943                HighlightStyle {
20944                    underline: Some(UnderlineStyle {
20945                        thickness: px(1.),
20946                        color: None,
20947                        wavy: false,
20948                    }),
20949                    ..Default::default()
20950                },
20951                cx,
20952            );
20953        }
20954
20955        self.ime_transaction = self.ime_transaction.or(transaction);
20956        if let Some(transaction) = self.ime_transaction {
20957            self.buffer.update(cx, |buffer, cx| {
20958                buffer.group_until_transaction(transaction, cx);
20959            });
20960        }
20961
20962        if self.text_highlights::<PendingInput>(cx).is_none() {
20963            self.ime_transaction.take();
20964        }
20965    }
20966
20967    pub fn register_action_renderer(
20968        &mut self,
20969        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20970    ) -> Subscription {
20971        let id = self.next_editor_action_id.post_inc();
20972        self.editor_actions
20973            .borrow_mut()
20974            .insert(id, Box::new(listener));
20975
20976        let editor_actions = self.editor_actions.clone();
20977        Subscription::new(move || {
20978            editor_actions.borrow_mut().remove(&id);
20979        })
20980    }
20981
20982    pub fn register_action<A: Action>(
20983        &mut self,
20984        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
20985    ) -> Subscription {
20986        let id = self.next_editor_action_id.post_inc();
20987        let listener = Arc::new(listener);
20988        self.editor_actions.borrow_mut().insert(
20989            id,
20990            Box::new(move |_, window, _| {
20991                let listener = listener.clone();
20992                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
20993                    let action = action.downcast_ref().unwrap();
20994                    if phase == DispatchPhase::Bubble {
20995                        listener(action, window, cx)
20996                    }
20997                })
20998            }),
20999        );
21000
21001        let editor_actions = self.editor_actions.clone();
21002        Subscription::new(move || {
21003            editor_actions.borrow_mut().remove(&id);
21004        })
21005    }
21006
21007    pub fn file_header_size(&self) -> u32 {
21008        FILE_HEADER_HEIGHT
21009    }
21010
21011    pub fn restore(
21012        &mut self,
21013        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21014        window: &mut Window,
21015        cx: &mut Context<Self>,
21016    ) {
21017        let workspace = self.workspace();
21018        let project = self.project.as_ref();
21019        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21020            let mut tasks = Vec::new();
21021            for (buffer_id, changes) in revert_changes {
21022                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21023                    buffer.update(cx, |buffer, cx| {
21024                        buffer.edit(
21025                            changes
21026                                .into_iter()
21027                                .map(|(range, text)| (range, text.to_string())),
21028                            None,
21029                            cx,
21030                        );
21031                    });
21032
21033                    if let Some(project) =
21034                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21035                    {
21036                        project.update(cx, |project, cx| {
21037                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21038                        })
21039                    }
21040                }
21041            }
21042            tasks
21043        });
21044        cx.spawn_in(window, async move |_, cx| {
21045            for (buffer, task) in save_tasks {
21046                let result = task.await;
21047                if result.is_err() {
21048                    let Some(path) = buffer
21049                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21050                        .ok()
21051                    else {
21052                        continue;
21053                    };
21054                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21055                        let Some(task) = cx
21056                            .update_window_entity(&workspace, |workspace, window, cx| {
21057                                workspace
21058                                    .open_path_preview(path, None, false, false, false, window, cx)
21059                            })
21060                            .ok()
21061                        else {
21062                            continue;
21063                        };
21064                        task.await.log_err();
21065                    }
21066                }
21067            }
21068        })
21069        .detach();
21070        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21071            selections.refresh()
21072        });
21073    }
21074
21075    pub fn to_pixel_point(
21076        &self,
21077        source: multi_buffer::Anchor,
21078        editor_snapshot: &EditorSnapshot,
21079        window: &mut Window,
21080    ) -> Option<gpui::Point<Pixels>> {
21081        let source_point = source.to_display_point(editor_snapshot);
21082        self.display_to_pixel_point(source_point, editor_snapshot, window)
21083    }
21084
21085    pub fn display_to_pixel_point(
21086        &self,
21087        source: DisplayPoint,
21088        editor_snapshot: &EditorSnapshot,
21089        window: &mut Window,
21090    ) -> Option<gpui::Point<Pixels>> {
21091        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21092        let text_layout_details = self.text_layout_details(window);
21093        let scroll_top = text_layout_details
21094            .scroll_anchor
21095            .scroll_position(editor_snapshot)
21096            .y;
21097
21098        if source.row().as_f32() < scroll_top.floor() {
21099            return None;
21100        }
21101        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21102        let source_y = line_height * (source.row().as_f32() - scroll_top);
21103        Some(gpui::Point::new(source_x, source_y))
21104    }
21105
21106    pub fn has_visible_completions_menu(&self) -> bool {
21107        !self.edit_prediction_preview_is_active()
21108            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
21109                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21110            })
21111    }
21112
21113    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21114        if self.mode.is_minimap() {
21115            return;
21116        }
21117        self.addons
21118            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21119    }
21120
21121    pub fn unregister_addon<T: Addon>(&mut self) {
21122        self.addons.remove(&std::any::TypeId::of::<T>());
21123    }
21124
21125    pub fn addon<T: Addon>(&self) -> Option<&T> {
21126        let type_id = std::any::TypeId::of::<T>();
21127        self.addons
21128            .get(&type_id)
21129            .and_then(|item| item.to_any().downcast_ref::<T>())
21130    }
21131
21132    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21133        let type_id = std::any::TypeId::of::<T>();
21134        self.addons
21135            .get_mut(&type_id)
21136            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21137    }
21138
21139    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21140        let text_layout_details = self.text_layout_details(window);
21141        let style = &text_layout_details.editor_style;
21142        let font_id = window.text_system().resolve_font(&style.text.font());
21143        let font_size = style.text.font_size.to_pixels(window.rem_size());
21144        let line_height = style.text.line_height_in_pixels(window.rem_size());
21145        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21146        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21147
21148        CharacterDimensions {
21149            em_width,
21150            em_advance,
21151            line_height,
21152        }
21153    }
21154
21155    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21156        self.load_diff_task.clone()
21157    }
21158
21159    fn read_metadata_from_db(
21160        &mut self,
21161        item_id: u64,
21162        workspace_id: WorkspaceId,
21163        window: &mut Window,
21164        cx: &mut Context<Editor>,
21165    ) {
21166        if self.is_singleton(cx)
21167            && !self.mode.is_minimap()
21168            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21169        {
21170            let buffer_snapshot = OnceCell::new();
21171
21172            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err() {
21173                if !folds.is_empty() {
21174                    let snapshot =
21175                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21176                    self.fold_ranges(
21177                        folds
21178                            .into_iter()
21179                            .map(|(start, end)| {
21180                                snapshot.clip_offset(start, Bias::Left)
21181                                    ..snapshot.clip_offset(end, Bias::Right)
21182                            })
21183                            .collect(),
21184                        false,
21185                        window,
21186                        cx,
21187                    );
21188                }
21189            }
21190
21191            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() {
21192                if !selections.is_empty() {
21193                    let snapshot =
21194                        buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21195                    // skip adding the initial selection to selection history
21196                    self.selection_history.mode = SelectionHistoryMode::Skipping;
21197                    self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21198                        s.select_ranges(selections.into_iter().map(|(start, end)| {
21199                            snapshot.clip_offset(start, Bias::Left)
21200                                ..snapshot.clip_offset(end, Bias::Right)
21201                        }));
21202                    });
21203                    self.selection_history.mode = SelectionHistoryMode::Normal;
21204                }
21205            };
21206        }
21207
21208        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21209    }
21210
21211    fn update_lsp_data(
21212        &mut self,
21213        ignore_cache: bool,
21214        for_buffer: Option<BufferId>,
21215        window: &mut Window,
21216        cx: &mut Context<'_, Self>,
21217    ) {
21218        self.pull_diagnostics(for_buffer, window, cx);
21219        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21220    }
21221}
21222
21223fn vim_enabled(cx: &App) -> bool {
21224    cx.global::<SettingsStore>()
21225        .raw_user_settings()
21226        .get("vim_mode")
21227        == Some(&serde_json::Value::Bool(true))
21228}
21229
21230fn process_completion_for_edit(
21231    completion: &Completion,
21232    intent: CompletionIntent,
21233    buffer: &Entity<Buffer>,
21234    cursor_position: &text::Anchor,
21235    cx: &mut Context<Editor>,
21236) -> CompletionEdit {
21237    let buffer = buffer.read(cx);
21238    let buffer_snapshot = buffer.snapshot();
21239    let (snippet, new_text) = if completion.is_snippet() {
21240        // Workaround for typescript language server issues so that methods don't expand within
21241        // strings and functions with type expressions. The previous point is used because the query
21242        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21243        let mut snippet_source = completion.new_text.clone();
21244        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21245        previous_point.column = previous_point.column.saturating_sub(1);
21246        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point) {
21247            if scope.prefers_label_for_snippet_in_completion() {
21248                if let Some(label) = completion.label() {
21249                    if matches!(
21250                        completion.kind(),
21251                        Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21252                    ) {
21253                        snippet_source = label;
21254                    }
21255                }
21256            }
21257        }
21258        match Snippet::parse(&snippet_source).log_err() {
21259            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21260            None => (None, completion.new_text.clone()),
21261        }
21262    } else {
21263        (None, completion.new_text.clone())
21264    };
21265
21266    let mut range_to_replace = {
21267        let replace_range = &completion.replace_range;
21268        if let CompletionSource::Lsp {
21269            insert_range: Some(insert_range),
21270            ..
21271        } = &completion.source
21272        {
21273            debug_assert_eq!(
21274                insert_range.start, replace_range.start,
21275                "insert_range and replace_range should start at the same position"
21276            );
21277            debug_assert!(
21278                insert_range
21279                    .start
21280                    .cmp(&cursor_position, &buffer_snapshot)
21281                    .is_le(),
21282                "insert_range should start before or at cursor position"
21283            );
21284            debug_assert!(
21285                replace_range
21286                    .start
21287                    .cmp(&cursor_position, &buffer_snapshot)
21288                    .is_le(),
21289                "replace_range should start before or at cursor position"
21290            );
21291
21292            let should_replace = match intent {
21293                CompletionIntent::CompleteWithInsert => false,
21294                CompletionIntent::CompleteWithReplace => true,
21295                CompletionIntent::Complete | CompletionIntent::Compose => {
21296                    let insert_mode =
21297                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21298                            .completions
21299                            .lsp_insert_mode;
21300                    match insert_mode {
21301                        LspInsertMode::Insert => false,
21302                        LspInsertMode::Replace => true,
21303                        LspInsertMode::ReplaceSubsequence => {
21304                            let mut text_to_replace = buffer.chars_for_range(
21305                                buffer.anchor_before(replace_range.start)
21306                                    ..buffer.anchor_after(replace_range.end),
21307                            );
21308                            let mut current_needle = text_to_replace.next();
21309                            for haystack_ch in completion.label.text.chars() {
21310                                if let Some(needle_ch) = current_needle {
21311                                    if haystack_ch.eq_ignore_ascii_case(&needle_ch) {
21312                                        current_needle = text_to_replace.next();
21313                                    }
21314                                }
21315                            }
21316                            current_needle.is_none()
21317                        }
21318                        LspInsertMode::ReplaceSuffix => {
21319                            if replace_range
21320                                .end
21321                                .cmp(&cursor_position, &buffer_snapshot)
21322                                .is_gt()
21323                            {
21324                                let range_after_cursor = *cursor_position..replace_range.end;
21325                                let text_after_cursor = buffer
21326                                    .text_for_range(
21327                                        buffer.anchor_before(range_after_cursor.start)
21328                                            ..buffer.anchor_after(range_after_cursor.end),
21329                                    )
21330                                    .collect::<String>()
21331                                    .to_ascii_lowercase();
21332                                completion
21333                                    .label
21334                                    .text
21335                                    .to_ascii_lowercase()
21336                                    .ends_with(&text_after_cursor)
21337                            } else {
21338                                true
21339                            }
21340                        }
21341                    }
21342                }
21343            };
21344
21345            if should_replace {
21346                replace_range.clone()
21347            } else {
21348                insert_range.clone()
21349            }
21350        } else {
21351            replace_range.clone()
21352        }
21353    };
21354
21355    if range_to_replace
21356        .end
21357        .cmp(&cursor_position, &buffer_snapshot)
21358        .is_lt()
21359    {
21360        range_to_replace.end = *cursor_position;
21361    }
21362
21363    CompletionEdit {
21364        new_text,
21365        replace_range: range_to_replace.to_offset(&buffer),
21366        snippet,
21367    }
21368}
21369
21370struct CompletionEdit {
21371    new_text: String,
21372    replace_range: Range<usize>,
21373    snippet: Option<Snippet>,
21374}
21375
21376fn insert_extra_newline_brackets(
21377    buffer: &MultiBufferSnapshot,
21378    range: Range<usize>,
21379    language: &language::LanguageScope,
21380) -> bool {
21381    let leading_whitespace_len = buffer
21382        .reversed_chars_at(range.start)
21383        .take_while(|c| c.is_whitespace() && *c != '\n')
21384        .map(|c| c.len_utf8())
21385        .sum::<usize>();
21386    let trailing_whitespace_len = buffer
21387        .chars_at(range.end)
21388        .take_while(|c| c.is_whitespace() && *c != '\n')
21389        .map(|c| c.len_utf8())
21390        .sum::<usize>();
21391    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21392
21393    language.brackets().any(|(pair, enabled)| {
21394        let pair_start = pair.start.trim_end();
21395        let pair_end = pair.end.trim_start();
21396
21397        enabled
21398            && pair.newline
21399            && buffer.contains_str_at(range.end, pair_end)
21400            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21401    })
21402}
21403
21404fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21405    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21406        [(buffer, range, _)] => (*buffer, range.clone()),
21407        _ => return false,
21408    };
21409    let pair = {
21410        let mut result: Option<BracketMatch> = None;
21411
21412        for pair in buffer
21413            .all_bracket_ranges(range.clone())
21414            .filter(move |pair| {
21415                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21416            })
21417        {
21418            let len = pair.close_range.end - pair.open_range.start;
21419
21420            if let Some(existing) = &result {
21421                let existing_len = existing.close_range.end - existing.open_range.start;
21422                if len > existing_len {
21423                    continue;
21424                }
21425            }
21426
21427            result = Some(pair);
21428        }
21429
21430        result
21431    };
21432    let Some(pair) = pair else {
21433        return false;
21434    };
21435    pair.newline_only
21436        && buffer
21437            .chars_for_range(pair.open_range.end..range.start)
21438            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21439            .all(|c| c.is_whitespace() && c != '\n')
21440}
21441
21442fn update_uncommitted_diff_for_buffer(
21443    editor: Entity<Editor>,
21444    project: &Entity<Project>,
21445    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21446    buffer: Entity<MultiBuffer>,
21447    cx: &mut App,
21448) -> Task<()> {
21449    let mut tasks = Vec::new();
21450    project.update(cx, |project, cx| {
21451        for buffer in buffers {
21452            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21453                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21454            }
21455        }
21456    });
21457    cx.spawn(async move |cx| {
21458        let diffs = future::join_all(tasks).await;
21459        if editor
21460            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21461            .unwrap_or(false)
21462        {
21463            return;
21464        }
21465
21466        buffer
21467            .update(cx, |buffer, cx| {
21468                for diff in diffs.into_iter().flatten() {
21469                    buffer.add_diff(diff, cx);
21470                }
21471            })
21472            .ok();
21473    })
21474}
21475
21476fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21477    let tab_size = tab_size.get() as usize;
21478    let mut width = offset;
21479
21480    for ch in text.chars() {
21481        width += if ch == '\t' {
21482            tab_size - (width % tab_size)
21483        } else {
21484            1
21485        };
21486    }
21487
21488    width - offset
21489}
21490
21491#[cfg(test)]
21492mod tests {
21493    use super::*;
21494
21495    #[test]
21496    fn test_string_size_with_expanded_tabs() {
21497        let nz = |val| NonZeroU32::new(val).unwrap();
21498        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21499        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21500        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21501        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21502        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21503        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21504        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21505        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21506    }
21507}
21508
21509/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21510struct WordBreakingTokenizer<'a> {
21511    input: &'a str,
21512}
21513
21514impl<'a> WordBreakingTokenizer<'a> {
21515    fn new(input: &'a str) -> Self {
21516        Self { input }
21517    }
21518}
21519
21520fn is_char_ideographic(ch: char) -> bool {
21521    use unicode_script::Script::*;
21522    use unicode_script::UnicodeScript;
21523    matches!(ch.script(), Han | Tangut | Yi)
21524}
21525
21526fn is_grapheme_ideographic(text: &str) -> bool {
21527    text.chars().any(is_char_ideographic)
21528}
21529
21530fn is_grapheme_whitespace(text: &str) -> bool {
21531    text.chars().any(|x| x.is_whitespace())
21532}
21533
21534fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21535    text.chars().next().map_or(false, |ch| {
21536        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21537    })
21538}
21539
21540#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21541enum WordBreakToken<'a> {
21542    Word { token: &'a str, grapheme_len: usize },
21543    InlineWhitespace { token: &'a str, grapheme_len: usize },
21544    Newline,
21545}
21546
21547impl<'a> Iterator for WordBreakingTokenizer<'a> {
21548    /// Yields a span, the count of graphemes in the token, and whether it was
21549    /// whitespace. Note that it also breaks at word boundaries.
21550    type Item = WordBreakToken<'a>;
21551
21552    fn next(&mut self) -> Option<Self::Item> {
21553        use unicode_segmentation::UnicodeSegmentation;
21554        if self.input.is_empty() {
21555            return None;
21556        }
21557
21558        let mut iter = self.input.graphemes(true).peekable();
21559        let mut offset = 0;
21560        let mut grapheme_len = 0;
21561        if let Some(first_grapheme) = iter.next() {
21562            let is_newline = first_grapheme == "\n";
21563            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21564            offset += first_grapheme.len();
21565            grapheme_len += 1;
21566            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21567                if let Some(grapheme) = iter.peek().copied() {
21568                    if should_stay_with_preceding_ideograph(grapheme) {
21569                        offset += grapheme.len();
21570                        grapheme_len += 1;
21571                    }
21572                }
21573            } else {
21574                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21575                let mut next_word_bound = words.peek().copied();
21576                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21577                    next_word_bound = words.next();
21578                }
21579                while let Some(grapheme) = iter.peek().copied() {
21580                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21581                        break;
21582                    };
21583                    if is_grapheme_whitespace(grapheme) != is_whitespace
21584                        || (grapheme == "\n") != is_newline
21585                    {
21586                        break;
21587                    };
21588                    offset += grapheme.len();
21589                    grapheme_len += 1;
21590                    iter.next();
21591                }
21592            }
21593            let token = &self.input[..offset];
21594            self.input = &self.input[offset..];
21595            if token == "\n" {
21596                Some(WordBreakToken::Newline)
21597            } else if is_whitespace {
21598                Some(WordBreakToken::InlineWhitespace {
21599                    token,
21600                    grapheme_len,
21601                })
21602            } else {
21603                Some(WordBreakToken::Word {
21604                    token,
21605                    grapheme_len,
21606                })
21607            }
21608        } else {
21609            None
21610        }
21611    }
21612}
21613
21614#[test]
21615fn test_word_breaking_tokenizer() {
21616    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21617        ("", &[]),
21618        ("  ", &[whitespace("  ", 2)]),
21619        ("Ʒ", &[word("Ʒ", 1)]),
21620        ("Ǽ", &[word("Ǽ", 1)]),
21621        ("", &[word("", 1)]),
21622        ("⋑⋑", &[word("⋑⋑", 2)]),
21623        (
21624            "原理,进而",
21625            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21626        ),
21627        (
21628            "hello world",
21629            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21630        ),
21631        (
21632            "hello, world",
21633            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21634        ),
21635        (
21636            "  hello world",
21637            &[
21638                whitespace("  ", 2),
21639                word("hello", 5),
21640                whitespace(" ", 1),
21641                word("world", 5),
21642            ],
21643        ),
21644        (
21645            "这是什么 \n 钢笔",
21646            &[
21647                word("", 1),
21648                word("", 1),
21649                word("", 1),
21650                word("", 1),
21651                whitespace(" ", 1),
21652                newline(),
21653                whitespace(" ", 1),
21654                word("", 1),
21655                word("", 1),
21656            ],
21657        ),
21658        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21659    ];
21660
21661    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21662        WordBreakToken::Word {
21663            token,
21664            grapheme_len,
21665        }
21666    }
21667
21668    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21669        WordBreakToken::InlineWhitespace {
21670            token,
21671            grapheme_len,
21672        }
21673    }
21674
21675    fn newline() -> WordBreakToken<'static> {
21676        WordBreakToken::Newline
21677    }
21678
21679    for (input, result) in tests {
21680        assert_eq!(
21681            WordBreakingTokenizer::new(input)
21682                .collect::<Vec<_>>()
21683                .as_slice(),
21684            *result,
21685        );
21686    }
21687}
21688
21689fn wrap_with_prefix(
21690    first_line_prefix: String,
21691    subsequent_lines_prefix: String,
21692    unwrapped_text: String,
21693    wrap_column: usize,
21694    tab_size: NonZeroU32,
21695    preserve_existing_whitespace: bool,
21696) -> String {
21697    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21698    let subsequent_lines_prefix_len =
21699        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21700    let mut wrapped_text = String::new();
21701    let mut current_line = first_line_prefix.clone();
21702    let mut is_first_line = true;
21703
21704    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21705    let mut current_line_len = first_line_prefix_len;
21706    let mut in_whitespace = false;
21707    for token in tokenizer {
21708        let have_preceding_whitespace = in_whitespace;
21709        match token {
21710            WordBreakToken::Word {
21711                token,
21712                grapheme_len,
21713            } => {
21714                in_whitespace = false;
21715                let current_prefix_len = if is_first_line {
21716                    first_line_prefix_len
21717                } else {
21718                    subsequent_lines_prefix_len
21719                };
21720                if current_line_len + grapheme_len > wrap_column
21721                    && current_line_len != current_prefix_len
21722                {
21723                    wrapped_text.push_str(current_line.trim_end());
21724                    wrapped_text.push('\n');
21725                    is_first_line = false;
21726                    current_line = subsequent_lines_prefix.clone();
21727                    current_line_len = subsequent_lines_prefix_len;
21728                }
21729                current_line.push_str(token);
21730                current_line_len += grapheme_len;
21731            }
21732            WordBreakToken::InlineWhitespace {
21733                mut token,
21734                mut grapheme_len,
21735            } => {
21736                in_whitespace = true;
21737                if have_preceding_whitespace && !preserve_existing_whitespace {
21738                    continue;
21739                }
21740                if !preserve_existing_whitespace {
21741                    token = " ";
21742                    grapheme_len = 1;
21743                }
21744                let current_prefix_len = if is_first_line {
21745                    first_line_prefix_len
21746                } else {
21747                    subsequent_lines_prefix_len
21748                };
21749                if current_line_len + grapheme_len > wrap_column {
21750                    wrapped_text.push_str(current_line.trim_end());
21751                    wrapped_text.push('\n');
21752                    is_first_line = false;
21753                    current_line = subsequent_lines_prefix.clone();
21754                    current_line_len = subsequent_lines_prefix_len;
21755                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21756                    current_line.push_str(token);
21757                    current_line_len += grapheme_len;
21758                }
21759            }
21760            WordBreakToken::Newline => {
21761                in_whitespace = true;
21762                let current_prefix_len = if is_first_line {
21763                    first_line_prefix_len
21764                } else {
21765                    subsequent_lines_prefix_len
21766                };
21767                if preserve_existing_whitespace {
21768                    wrapped_text.push_str(current_line.trim_end());
21769                    wrapped_text.push('\n');
21770                    is_first_line = false;
21771                    current_line = subsequent_lines_prefix.clone();
21772                    current_line_len = subsequent_lines_prefix_len;
21773                } else if have_preceding_whitespace {
21774                    continue;
21775                } else if current_line_len + 1 > wrap_column
21776                    && current_line_len != current_prefix_len
21777                {
21778                    wrapped_text.push_str(current_line.trim_end());
21779                    wrapped_text.push('\n');
21780                    is_first_line = false;
21781                    current_line = subsequent_lines_prefix.clone();
21782                    current_line_len = subsequent_lines_prefix_len;
21783                } else if current_line_len != current_prefix_len {
21784                    current_line.push(' ');
21785                    current_line_len += 1;
21786                }
21787            }
21788        }
21789    }
21790
21791    if !current_line.is_empty() {
21792        wrapped_text.push_str(&current_line);
21793    }
21794    wrapped_text
21795}
21796
21797#[test]
21798fn test_wrap_with_prefix() {
21799    assert_eq!(
21800        wrap_with_prefix(
21801            "# ".to_string(),
21802            "# ".to_string(),
21803            "abcdefg".to_string(),
21804            4,
21805            NonZeroU32::new(4).unwrap(),
21806            false,
21807        ),
21808        "# abcdefg"
21809    );
21810    assert_eq!(
21811        wrap_with_prefix(
21812            "".to_string(),
21813            "".to_string(),
21814            "\thello world".to_string(),
21815            8,
21816            NonZeroU32::new(4).unwrap(),
21817            false,
21818        ),
21819        "hello\nworld"
21820    );
21821    assert_eq!(
21822        wrap_with_prefix(
21823            "// ".to_string(),
21824            "// ".to_string(),
21825            "xx \nyy zz aa bb cc".to_string(),
21826            12,
21827            NonZeroU32::new(4).unwrap(),
21828            false,
21829        ),
21830        "// xx yy zz\n// aa bb cc"
21831    );
21832    assert_eq!(
21833        wrap_with_prefix(
21834            String::new(),
21835            String::new(),
21836            "这是什么 \n 钢笔".to_string(),
21837            3,
21838            NonZeroU32::new(4).unwrap(),
21839            false,
21840        ),
21841        "这是什\n么 钢\n"
21842    );
21843}
21844
21845pub trait CollaborationHub {
21846    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21847    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21848    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21849}
21850
21851impl CollaborationHub for Entity<Project> {
21852    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21853        self.read(cx).collaborators()
21854    }
21855
21856    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21857        self.read(cx).user_store().read(cx).participant_indices()
21858    }
21859
21860    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21861        let this = self.read(cx);
21862        let user_ids = this.collaborators().values().map(|c| c.user_id);
21863        this.user_store().read(cx).participant_names(user_ids, cx)
21864    }
21865}
21866
21867pub trait SemanticsProvider {
21868    fn hover(
21869        &self,
21870        buffer: &Entity<Buffer>,
21871        position: text::Anchor,
21872        cx: &mut App,
21873    ) -> Option<Task<Vec<project::Hover>>>;
21874
21875    fn inline_values(
21876        &self,
21877        buffer_handle: Entity<Buffer>,
21878        range: Range<text::Anchor>,
21879        cx: &mut App,
21880    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21881
21882    fn inlay_hints(
21883        &self,
21884        buffer_handle: Entity<Buffer>,
21885        range: Range<text::Anchor>,
21886        cx: &mut App,
21887    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21888
21889    fn resolve_inlay_hint(
21890        &self,
21891        hint: InlayHint,
21892        buffer_handle: Entity<Buffer>,
21893        server_id: LanguageServerId,
21894        cx: &mut App,
21895    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21896
21897    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21898
21899    fn document_highlights(
21900        &self,
21901        buffer: &Entity<Buffer>,
21902        position: text::Anchor,
21903        cx: &mut App,
21904    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21905
21906    fn definitions(
21907        &self,
21908        buffer: &Entity<Buffer>,
21909        position: text::Anchor,
21910        kind: GotoDefinitionKind,
21911        cx: &mut App,
21912    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21913
21914    fn range_for_rename(
21915        &self,
21916        buffer: &Entity<Buffer>,
21917        position: text::Anchor,
21918        cx: &mut App,
21919    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21920
21921    fn perform_rename(
21922        &self,
21923        buffer: &Entity<Buffer>,
21924        position: text::Anchor,
21925        new_name: String,
21926        cx: &mut App,
21927    ) -> Option<Task<Result<ProjectTransaction>>>;
21928}
21929
21930pub trait CompletionProvider {
21931    fn completions(
21932        &self,
21933        excerpt_id: ExcerptId,
21934        buffer: &Entity<Buffer>,
21935        buffer_position: text::Anchor,
21936        trigger: CompletionContext,
21937        window: &mut Window,
21938        cx: &mut Context<Editor>,
21939    ) -> Task<Result<Vec<CompletionResponse>>>;
21940
21941    fn resolve_completions(
21942        &self,
21943        _buffer: Entity<Buffer>,
21944        _completion_indices: Vec<usize>,
21945        _completions: Rc<RefCell<Box<[Completion]>>>,
21946        _cx: &mut Context<Editor>,
21947    ) -> Task<Result<bool>> {
21948        Task::ready(Ok(false))
21949    }
21950
21951    fn apply_additional_edits_for_completion(
21952        &self,
21953        _buffer: Entity<Buffer>,
21954        _completions: Rc<RefCell<Box<[Completion]>>>,
21955        _completion_index: usize,
21956        _push_to_history: bool,
21957        _cx: &mut Context<Editor>,
21958    ) -> Task<Result<Option<language::Transaction>>> {
21959        Task::ready(Ok(None))
21960    }
21961
21962    fn is_completion_trigger(
21963        &self,
21964        buffer: &Entity<Buffer>,
21965        position: language::Anchor,
21966        text: &str,
21967        trigger_in_words: bool,
21968        menu_is_open: bool,
21969        cx: &mut Context<Editor>,
21970    ) -> bool;
21971
21972    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21973
21974    fn sort_completions(&self) -> bool {
21975        true
21976    }
21977
21978    fn filter_completions(&self) -> bool {
21979        true
21980    }
21981}
21982
21983pub trait CodeActionProvider {
21984    fn id(&self) -> Arc<str>;
21985
21986    fn code_actions(
21987        &self,
21988        buffer: &Entity<Buffer>,
21989        range: Range<text::Anchor>,
21990        window: &mut Window,
21991        cx: &mut App,
21992    ) -> Task<Result<Vec<CodeAction>>>;
21993
21994    fn apply_code_action(
21995        &self,
21996        buffer_handle: Entity<Buffer>,
21997        action: CodeAction,
21998        excerpt_id: ExcerptId,
21999        push_to_history: bool,
22000        window: &mut Window,
22001        cx: &mut App,
22002    ) -> Task<Result<ProjectTransaction>>;
22003}
22004
22005impl CodeActionProvider for Entity<Project> {
22006    fn id(&self) -> Arc<str> {
22007        "project".into()
22008    }
22009
22010    fn code_actions(
22011        &self,
22012        buffer: &Entity<Buffer>,
22013        range: Range<text::Anchor>,
22014        _window: &mut Window,
22015        cx: &mut App,
22016    ) -> Task<Result<Vec<CodeAction>>> {
22017        self.update(cx, |project, cx| {
22018            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22019            let code_actions = project.code_actions(buffer, range, None, cx);
22020            cx.background_spawn(async move {
22021                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22022                Ok(code_lens_actions
22023                    .context("code lens fetch")?
22024                    .into_iter()
22025                    .chain(code_actions.context("code action fetch")?)
22026                    .collect())
22027            })
22028        })
22029    }
22030
22031    fn apply_code_action(
22032        &self,
22033        buffer_handle: Entity<Buffer>,
22034        action: CodeAction,
22035        _excerpt_id: ExcerptId,
22036        push_to_history: bool,
22037        _window: &mut Window,
22038        cx: &mut App,
22039    ) -> Task<Result<ProjectTransaction>> {
22040        self.update(cx, |project, cx| {
22041            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22042        })
22043    }
22044}
22045
22046fn snippet_completions(
22047    project: &Project,
22048    buffer: &Entity<Buffer>,
22049    buffer_position: text::Anchor,
22050    cx: &mut App,
22051) -> Task<Result<CompletionResponse>> {
22052    let languages = buffer.read(cx).languages_at(buffer_position);
22053    let snippet_store = project.snippets().read(cx);
22054
22055    let scopes: Vec<_> = languages
22056        .iter()
22057        .filter_map(|language| {
22058            let language_name = language.lsp_id();
22059            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22060
22061            if snippets.is_empty() {
22062                None
22063            } else {
22064                Some((language.default_scope(), snippets))
22065            }
22066        })
22067        .collect();
22068
22069    if scopes.is_empty() {
22070        return Task::ready(Ok(CompletionResponse {
22071            completions: vec![],
22072            is_incomplete: false,
22073        }));
22074    }
22075
22076    let snapshot = buffer.read(cx).text_snapshot();
22077    let chars: String = snapshot
22078        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22079        .collect();
22080    let executor = cx.background_executor().clone();
22081
22082    cx.background_spawn(async move {
22083        let mut is_incomplete = false;
22084        let mut completions: Vec<Completion> = Vec::new();
22085        for (scope, snippets) in scopes.into_iter() {
22086            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22087            let mut last_word = chars
22088                .chars()
22089                .take_while(|c| classifier.is_word(*c))
22090                .collect::<String>();
22091            last_word = last_word.chars().rev().collect();
22092
22093            if last_word.is_empty() {
22094                return Ok(CompletionResponse {
22095                    completions: vec![],
22096                    is_incomplete: true,
22097                });
22098            }
22099
22100            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22101            let to_lsp = |point: &text::Anchor| {
22102                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22103                point_to_lsp(end)
22104            };
22105            let lsp_end = to_lsp(&buffer_position);
22106
22107            let candidates = snippets
22108                .iter()
22109                .enumerate()
22110                .flat_map(|(ix, snippet)| {
22111                    snippet
22112                        .prefix
22113                        .iter()
22114                        .map(move |prefix| StringMatchCandidate::new(ix, &prefix))
22115                })
22116                .collect::<Vec<StringMatchCandidate>>();
22117
22118            const MAX_RESULTS: usize = 100;
22119            let mut matches = fuzzy::match_strings(
22120                &candidates,
22121                &last_word,
22122                last_word.chars().any(|c| c.is_uppercase()),
22123                true,
22124                MAX_RESULTS,
22125                &Default::default(),
22126                executor.clone(),
22127            )
22128            .await;
22129
22130            if matches.len() >= MAX_RESULTS {
22131                is_incomplete = true;
22132            }
22133
22134            // Remove all candidates where the query's start does not match the start of any word in the candidate
22135            if let Some(query_start) = last_word.chars().next() {
22136                matches.retain(|string_match| {
22137                    split_words(&string_match.string).any(|word| {
22138                        // Check that the first codepoint of the word as lowercase matches the first
22139                        // codepoint of the query as lowercase
22140                        word.chars()
22141                            .flat_map(|codepoint| codepoint.to_lowercase())
22142                            .zip(query_start.to_lowercase())
22143                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22144                    })
22145                });
22146            }
22147
22148            let matched_strings = matches
22149                .into_iter()
22150                .map(|m| m.string)
22151                .collect::<HashSet<_>>();
22152
22153            completions.extend(snippets.iter().filter_map(|snippet| {
22154                let matching_prefix = snippet
22155                    .prefix
22156                    .iter()
22157                    .find(|prefix| matched_strings.contains(*prefix))?;
22158                let start = as_offset - last_word.len();
22159                let start = snapshot.anchor_before(start);
22160                let range = start..buffer_position;
22161                let lsp_start = to_lsp(&start);
22162                let lsp_range = lsp::Range {
22163                    start: lsp_start,
22164                    end: lsp_end,
22165                };
22166                Some(Completion {
22167                    replace_range: range,
22168                    new_text: snippet.body.clone(),
22169                    source: CompletionSource::Lsp {
22170                        insert_range: None,
22171                        server_id: LanguageServerId(usize::MAX),
22172                        resolved: true,
22173                        lsp_completion: Box::new(lsp::CompletionItem {
22174                            label: snippet.prefix.first().unwrap().clone(),
22175                            kind: Some(CompletionItemKind::SNIPPET),
22176                            label_details: snippet.description.as_ref().map(|description| {
22177                                lsp::CompletionItemLabelDetails {
22178                                    detail: Some(description.clone()),
22179                                    description: None,
22180                                }
22181                            }),
22182                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22183                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22184                                lsp::InsertReplaceEdit {
22185                                    new_text: snippet.body.clone(),
22186                                    insert: lsp_range,
22187                                    replace: lsp_range,
22188                                },
22189                            )),
22190                            filter_text: Some(snippet.body.clone()),
22191                            sort_text: Some(char::MAX.to_string()),
22192                            ..lsp::CompletionItem::default()
22193                        }),
22194                        lsp_defaults: None,
22195                    },
22196                    label: CodeLabel {
22197                        text: matching_prefix.clone(),
22198                        runs: Vec::new(),
22199                        filter_range: 0..matching_prefix.len(),
22200                    },
22201                    icon_path: None,
22202                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22203                        single_line: snippet.name.clone().into(),
22204                        plain_text: snippet
22205                            .description
22206                            .clone()
22207                            .map(|description| description.into()),
22208                    }),
22209                    insert_text_mode: None,
22210                    confirm: None,
22211                })
22212            }))
22213        }
22214
22215        Ok(CompletionResponse {
22216            completions,
22217            is_incomplete,
22218        })
22219    })
22220}
22221
22222impl CompletionProvider for Entity<Project> {
22223    fn completions(
22224        &self,
22225        _excerpt_id: ExcerptId,
22226        buffer: &Entity<Buffer>,
22227        buffer_position: text::Anchor,
22228        options: CompletionContext,
22229        _window: &mut Window,
22230        cx: &mut Context<Editor>,
22231    ) -> Task<Result<Vec<CompletionResponse>>> {
22232        self.update(cx, |project, cx| {
22233            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22234            let project_completions = project.completions(buffer, buffer_position, options, cx);
22235            cx.background_spawn(async move {
22236                let mut responses = project_completions.await?;
22237                let snippets = snippets.await?;
22238                if !snippets.completions.is_empty() {
22239                    responses.push(snippets);
22240                }
22241                Ok(responses)
22242            })
22243        })
22244    }
22245
22246    fn resolve_completions(
22247        &self,
22248        buffer: Entity<Buffer>,
22249        completion_indices: Vec<usize>,
22250        completions: Rc<RefCell<Box<[Completion]>>>,
22251        cx: &mut Context<Editor>,
22252    ) -> Task<Result<bool>> {
22253        self.update(cx, |project, cx| {
22254            project.lsp_store().update(cx, |lsp_store, cx| {
22255                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22256            })
22257        })
22258    }
22259
22260    fn apply_additional_edits_for_completion(
22261        &self,
22262        buffer: Entity<Buffer>,
22263        completions: Rc<RefCell<Box<[Completion]>>>,
22264        completion_index: usize,
22265        push_to_history: bool,
22266        cx: &mut Context<Editor>,
22267    ) -> Task<Result<Option<language::Transaction>>> {
22268        self.update(cx, |project, cx| {
22269            project.lsp_store().update(cx, |lsp_store, cx| {
22270                lsp_store.apply_additional_edits_for_completion(
22271                    buffer,
22272                    completions,
22273                    completion_index,
22274                    push_to_history,
22275                    cx,
22276                )
22277            })
22278        })
22279    }
22280
22281    fn is_completion_trigger(
22282        &self,
22283        buffer: &Entity<Buffer>,
22284        position: language::Anchor,
22285        text: &str,
22286        trigger_in_words: bool,
22287        menu_is_open: bool,
22288        cx: &mut Context<Editor>,
22289    ) -> bool {
22290        let mut chars = text.chars();
22291        let char = if let Some(char) = chars.next() {
22292            char
22293        } else {
22294            return false;
22295        };
22296        if chars.next().is_some() {
22297            return false;
22298        }
22299
22300        let buffer = buffer.read(cx);
22301        let snapshot = buffer.snapshot();
22302        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22303            return false;
22304        }
22305        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22306        if trigger_in_words && classifier.is_word(char) {
22307            return true;
22308        }
22309
22310        buffer.completion_triggers().contains(text)
22311    }
22312}
22313
22314impl SemanticsProvider for Entity<Project> {
22315    fn hover(
22316        &self,
22317        buffer: &Entity<Buffer>,
22318        position: text::Anchor,
22319        cx: &mut App,
22320    ) -> Option<Task<Vec<project::Hover>>> {
22321        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22322    }
22323
22324    fn document_highlights(
22325        &self,
22326        buffer: &Entity<Buffer>,
22327        position: text::Anchor,
22328        cx: &mut App,
22329    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22330        Some(self.update(cx, |project, cx| {
22331            project.document_highlights(buffer, position, cx)
22332        }))
22333    }
22334
22335    fn definitions(
22336        &self,
22337        buffer: &Entity<Buffer>,
22338        position: text::Anchor,
22339        kind: GotoDefinitionKind,
22340        cx: &mut App,
22341    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22342        Some(self.update(cx, |project, cx| match kind {
22343            GotoDefinitionKind::Symbol => project.definitions(&buffer, position, cx),
22344            GotoDefinitionKind::Declaration => project.declarations(&buffer, position, cx),
22345            GotoDefinitionKind::Type => project.type_definitions(&buffer, position, cx),
22346            GotoDefinitionKind::Implementation => project.implementations(&buffer, position, cx),
22347        }))
22348    }
22349
22350    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22351        self.update(cx, |project, cx| {
22352            if project
22353                .active_debug_session(cx)
22354                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22355            {
22356                return true;
22357            }
22358
22359            buffer.update(cx, |buffer, cx| {
22360                project.any_language_server_supports_inlay_hints(buffer, cx)
22361            })
22362        })
22363    }
22364
22365    fn inline_values(
22366        &self,
22367        buffer_handle: Entity<Buffer>,
22368        range: Range<text::Anchor>,
22369        cx: &mut App,
22370    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22371        self.update(cx, |project, cx| {
22372            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22373
22374            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22375        })
22376    }
22377
22378    fn inlay_hints(
22379        &self,
22380        buffer_handle: Entity<Buffer>,
22381        range: Range<text::Anchor>,
22382        cx: &mut App,
22383    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22384        Some(self.update(cx, |project, cx| {
22385            project.inlay_hints(buffer_handle, range, cx)
22386        }))
22387    }
22388
22389    fn resolve_inlay_hint(
22390        &self,
22391        hint: InlayHint,
22392        buffer_handle: Entity<Buffer>,
22393        server_id: LanguageServerId,
22394        cx: &mut App,
22395    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22396        Some(self.update(cx, |project, cx| {
22397            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22398        }))
22399    }
22400
22401    fn range_for_rename(
22402        &self,
22403        buffer: &Entity<Buffer>,
22404        position: text::Anchor,
22405        cx: &mut App,
22406    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22407        Some(self.update(cx, |project, cx| {
22408            let buffer = buffer.clone();
22409            let task = project.prepare_rename(buffer.clone(), position, cx);
22410            cx.spawn(async move |_, cx| {
22411                Ok(match task.await? {
22412                    PrepareRenameResponse::Success(range) => Some(range),
22413                    PrepareRenameResponse::InvalidPosition => None,
22414                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22415                        // Fallback on using TreeSitter info to determine identifier range
22416                        buffer.read_with(cx, |buffer, _| {
22417                            let snapshot = buffer.snapshot();
22418                            let (range, kind) = snapshot.surrounding_word(position, false);
22419                            if kind != Some(CharKind::Word) {
22420                                return None;
22421                            }
22422                            Some(
22423                                snapshot.anchor_before(range.start)
22424                                    ..snapshot.anchor_after(range.end),
22425                            )
22426                        })?
22427                    }
22428                })
22429            })
22430        }))
22431    }
22432
22433    fn perform_rename(
22434        &self,
22435        buffer: &Entity<Buffer>,
22436        position: text::Anchor,
22437        new_name: String,
22438        cx: &mut App,
22439    ) -> Option<Task<Result<ProjectTransaction>>> {
22440        Some(self.update(cx, |project, cx| {
22441            project.perform_rename(buffer.clone(), position, new_name, cx)
22442        }))
22443    }
22444}
22445
22446fn inlay_hint_settings(
22447    location: Anchor,
22448    snapshot: &MultiBufferSnapshot,
22449    cx: &mut Context<Editor>,
22450) -> InlayHintSettings {
22451    let file = snapshot.file_at(location);
22452    let language = snapshot.language_at(location).map(|l| l.name());
22453    language_settings(language, file, cx).inlay_hints
22454}
22455
22456fn consume_contiguous_rows(
22457    contiguous_row_selections: &mut Vec<Selection<Point>>,
22458    selection: &Selection<Point>,
22459    display_map: &DisplaySnapshot,
22460    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22461) -> (MultiBufferRow, MultiBufferRow) {
22462    contiguous_row_selections.push(selection.clone());
22463    let start_row = starting_row(selection, display_map);
22464    let mut end_row = ending_row(selection, display_map);
22465
22466    while let Some(next_selection) = selections.peek() {
22467        if next_selection.start.row <= end_row.0 {
22468            end_row = ending_row(next_selection, display_map);
22469            contiguous_row_selections.push(selections.next().unwrap().clone());
22470        } else {
22471            break;
22472        }
22473    }
22474    (start_row, end_row)
22475}
22476
22477fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22478    if selection.start.column > 0 {
22479        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22480    } else {
22481        MultiBufferRow(selection.start.row)
22482    }
22483}
22484
22485fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22486    if next_selection.end.column > 0 || next_selection.is_empty() {
22487        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22488    } else {
22489        MultiBufferRow(next_selection.end.row)
22490    }
22491}
22492
22493impl EditorSnapshot {
22494    pub fn remote_selections_in_range<'a>(
22495        &'a self,
22496        range: &'a Range<Anchor>,
22497        collaboration_hub: &dyn CollaborationHub,
22498        cx: &'a App,
22499    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22500        let participant_names = collaboration_hub.user_names(cx);
22501        let participant_indices = collaboration_hub.user_participant_indices(cx);
22502        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22503        let collaborators_by_replica_id = collaborators_by_peer_id
22504            .values()
22505            .map(|collaborator| (collaborator.replica_id, collaborator))
22506            .collect::<HashMap<_, _>>();
22507        self.buffer_snapshot
22508            .selections_in_range(range, false)
22509            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22510                if replica_id == AGENT_REPLICA_ID {
22511                    Some(RemoteSelection {
22512                        replica_id,
22513                        selection,
22514                        cursor_shape,
22515                        line_mode,
22516                        collaborator_id: CollaboratorId::Agent,
22517                        user_name: Some("Agent".into()),
22518                        color: cx.theme().players().agent(),
22519                    })
22520                } else {
22521                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22522                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22523                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22524                    Some(RemoteSelection {
22525                        replica_id,
22526                        selection,
22527                        cursor_shape,
22528                        line_mode,
22529                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22530                        user_name,
22531                        color: if let Some(index) = participant_index {
22532                            cx.theme().players().color_for_participant(index.0)
22533                        } else {
22534                            cx.theme().players().absent()
22535                        },
22536                    })
22537                }
22538            })
22539    }
22540
22541    pub fn hunks_for_ranges(
22542        &self,
22543        ranges: impl IntoIterator<Item = Range<Point>>,
22544    ) -> Vec<MultiBufferDiffHunk> {
22545        let mut hunks = Vec::new();
22546        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22547            HashMap::default();
22548        for query_range in ranges {
22549            let query_rows =
22550                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22551            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22552                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22553            ) {
22554                // Include deleted hunks that are adjacent to the query range, because
22555                // otherwise they would be missed.
22556                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22557                if hunk.status().is_deleted() {
22558                    intersects_range |= hunk.row_range.start == query_rows.end;
22559                    intersects_range |= hunk.row_range.end == query_rows.start;
22560                }
22561                if intersects_range {
22562                    if !processed_buffer_rows
22563                        .entry(hunk.buffer_id)
22564                        .or_default()
22565                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22566                    {
22567                        continue;
22568                    }
22569                    hunks.push(hunk);
22570                }
22571            }
22572        }
22573
22574        hunks
22575    }
22576
22577    fn display_diff_hunks_for_rows<'a>(
22578        &'a self,
22579        display_rows: Range<DisplayRow>,
22580        folded_buffers: &'a HashSet<BufferId>,
22581    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22582        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22583        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22584
22585        self.buffer_snapshot
22586            .diff_hunks_in_range(buffer_start..buffer_end)
22587            .filter_map(|hunk| {
22588                if folded_buffers.contains(&hunk.buffer_id) {
22589                    return None;
22590                }
22591
22592                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22593                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22594
22595                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22596                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22597
22598                let display_hunk = if hunk_display_start.column() != 0 {
22599                    DisplayDiffHunk::Folded {
22600                        display_row: hunk_display_start.row(),
22601                    }
22602                } else {
22603                    let mut end_row = hunk_display_end.row();
22604                    if hunk_display_end.column() > 0 {
22605                        end_row.0 += 1;
22606                    }
22607                    let is_created_file = hunk.is_created_file();
22608                    DisplayDiffHunk::Unfolded {
22609                        status: hunk.status(),
22610                        diff_base_byte_range: hunk.diff_base_byte_range,
22611                        display_row_range: hunk_display_start.row()..end_row,
22612                        multi_buffer_range: Anchor::range_in_buffer(
22613                            hunk.excerpt_id,
22614                            hunk.buffer_id,
22615                            hunk.buffer_range,
22616                        ),
22617                        is_created_file,
22618                    }
22619                };
22620
22621                Some(display_hunk)
22622            })
22623    }
22624
22625    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22626        self.display_snapshot.buffer_snapshot.language_at(position)
22627    }
22628
22629    pub fn is_focused(&self) -> bool {
22630        self.is_focused
22631    }
22632
22633    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22634        self.placeholder_text.as_ref()
22635    }
22636
22637    pub fn scroll_position(&self) -> gpui::Point<f32> {
22638        self.scroll_anchor.scroll_position(&self.display_snapshot)
22639    }
22640
22641    fn gutter_dimensions(
22642        &self,
22643        font_id: FontId,
22644        font_size: Pixels,
22645        max_line_number_width: Pixels,
22646        cx: &App,
22647    ) -> Option<GutterDimensions> {
22648        if !self.show_gutter {
22649            return None;
22650        }
22651
22652        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22653        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22654
22655        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22656            matches!(
22657                ProjectSettings::get_global(cx).git.git_gutter,
22658                Some(GitGutterSetting::TrackedFiles)
22659            )
22660        });
22661        let gutter_settings = EditorSettings::get_global(cx).gutter;
22662        let show_line_numbers = self
22663            .show_line_numbers
22664            .unwrap_or(gutter_settings.line_numbers);
22665        let line_gutter_width = if show_line_numbers {
22666            // Avoid flicker-like gutter resizes when the line number gains another digit by
22667            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22668            let min_width_for_number_on_gutter =
22669                ch_advance * gutter_settings.min_line_number_digits as f32;
22670            max_line_number_width.max(min_width_for_number_on_gutter)
22671        } else {
22672            0.0.into()
22673        };
22674
22675        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22676        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22677
22678        let git_blame_entries_width =
22679            self.git_blame_gutter_max_author_length
22680                .map(|max_author_length| {
22681                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22682                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22683
22684                    /// The number of characters to dedicate to gaps and margins.
22685                    const SPACING_WIDTH: usize = 4;
22686
22687                    let max_char_count = max_author_length.min(renderer.max_author_length())
22688                        + ::git::SHORT_SHA_LENGTH
22689                        + MAX_RELATIVE_TIMESTAMP.len()
22690                        + SPACING_WIDTH;
22691
22692                    ch_advance * max_char_count
22693                });
22694
22695        let is_singleton = self.buffer_snapshot.is_singleton();
22696
22697        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22698        left_padding += if !is_singleton {
22699            ch_width * 4.0
22700        } else if show_runnables || show_breakpoints {
22701            ch_width * 3.0
22702        } else if show_git_gutter && show_line_numbers {
22703            ch_width * 2.0
22704        } else if show_git_gutter || show_line_numbers {
22705            ch_width
22706        } else {
22707            px(0.)
22708        };
22709
22710        let shows_folds = is_singleton && gutter_settings.folds;
22711
22712        let right_padding = if shows_folds && show_line_numbers {
22713            ch_width * 4.0
22714        } else if shows_folds || (!is_singleton && show_line_numbers) {
22715            ch_width * 3.0
22716        } else if show_line_numbers {
22717            ch_width
22718        } else {
22719            px(0.)
22720        };
22721
22722        Some(GutterDimensions {
22723            left_padding,
22724            right_padding,
22725            width: line_gutter_width + left_padding + right_padding,
22726            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22727            git_blame_entries_width,
22728        })
22729    }
22730
22731    pub fn render_crease_toggle(
22732        &self,
22733        buffer_row: MultiBufferRow,
22734        row_contains_cursor: bool,
22735        editor: Entity<Editor>,
22736        window: &mut Window,
22737        cx: &mut App,
22738    ) -> Option<AnyElement> {
22739        let folded = self.is_line_folded(buffer_row);
22740        let mut is_foldable = false;
22741
22742        if let Some(crease) = self
22743            .crease_snapshot
22744            .query_row(buffer_row, &self.buffer_snapshot)
22745        {
22746            is_foldable = true;
22747            match crease {
22748                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22749                    if let Some(render_toggle) = render_toggle {
22750                        let toggle_callback =
22751                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22752                                if folded {
22753                                    editor.update(cx, |editor, cx| {
22754                                        editor.fold_at(buffer_row, window, cx)
22755                                    });
22756                                } else {
22757                                    editor.update(cx, |editor, cx| {
22758                                        editor.unfold_at(buffer_row, window, cx)
22759                                    });
22760                                }
22761                            });
22762                        return Some((render_toggle)(
22763                            buffer_row,
22764                            folded,
22765                            toggle_callback,
22766                            window,
22767                            cx,
22768                        ));
22769                    }
22770                }
22771            }
22772        }
22773
22774        is_foldable |= self.starts_indent(buffer_row);
22775
22776        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22777            Some(
22778                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22779                    .toggle_state(folded)
22780                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22781                        if folded {
22782                            this.unfold_at(buffer_row, window, cx);
22783                        } else {
22784                            this.fold_at(buffer_row, window, cx);
22785                        }
22786                    }))
22787                    .into_any_element(),
22788            )
22789        } else {
22790            None
22791        }
22792    }
22793
22794    pub fn render_crease_trailer(
22795        &self,
22796        buffer_row: MultiBufferRow,
22797        window: &mut Window,
22798        cx: &mut App,
22799    ) -> Option<AnyElement> {
22800        let folded = self.is_line_folded(buffer_row);
22801        if let Crease::Inline { render_trailer, .. } = self
22802            .crease_snapshot
22803            .query_row(buffer_row, &self.buffer_snapshot)?
22804        {
22805            let render_trailer = render_trailer.as_ref()?;
22806            Some(render_trailer(buffer_row, folded, window, cx))
22807        } else {
22808            None
22809        }
22810    }
22811}
22812
22813impl Deref for EditorSnapshot {
22814    type Target = DisplaySnapshot;
22815
22816    fn deref(&self) -> &Self::Target {
22817        &self.display_snapshot
22818    }
22819}
22820
22821#[derive(Clone, Debug, PartialEq, Eq)]
22822pub enum EditorEvent {
22823    InputIgnored {
22824        text: Arc<str>,
22825    },
22826    InputHandled {
22827        utf16_range_to_replace: Option<Range<isize>>,
22828        text: Arc<str>,
22829    },
22830    ExcerptsAdded {
22831        buffer: Entity<Buffer>,
22832        predecessor: ExcerptId,
22833        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22834    },
22835    ExcerptsRemoved {
22836        ids: Vec<ExcerptId>,
22837        removed_buffer_ids: Vec<BufferId>,
22838    },
22839    BufferFoldToggled {
22840        ids: Vec<ExcerptId>,
22841        folded: bool,
22842    },
22843    ExcerptsEdited {
22844        ids: Vec<ExcerptId>,
22845    },
22846    ExcerptsExpanded {
22847        ids: Vec<ExcerptId>,
22848    },
22849    BufferEdited,
22850    Edited {
22851        transaction_id: clock::Lamport,
22852    },
22853    Reparsed(BufferId),
22854    Focused,
22855    FocusedIn,
22856    Blurred,
22857    DirtyChanged,
22858    Saved,
22859    TitleChanged,
22860    DiffBaseChanged,
22861    SelectionsChanged {
22862        local: bool,
22863    },
22864    ScrollPositionChanged {
22865        local: bool,
22866        autoscroll: bool,
22867    },
22868    Closed,
22869    TransactionUndone {
22870        transaction_id: clock::Lamport,
22871    },
22872    TransactionBegun {
22873        transaction_id: clock::Lamport,
22874    },
22875    Reloaded,
22876    CursorShapeChanged,
22877    BreadcrumbsChanged,
22878    PushedToNavHistory {
22879        anchor: Anchor,
22880        is_deactivate: bool,
22881    },
22882}
22883
22884impl EventEmitter<EditorEvent> for Editor {}
22885
22886impl Focusable for Editor {
22887    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22888        self.focus_handle.clone()
22889    }
22890}
22891
22892impl Render for Editor {
22893    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22894        let settings = ThemeSettings::get_global(cx);
22895
22896        let mut text_style = match self.mode {
22897            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22898                color: cx.theme().colors().editor_foreground,
22899                font_family: settings.ui_font.family.clone(),
22900                font_features: settings.ui_font.features.clone(),
22901                font_fallbacks: settings.ui_font.fallbacks.clone(),
22902                font_size: rems(0.875).into(),
22903                font_weight: settings.ui_font.weight,
22904                line_height: relative(settings.buffer_line_height.value()),
22905                ..Default::default()
22906            },
22907            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22908                color: cx.theme().colors().editor_foreground,
22909                font_family: settings.buffer_font.family.clone(),
22910                font_features: settings.buffer_font.features.clone(),
22911                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22912                font_size: settings.buffer_font_size(cx).into(),
22913                font_weight: settings.buffer_font.weight,
22914                line_height: relative(settings.buffer_line_height.value()),
22915                ..Default::default()
22916            },
22917        };
22918        if let Some(text_style_refinement) = &self.text_style_refinement {
22919            text_style.refine(text_style_refinement)
22920        }
22921
22922        let background = match self.mode {
22923            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22924            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22925            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22926            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22927        };
22928
22929        EditorElement::new(
22930            &cx.entity(),
22931            EditorStyle {
22932                background,
22933                border: cx.theme().colors().border,
22934                local_player: cx.theme().players().local(),
22935                text: text_style,
22936                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22937                syntax: cx.theme().syntax().clone(),
22938                status: cx.theme().status().clone(),
22939                inlay_hints_style: make_inlay_hints_style(cx),
22940                edit_prediction_styles: make_suggestion_styles(cx),
22941                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22942                show_underlines: self.diagnostics_enabled(),
22943            },
22944        )
22945    }
22946}
22947
22948impl EntityInputHandler for Editor {
22949    fn text_for_range(
22950        &mut self,
22951        range_utf16: Range<usize>,
22952        adjusted_range: &mut Option<Range<usize>>,
22953        _: &mut Window,
22954        cx: &mut Context<Self>,
22955    ) -> Option<String> {
22956        let snapshot = self.buffer.read(cx).read(cx);
22957        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22958        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22959        if (start.0..end.0) != range_utf16 {
22960            adjusted_range.replace(start.0..end.0);
22961        }
22962        Some(snapshot.text_for_range(start..end).collect())
22963    }
22964
22965    fn selected_text_range(
22966        &mut self,
22967        ignore_disabled_input: bool,
22968        _: &mut Window,
22969        cx: &mut Context<Self>,
22970    ) -> Option<UTF16Selection> {
22971        // Prevent the IME menu from appearing when holding down an alphabetic key
22972        // while input is disabled.
22973        if !ignore_disabled_input && !self.input_enabled {
22974            return None;
22975        }
22976
22977        let selection = self.selections.newest::<OffsetUtf16>(cx);
22978        let range = selection.range();
22979
22980        Some(UTF16Selection {
22981            range: range.start.0..range.end.0,
22982            reversed: selection.reversed,
22983        })
22984    }
22985
22986    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
22987        let snapshot = self.buffer.read(cx).read(cx);
22988        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
22989        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
22990    }
22991
22992    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22993        self.clear_highlights::<InputComposition>(cx);
22994        self.ime_transaction.take();
22995    }
22996
22997    fn replace_text_in_range(
22998        &mut self,
22999        range_utf16: Option<Range<usize>>,
23000        text: &str,
23001        window: &mut Window,
23002        cx: &mut Context<Self>,
23003    ) {
23004        if !self.input_enabled {
23005            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23006            return;
23007        }
23008
23009        self.transact(window, cx, |this, window, cx| {
23010            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23011                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23012                Some(this.selection_replacement_ranges(range_utf16, cx))
23013            } else {
23014                this.marked_text_ranges(cx)
23015            };
23016
23017            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23018                let newest_selection_id = this.selections.newest_anchor().id;
23019                this.selections
23020                    .all::<OffsetUtf16>(cx)
23021                    .iter()
23022                    .zip(ranges_to_replace.iter())
23023                    .find_map(|(selection, range)| {
23024                        if selection.id == newest_selection_id {
23025                            Some(
23026                                (range.start.0 as isize - selection.head().0 as isize)
23027                                    ..(range.end.0 as isize - selection.head().0 as isize),
23028                            )
23029                        } else {
23030                            None
23031                        }
23032                    })
23033            });
23034
23035            cx.emit(EditorEvent::InputHandled {
23036                utf16_range_to_replace: range_to_replace,
23037                text: text.into(),
23038            });
23039
23040            if let Some(new_selected_ranges) = new_selected_ranges {
23041                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23042                    selections.select_ranges(new_selected_ranges)
23043                });
23044                this.backspace(&Default::default(), window, cx);
23045            }
23046
23047            this.handle_input(text, window, cx);
23048        });
23049
23050        if let Some(transaction) = self.ime_transaction {
23051            self.buffer.update(cx, |buffer, cx| {
23052                buffer.group_until_transaction(transaction, cx);
23053            });
23054        }
23055
23056        self.unmark_text(window, cx);
23057    }
23058
23059    fn replace_and_mark_text_in_range(
23060        &mut self,
23061        range_utf16: Option<Range<usize>>,
23062        text: &str,
23063        new_selected_range_utf16: Option<Range<usize>>,
23064        window: &mut Window,
23065        cx: &mut Context<Self>,
23066    ) {
23067        if !self.input_enabled {
23068            return;
23069        }
23070
23071        let transaction = self.transact(window, cx, |this, window, cx| {
23072            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23073                let snapshot = this.buffer.read(cx).read(cx);
23074                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23075                    for marked_range in &mut marked_ranges {
23076                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23077                        marked_range.start.0 += relative_range_utf16.start;
23078                        marked_range.start =
23079                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23080                        marked_range.end =
23081                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23082                    }
23083                }
23084                Some(marked_ranges)
23085            } else if let Some(range_utf16) = range_utf16 {
23086                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23087                Some(this.selection_replacement_ranges(range_utf16, cx))
23088            } else {
23089                None
23090            };
23091
23092            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23093                let newest_selection_id = this.selections.newest_anchor().id;
23094                this.selections
23095                    .all::<OffsetUtf16>(cx)
23096                    .iter()
23097                    .zip(ranges_to_replace.iter())
23098                    .find_map(|(selection, range)| {
23099                        if selection.id == newest_selection_id {
23100                            Some(
23101                                (range.start.0 as isize - selection.head().0 as isize)
23102                                    ..(range.end.0 as isize - selection.head().0 as isize),
23103                            )
23104                        } else {
23105                            None
23106                        }
23107                    })
23108            });
23109
23110            cx.emit(EditorEvent::InputHandled {
23111                utf16_range_to_replace: range_to_replace,
23112                text: text.into(),
23113            });
23114
23115            if let Some(ranges) = ranges_to_replace {
23116                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23117                    s.select_ranges(ranges)
23118                });
23119            }
23120
23121            let marked_ranges = {
23122                let snapshot = this.buffer.read(cx).read(cx);
23123                this.selections
23124                    .disjoint_anchors()
23125                    .iter()
23126                    .map(|selection| {
23127                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23128                    })
23129                    .collect::<Vec<_>>()
23130            };
23131
23132            if text.is_empty() {
23133                this.unmark_text(window, cx);
23134            } else {
23135                this.highlight_text::<InputComposition>(
23136                    marked_ranges.clone(),
23137                    HighlightStyle {
23138                        underline: Some(UnderlineStyle {
23139                            thickness: px(1.),
23140                            color: None,
23141                            wavy: false,
23142                        }),
23143                        ..Default::default()
23144                    },
23145                    cx,
23146                );
23147            }
23148
23149            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23150            let use_autoclose = this.use_autoclose;
23151            let use_auto_surround = this.use_auto_surround;
23152            this.set_use_autoclose(false);
23153            this.set_use_auto_surround(false);
23154            this.handle_input(text, window, cx);
23155            this.set_use_autoclose(use_autoclose);
23156            this.set_use_auto_surround(use_auto_surround);
23157
23158            if let Some(new_selected_range) = new_selected_range_utf16 {
23159                let snapshot = this.buffer.read(cx).read(cx);
23160                let new_selected_ranges = marked_ranges
23161                    .into_iter()
23162                    .map(|marked_range| {
23163                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23164                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23165                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23166                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23167                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23168                    })
23169                    .collect::<Vec<_>>();
23170
23171                drop(snapshot);
23172                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23173                    selections.select_ranges(new_selected_ranges)
23174                });
23175            }
23176        });
23177
23178        self.ime_transaction = self.ime_transaction.or(transaction);
23179        if let Some(transaction) = self.ime_transaction {
23180            self.buffer.update(cx, |buffer, cx| {
23181                buffer.group_until_transaction(transaction, cx);
23182            });
23183        }
23184
23185        if self.text_highlights::<InputComposition>(cx).is_none() {
23186            self.ime_transaction.take();
23187        }
23188    }
23189
23190    fn bounds_for_range(
23191        &mut self,
23192        range_utf16: Range<usize>,
23193        element_bounds: gpui::Bounds<Pixels>,
23194        window: &mut Window,
23195        cx: &mut Context<Self>,
23196    ) -> Option<gpui::Bounds<Pixels>> {
23197        let text_layout_details = self.text_layout_details(window);
23198        let CharacterDimensions {
23199            em_width,
23200            em_advance,
23201            line_height,
23202        } = self.character_dimensions(window);
23203
23204        let snapshot = self.snapshot(window, cx);
23205        let scroll_position = snapshot.scroll_position();
23206        let scroll_left = scroll_position.x * em_advance;
23207
23208        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23209        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23210            + self.gutter_dimensions.full_width();
23211        let y = line_height * (start.row().as_f32() - scroll_position.y);
23212
23213        Some(Bounds {
23214            origin: element_bounds.origin + point(x, y),
23215            size: size(em_width, line_height),
23216        })
23217    }
23218
23219    fn character_index_for_point(
23220        &mut self,
23221        point: gpui::Point<Pixels>,
23222        _window: &mut Window,
23223        _cx: &mut Context<Self>,
23224    ) -> Option<usize> {
23225        let position_map = self.last_position_map.as_ref()?;
23226        if !position_map.text_hitbox.contains(&point) {
23227            return None;
23228        }
23229        let display_point = position_map.point_for_position(point).previous_valid;
23230        let anchor = position_map
23231            .snapshot
23232            .display_point_to_anchor(display_point, Bias::Left);
23233        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23234        Some(utf16_offset.0)
23235    }
23236}
23237
23238trait SelectionExt {
23239    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23240    fn spanned_rows(
23241        &self,
23242        include_end_if_at_line_start: bool,
23243        map: &DisplaySnapshot,
23244    ) -> Range<MultiBufferRow>;
23245}
23246
23247impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23248    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23249        let start = self
23250            .start
23251            .to_point(&map.buffer_snapshot)
23252            .to_display_point(map);
23253        let end = self
23254            .end
23255            .to_point(&map.buffer_snapshot)
23256            .to_display_point(map);
23257        if self.reversed {
23258            end..start
23259        } else {
23260            start..end
23261        }
23262    }
23263
23264    fn spanned_rows(
23265        &self,
23266        include_end_if_at_line_start: bool,
23267        map: &DisplaySnapshot,
23268    ) -> Range<MultiBufferRow> {
23269        let start = self.start.to_point(&map.buffer_snapshot);
23270        let mut end = self.end.to_point(&map.buffer_snapshot);
23271        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23272            end.row -= 1;
23273        }
23274
23275        let buffer_start = map.prev_line_boundary(start).0;
23276        let buffer_end = map.next_line_boundary(end).0;
23277        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23278    }
23279}
23280
23281impl<T: InvalidationRegion> InvalidationStack<T> {
23282    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23283    where
23284        S: Clone + ToOffset,
23285    {
23286        while let Some(region) = self.last() {
23287            let all_selections_inside_invalidation_ranges =
23288                if selections.len() == region.ranges().len() {
23289                    selections
23290                        .iter()
23291                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23292                        .all(|(selection, invalidation_range)| {
23293                            let head = selection.head().to_offset(buffer);
23294                            invalidation_range.start <= head && invalidation_range.end >= head
23295                        })
23296                } else {
23297                    false
23298                };
23299
23300            if all_selections_inside_invalidation_ranges {
23301                break;
23302            } else {
23303                self.pop();
23304            }
23305        }
23306    }
23307}
23308
23309impl<T> Default for InvalidationStack<T> {
23310    fn default() -> Self {
23311        Self(Default::default())
23312    }
23313}
23314
23315impl<T> Deref for InvalidationStack<T> {
23316    type Target = Vec<T>;
23317
23318    fn deref(&self) -> &Self::Target {
23319        &self.0
23320    }
23321}
23322
23323impl<T> DerefMut for InvalidationStack<T> {
23324    fn deref_mut(&mut self) -> &mut Self::Target {
23325        &mut self.0
23326    }
23327}
23328
23329impl InvalidationRegion for SnippetState {
23330    fn ranges(&self) -> &[Range<Anchor>] {
23331        &self.ranges[self.active_index]
23332    }
23333}
23334
23335fn edit_prediction_edit_text(
23336    current_snapshot: &BufferSnapshot,
23337    edits: &[(Range<Anchor>, String)],
23338    edit_preview: &EditPreview,
23339    include_deletions: bool,
23340    cx: &App,
23341) -> HighlightedText {
23342    let edits = edits
23343        .iter()
23344        .map(|(anchor, text)| {
23345            (
23346                anchor.start.text_anchor..anchor.end.text_anchor,
23347                text.clone(),
23348            )
23349        })
23350        .collect::<Vec<_>>();
23351
23352    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23353}
23354
23355fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23356    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23357    // Just show the raw edit text with basic styling
23358    let mut text = String::new();
23359    let mut highlights = Vec::new();
23360
23361    let insertion_highlight_style = HighlightStyle {
23362        color: Some(cx.theme().colors().text),
23363        ..Default::default()
23364    };
23365
23366    for (_, edit_text) in edits {
23367        let start_offset = text.len();
23368        text.push_str(edit_text);
23369        let end_offset = text.len();
23370
23371        if start_offset < end_offset {
23372            highlights.push((start_offset..end_offset, insertion_highlight_style));
23373        }
23374    }
23375
23376    HighlightedText {
23377        text: text.into(),
23378        highlights,
23379    }
23380}
23381
23382pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23383    match severity {
23384        lsp::DiagnosticSeverity::ERROR => colors.error,
23385        lsp::DiagnosticSeverity::WARNING => colors.warning,
23386        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23387        lsp::DiagnosticSeverity::HINT => colors.info,
23388        _ => colors.ignored,
23389    }
23390}
23391
23392pub fn styled_runs_for_code_label<'a>(
23393    label: &'a CodeLabel,
23394    syntax_theme: &'a theme::SyntaxTheme,
23395) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23396    let fade_out = HighlightStyle {
23397        fade_out: Some(0.35),
23398        ..Default::default()
23399    };
23400
23401    let mut prev_end = label.filter_range.end;
23402    label
23403        .runs
23404        .iter()
23405        .enumerate()
23406        .flat_map(move |(ix, (range, highlight_id))| {
23407            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23408                style
23409            } else {
23410                return Default::default();
23411            };
23412            let mut muted_style = style;
23413            muted_style.highlight(fade_out);
23414
23415            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23416            if range.start >= label.filter_range.end {
23417                if range.start > prev_end {
23418                    runs.push((prev_end..range.start, fade_out));
23419                }
23420                runs.push((range.clone(), muted_style));
23421            } else if range.end <= label.filter_range.end {
23422                runs.push((range.clone(), style));
23423            } else {
23424                runs.push((range.start..label.filter_range.end, style));
23425                runs.push((label.filter_range.end..range.end, muted_style));
23426            }
23427            prev_end = cmp::max(prev_end, range.end);
23428
23429            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23430                runs.push((prev_end..label.text.len(), fade_out));
23431            }
23432
23433            runs
23434        })
23435}
23436
23437pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23438    let mut prev_index = 0;
23439    let mut prev_codepoint: Option<char> = None;
23440    text.char_indices()
23441        .chain([(text.len(), '\0')])
23442        .filter_map(move |(index, codepoint)| {
23443            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23444            let is_boundary = index == text.len()
23445                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23446                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23447            if is_boundary {
23448                let chunk = &text[prev_index..index];
23449                prev_index = index;
23450                Some(chunk)
23451            } else {
23452                None
23453            }
23454        })
23455}
23456
23457pub trait RangeToAnchorExt: Sized {
23458    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23459
23460    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23461        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23462        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23463    }
23464}
23465
23466impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23467    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23468        let start_offset = self.start.to_offset(snapshot);
23469        let end_offset = self.end.to_offset(snapshot);
23470        if start_offset == end_offset {
23471            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23472        } else {
23473            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23474        }
23475    }
23476}
23477
23478pub trait RowExt {
23479    fn as_f32(&self) -> f32;
23480
23481    fn next_row(&self) -> Self;
23482
23483    fn previous_row(&self) -> Self;
23484
23485    fn minus(&self, other: Self) -> u32;
23486}
23487
23488impl RowExt for DisplayRow {
23489    fn as_f32(&self) -> f32 {
23490        self.0 as f32
23491    }
23492
23493    fn next_row(&self) -> Self {
23494        Self(self.0 + 1)
23495    }
23496
23497    fn previous_row(&self) -> Self {
23498        Self(self.0.saturating_sub(1))
23499    }
23500
23501    fn minus(&self, other: Self) -> u32 {
23502        self.0 - other.0
23503    }
23504}
23505
23506impl RowExt for MultiBufferRow {
23507    fn as_f32(&self) -> f32 {
23508        self.0 as f32
23509    }
23510
23511    fn next_row(&self) -> Self {
23512        Self(self.0 + 1)
23513    }
23514
23515    fn previous_row(&self) -> Self {
23516        Self(self.0.saturating_sub(1))
23517    }
23518
23519    fn minus(&self, other: Self) -> u32 {
23520        self.0 - other.0
23521    }
23522}
23523
23524trait RowRangeExt {
23525    type Row;
23526
23527    fn len(&self) -> usize;
23528
23529    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23530}
23531
23532impl RowRangeExt for Range<MultiBufferRow> {
23533    type Row = MultiBufferRow;
23534
23535    fn len(&self) -> usize {
23536        (self.end.0 - self.start.0) as usize
23537    }
23538
23539    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23540        (self.start.0..self.end.0).map(MultiBufferRow)
23541    }
23542}
23543
23544impl RowRangeExt for Range<DisplayRow> {
23545    type Row = DisplayRow;
23546
23547    fn len(&self) -> usize {
23548        (self.end.0 - self.start.0) as usize
23549    }
23550
23551    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23552        (self.start.0..self.end.0).map(DisplayRow)
23553    }
23554}
23555
23556/// If select range has more than one line, we
23557/// just point the cursor to range.start.
23558fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23559    if range.start.row == range.end.row {
23560        range
23561    } else {
23562        range.start..range.start
23563    }
23564}
23565pub struct KillRing(ClipboardItem);
23566impl Global for KillRing {}
23567
23568const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23569
23570enum BreakpointPromptEditAction {
23571    Log,
23572    Condition,
23573    HitCondition,
23574}
23575
23576struct BreakpointPromptEditor {
23577    pub(crate) prompt: Entity<Editor>,
23578    editor: WeakEntity<Editor>,
23579    breakpoint_anchor: Anchor,
23580    breakpoint: Breakpoint,
23581    edit_action: BreakpointPromptEditAction,
23582    block_ids: HashSet<CustomBlockId>,
23583    editor_margins: Arc<Mutex<EditorMargins>>,
23584    _subscriptions: Vec<Subscription>,
23585}
23586
23587impl BreakpointPromptEditor {
23588    const MAX_LINES: u8 = 4;
23589
23590    fn new(
23591        editor: WeakEntity<Editor>,
23592        breakpoint_anchor: Anchor,
23593        breakpoint: Breakpoint,
23594        edit_action: BreakpointPromptEditAction,
23595        window: &mut Window,
23596        cx: &mut Context<Self>,
23597    ) -> Self {
23598        let base_text = match edit_action {
23599            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23600            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23601            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23602        }
23603        .map(|msg| msg.to_string())
23604        .unwrap_or_default();
23605
23606        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23607        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23608
23609        let prompt = cx.new(|cx| {
23610            let mut prompt = Editor::new(
23611                EditorMode::AutoHeight {
23612                    min_lines: 1,
23613                    max_lines: Some(Self::MAX_LINES as usize),
23614                },
23615                buffer,
23616                None,
23617                window,
23618                cx,
23619            );
23620            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23621            prompt.set_show_cursor_when_unfocused(false, cx);
23622            prompt.set_placeholder_text(
23623                match edit_action {
23624                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23625                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23626                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23627                },
23628                cx,
23629            );
23630
23631            prompt
23632        });
23633
23634        Self {
23635            prompt,
23636            editor,
23637            breakpoint_anchor,
23638            breakpoint,
23639            edit_action,
23640            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23641            block_ids: Default::default(),
23642            _subscriptions: vec![],
23643        }
23644    }
23645
23646    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23647        self.block_ids.extend(block_ids)
23648    }
23649
23650    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23651        if let Some(editor) = self.editor.upgrade() {
23652            let message = self
23653                .prompt
23654                .read(cx)
23655                .buffer
23656                .read(cx)
23657                .as_singleton()
23658                .expect("A multi buffer in breakpoint prompt isn't possible")
23659                .read(cx)
23660                .as_rope()
23661                .to_string();
23662
23663            editor.update(cx, |editor, cx| {
23664                editor.edit_breakpoint_at_anchor(
23665                    self.breakpoint_anchor,
23666                    self.breakpoint.clone(),
23667                    match self.edit_action {
23668                        BreakpointPromptEditAction::Log => {
23669                            BreakpointEditAction::EditLogMessage(message.into())
23670                        }
23671                        BreakpointPromptEditAction::Condition => {
23672                            BreakpointEditAction::EditCondition(message.into())
23673                        }
23674                        BreakpointPromptEditAction::HitCondition => {
23675                            BreakpointEditAction::EditHitCondition(message.into())
23676                        }
23677                    },
23678                    cx,
23679                );
23680
23681                editor.remove_blocks(self.block_ids.clone(), None, cx);
23682                cx.focus_self(window);
23683            });
23684        }
23685    }
23686
23687    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23688        self.editor
23689            .update(cx, |editor, cx| {
23690                editor.remove_blocks(self.block_ids.clone(), None, cx);
23691                window.focus(&editor.focus_handle);
23692            })
23693            .log_err();
23694    }
23695
23696    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23697        let settings = ThemeSettings::get_global(cx);
23698        let text_style = TextStyle {
23699            color: if self.prompt.read(cx).read_only(cx) {
23700                cx.theme().colors().text_disabled
23701            } else {
23702                cx.theme().colors().text
23703            },
23704            font_family: settings.buffer_font.family.clone(),
23705            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23706            font_size: settings.buffer_font_size(cx).into(),
23707            font_weight: settings.buffer_font.weight,
23708            line_height: relative(settings.buffer_line_height.value()),
23709            ..Default::default()
23710        };
23711        EditorElement::new(
23712            &self.prompt,
23713            EditorStyle {
23714                background: cx.theme().colors().editor_background,
23715                local_player: cx.theme().players().local(),
23716                text: text_style,
23717                ..Default::default()
23718            },
23719        )
23720    }
23721}
23722
23723impl Render for BreakpointPromptEditor {
23724    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23725        let editor_margins = *self.editor_margins.lock();
23726        let gutter_dimensions = editor_margins.gutter;
23727        h_flex()
23728            .key_context("Editor")
23729            .bg(cx.theme().colors().editor_background)
23730            .border_y_1()
23731            .border_color(cx.theme().status().info_border)
23732            .size_full()
23733            .py(window.line_height() / 2.5)
23734            .on_action(cx.listener(Self::confirm))
23735            .on_action(cx.listener(Self::cancel))
23736            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23737            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23738    }
23739}
23740
23741impl Focusable for BreakpointPromptEditor {
23742    fn focus_handle(&self, cx: &App) -> FocusHandle {
23743        self.prompt.focus_handle(cx)
23744    }
23745}
23746
23747fn all_edits_insertions_or_deletions(
23748    edits: &Vec<(Range<Anchor>, String)>,
23749    snapshot: &MultiBufferSnapshot,
23750) -> bool {
23751    let mut all_insertions = true;
23752    let mut all_deletions = true;
23753
23754    for (range, new_text) in edits.iter() {
23755        let range_is_empty = range.to_offset(&snapshot).is_empty();
23756        let text_is_empty = new_text.is_empty();
23757
23758        if range_is_empty != text_is_empty {
23759            if range_is_empty {
23760                all_deletions = false;
23761            } else {
23762                all_insertions = false;
23763            }
23764        } else {
23765            return false;
23766        }
23767
23768        if !all_insertions && !all_deletions {
23769            return false;
23770        }
23771    }
23772    all_insertions || all_deletions
23773}
23774
23775struct MissingEditPredictionKeybindingTooltip;
23776
23777impl Render for MissingEditPredictionKeybindingTooltip {
23778    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23779        ui::tooltip_container(window, cx, |container, _, cx| {
23780            container
23781                .flex_shrink_0()
23782                .max_w_80()
23783                .min_h(rems_from_px(124.))
23784                .justify_between()
23785                .child(
23786                    v_flex()
23787                        .flex_1()
23788                        .text_ui_sm(cx)
23789                        .child(Label::new("Conflict with Accept Keybinding"))
23790                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23791                )
23792                .child(
23793                    h_flex()
23794                        .pb_1()
23795                        .gap_1()
23796                        .items_end()
23797                        .w_full()
23798                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23799                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23800                        }))
23801                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23802                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23803                        })),
23804                )
23805        })
23806    }
23807}
23808
23809#[derive(Debug, Clone, Copy, PartialEq)]
23810pub struct LineHighlight {
23811    pub background: Background,
23812    pub border: Option<gpui::Hsla>,
23813    pub include_gutter: bool,
23814    pub type_id: Option<TypeId>,
23815}
23816
23817struct LineManipulationResult {
23818    pub new_text: String,
23819    pub line_count_before: usize,
23820    pub line_count_after: usize,
23821}
23822
23823fn render_diff_hunk_controls(
23824    row: u32,
23825    status: &DiffHunkStatus,
23826    hunk_range: Range<Anchor>,
23827    is_created_file: bool,
23828    line_height: Pixels,
23829    editor: &Entity<Editor>,
23830    _window: &mut Window,
23831    cx: &mut App,
23832) -> AnyElement {
23833    h_flex()
23834        .h(line_height)
23835        .mr_1()
23836        .gap_1()
23837        .px_0p5()
23838        .pb_1()
23839        .border_x_1()
23840        .border_b_1()
23841        .border_color(cx.theme().colors().border_variant)
23842        .rounded_b_lg()
23843        .bg(cx.theme().colors().editor_background)
23844        .gap_1()
23845        .block_mouse_except_scroll()
23846        .shadow_md()
23847        .child(if status.has_secondary_hunk() {
23848            Button::new(("stage", row as u64), "Stage")
23849                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23850                .tooltip({
23851                    let focus_handle = editor.focus_handle(cx);
23852                    move |window, cx| {
23853                        Tooltip::for_action_in(
23854                            "Stage Hunk",
23855                            &::git::ToggleStaged,
23856                            &focus_handle,
23857                            window,
23858                            cx,
23859                        )
23860                    }
23861                })
23862                .on_click({
23863                    let editor = editor.clone();
23864                    move |_event, _window, cx| {
23865                        editor.update(cx, |editor, cx| {
23866                            editor.stage_or_unstage_diff_hunks(
23867                                true,
23868                                vec![hunk_range.start..hunk_range.start],
23869                                cx,
23870                            );
23871                        });
23872                    }
23873                })
23874        } else {
23875            Button::new(("unstage", row as u64), "Unstage")
23876                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23877                .tooltip({
23878                    let focus_handle = editor.focus_handle(cx);
23879                    move |window, cx| {
23880                        Tooltip::for_action_in(
23881                            "Unstage Hunk",
23882                            &::git::ToggleStaged,
23883                            &focus_handle,
23884                            window,
23885                            cx,
23886                        )
23887                    }
23888                })
23889                .on_click({
23890                    let editor = editor.clone();
23891                    move |_event, _window, cx| {
23892                        editor.update(cx, |editor, cx| {
23893                            editor.stage_or_unstage_diff_hunks(
23894                                false,
23895                                vec![hunk_range.start..hunk_range.start],
23896                                cx,
23897                            );
23898                        });
23899                    }
23900                })
23901        })
23902        .child(
23903            Button::new(("restore", row as u64), "Restore")
23904                .tooltip({
23905                    let focus_handle = editor.focus_handle(cx);
23906                    move |window, cx| {
23907                        Tooltip::for_action_in(
23908                            "Restore Hunk",
23909                            &::git::Restore,
23910                            &focus_handle,
23911                            window,
23912                            cx,
23913                        )
23914                    }
23915                })
23916                .on_click({
23917                    let editor = editor.clone();
23918                    move |_event, window, cx| {
23919                        editor.update(cx, |editor, cx| {
23920                            let snapshot = editor.snapshot(window, cx);
23921                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23922                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23923                        });
23924                    }
23925                })
23926                .disabled(is_created_file),
23927        )
23928        .when(
23929            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23930            |el| {
23931                el.child(
23932                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23933                        .shape(IconButtonShape::Square)
23934                        .icon_size(IconSize::Small)
23935                        // .disabled(!has_multiple_hunks)
23936                        .tooltip({
23937                            let focus_handle = editor.focus_handle(cx);
23938                            move |window, cx| {
23939                                Tooltip::for_action_in(
23940                                    "Next Hunk",
23941                                    &GoToHunk,
23942                                    &focus_handle,
23943                                    window,
23944                                    cx,
23945                                )
23946                            }
23947                        })
23948                        .on_click({
23949                            let editor = editor.clone();
23950                            move |_event, window, cx| {
23951                                editor.update(cx, |editor, cx| {
23952                                    let snapshot = editor.snapshot(window, cx);
23953                                    let position =
23954                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23955                                    editor.go_to_hunk_before_or_after_position(
23956                                        &snapshot,
23957                                        position,
23958                                        Direction::Next,
23959                                        window,
23960                                        cx,
23961                                    );
23962                                    editor.expand_selected_diff_hunks(cx);
23963                                });
23964                            }
23965                        }),
23966                )
23967                .child(
23968                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23969                        .shape(IconButtonShape::Square)
23970                        .icon_size(IconSize::Small)
23971                        // .disabled(!has_multiple_hunks)
23972                        .tooltip({
23973                            let focus_handle = editor.focus_handle(cx);
23974                            move |window, cx| {
23975                                Tooltip::for_action_in(
23976                                    "Previous Hunk",
23977                                    &GoToPreviousHunk,
23978                                    &focus_handle,
23979                                    window,
23980                                    cx,
23981                                )
23982                            }
23983                        })
23984                        .on_click({
23985                            let editor = editor.clone();
23986                            move |_event, window, cx| {
23987                                editor.update(cx, |editor, cx| {
23988                                    let snapshot = editor.snapshot(window, cx);
23989                                    let point =
23990                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
23991                                    editor.go_to_hunk_before_or_after_position(
23992                                        &snapshot,
23993                                        point,
23994                                        Direction::Prev,
23995                                        window,
23996                                        cx,
23997                                    );
23998                                    editor.expand_selected_diff_hunks(cx);
23999                                });
24000                            }
24001                        }),
24002                )
24003            },
24004        )
24005        .into_any_element()
24006}