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            && let Some(current) = last.current.as_mut()
  947        {
  948            mem::swap(&mut last.original, current);
  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    project: Option<Entity<Project>>,
 1043    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1044    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1045    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1046    blink_manager: Entity<BlinkManager>,
 1047    show_cursor_names: bool,
 1048    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1049    pub show_local_selections: bool,
 1050    mode: EditorMode,
 1051    show_breadcrumbs: bool,
 1052    show_gutter: bool,
 1053    show_scrollbars: ScrollbarAxes,
 1054    minimap_visibility: MinimapVisibility,
 1055    offset_content: bool,
 1056    disable_expand_excerpt_buttons: bool,
 1057    show_line_numbers: Option<bool>,
 1058    use_relative_line_numbers: Option<bool>,
 1059    show_git_diff_gutter: Option<bool>,
 1060    show_code_actions: Option<bool>,
 1061    show_runnables: Option<bool>,
 1062    show_breakpoints: Option<bool>,
 1063    show_wrap_guides: Option<bool>,
 1064    show_indent_guides: Option<bool>,
 1065    placeholder_text: Option<Arc<str>>,
 1066    highlight_order: usize,
 1067    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1068    background_highlights: TreeMap<HighlightKey, BackgroundHighlight>,
 1069    gutter_highlights: TreeMap<TypeId, GutterHighlight>,
 1070    scrollbar_marker_state: ScrollbarMarkerState,
 1071    active_indent_guides_state: ActiveIndentGuidesState,
 1072    nav_history: Option<ItemNavHistory>,
 1073    context_menu: RefCell<Option<CodeContextMenu>>,
 1074    context_menu_options: Option<ContextMenuOptions>,
 1075    mouse_context_menu: Option<MouseContextMenu>,
 1076    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1077    inline_blame_popover: Option<InlineBlamePopover>,
 1078    inline_blame_popover_show_task: Option<Task<()>>,
 1079    signature_help_state: SignatureHelpState,
 1080    auto_signature_help: Option<bool>,
 1081    find_all_references_task_sources: Vec<Anchor>,
 1082    next_completion_id: CompletionId,
 1083    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1084    code_actions_task: Option<Task<Result<()>>>,
 1085    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1086    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1087    document_highlights_task: Option<Task<()>>,
 1088    linked_editing_range_task: Option<Task<Option<()>>>,
 1089    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1090    pending_rename: Option<RenameState>,
 1091    searchable: bool,
 1092    cursor_shape: CursorShape,
 1093    current_line_highlight: Option<CurrentLineHighlight>,
 1094    collapse_matches: bool,
 1095    autoindent_mode: Option<AutoindentMode>,
 1096    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1097    input_enabled: bool,
 1098    use_modal_editing: bool,
 1099    read_only: bool,
 1100    leader_id: Option<CollaboratorId>,
 1101    remote_id: Option<ViewId>,
 1102    pub hover_state: HoverState,
 1103    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1104    gutter_hovered: bool,
 1105    hovered_link_state: Option<HoveredLinkState>,
 1106    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1107    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1108    active_edit_prediction: Option<EditPredictionState>,
 1109    /// Used to prevent flickering as the user types while the menu is open
 1110    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1111    edit_prediction_settings: EditPredictionSettings,
 1112    edit_predictions_hidden_for_vim_mode: bool,
 1113    show_edit_predictions_override: Option<bool>,
 1114    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1115    edit_prediction_preview: EditPredictionPreview,
 1116    edit_prediction_indent_conflict: bool,
 1117    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1118    inlay_hint_cache: InlayHintCache,
 1119    next_inlay_id: usize,
 1120    _subscriptions: Vec<Subscription>,
 1121    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1122    gutter_dimensions: GutterDimensions,
 1123    style: Option<EditorStyle>,
 1124    text_style_refinement: Option<TextStyleRefinement>,
 1125    next_editor_action_id: EditorActionId,
 1126    editor_actions: Rc<
 1127        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1128    >,
 1129    use_autoclose: bool,
 1130    use_auto_surround: bool,
 1131    auto_replace_emoji_shortcode: bool,
 1132    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1133    show_git_blame_gutter: bool,
 1134    show_git_blame_inline: bool,
 1135    show_git_blame_inline_delay_task: Option<Task<()>>,
 1136    git_blame_inline_enabled: bool,
 1137    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1138    serialize_dirty_buffers: bool,
 1139    show_selection_menu: Option<bool>,
 1140    blame: Option<Entity<GitBlame>>,
 1141    blame_subscription: Option<Subscription>,
 1142    custom_context_menu: Option<
 1143        Box<
 1144            dyn 'static
 1145                + Fn(
 1146                    &mut Self,
 1147                    DisplayPoint,
 1148                    &mut Window,
 1149                    &mut Context<Self>,
 1150                ) -> Option<Entity<ui::ContextMenu>>,
 1151        >,
 1152    >,
 1153    last_bounds: Option<Bounds<Pixels>>,
 1154    last_position_map: Option<Rc<PositionMap>>,
 1155    expect_bounds_change: Option<Bounds<Pixels>>,
 1156    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1157    tasks_update_task: Option<Task<()>>,
 1158    breakpoint_store: Option<Entity<BreakpointStore>>,
 1159    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1160    hovered_diff_hunk_row: Option<DisplayRow>,
 1161    pull_diagnostics_task: Task<()>,
 1162    in_project_search: bool,
 1163    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1164    breadcrumb_header: Option<String>,
 1165    focused_block: Option<FocusedBlock>,
 1166    next_scroll_position: NextScrollCursorCenterTopBottom,
 1167    addons: HashMap<TypeId, Box<dyn Addon>>,
 1168    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1169    load_diff_task: Option<Shared<Task<()>>>,
 1170    /// Whether we are temporarily displaying a diff other than git's
 1171    temporary_diff_override: bool,
 1172    selection_mark_mode: bool,
 1173    toggle_fold_multiple_buffers: Task<()>,
 1174    _scroll_cursor_center_top_bottom_task: Task<()>,
 1175    serialize_selections: Task<()>,
 1176    serialize_folds: Task<()>,
 1177    mouse_cursor_hidden: bool,
 1178    minimap: Option<Entity<Self>>,
 1179    hide_mouse_mode: HideMouseMode,
 1180    pub change_list: ChangeList,
 1181    inline_value_cache: InlineValueCache,
 1182    selection_drag_state: SelectionDragState,
 1183    next_color_inlay_id: usize,
 1184    colors: Option<LspColorData>,
 1185    folding_newlines: Task<()>,
 1186}
 1187
 1188#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1189enum NextScrollCursorCenterTopBottom {
 1190    #[default]
 1191    Center,
 1192    Top,
 1193    Bottom,
 1194}
 1195
 1196impl NextScrollCursorCenterTopBottom {
 1197    fn next(&self) -> Self {
 1198        match self {
 1199            Self::Center => Self::Top,
 1200            Self::Top => Self::Bottom,
 1201            Self::Bottom => Self::Center,
 1202        }
 1203    }
 1204}
 1205
 1206#[derive(Clone)]
 1207pub struct EditorSnapshot {
 1208    pub mode: EditorMode,
 1209    show_gutter: bool,
 1210    show_line_numbers: Option<bool>,
 1211    show_git_diff_gutter: Option<bool>,
 1212    show_code_actions: Option<bool>,
 1213    show_runnables: Option<bool>,
 1214    show_breakpoints: Option<bool>,
 1215    git_blame_gutter_max_author_length: Option<usize>,
 1216    pub display_snapshot: DisplaySnapshot,
 1217    pub placeholder_text: Option<Arc<str>>,
 1218    is_focused: bool,
 1219    scroll_anchor: ScrollAnchor,
 1220    ongoing_scroll: OngoingScroll,
 1221    current_line_highlight: CurrentLineHighlight,
 1222    gutter_hovered: bool,
 1223}
 1224
 1225#[derive(Default, Debug, Clone, Copy)]
 1226pub struct GutterDimensions {
 1227    pub left_padding: Pixels,
 1228    pub right_padding: Pixels,
 1229    pub width: Pixels,
 1230    pub margin: Pixels,
 1231    pub git_blame_entries_width: Option<Pixels>,
 1232}
 1233
 1234impl GutterDimensions {
 1235    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1236        Self {
 1237            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1238            ..Default::default()
 1239        }
 1240    }
 1241
 1242    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1243        -cx.text_system().descent(font_id, font_size)
 1244    }
 1245    /// The full width of the space taken up by the gutter.
 1246    pub fn full_width(&self) -> Pixels {
 1247        self.margin + self.width
 1248    }
 1249
 1250    /// The width of the space reserved for the fold indicators,
 1251    /// use alongside 'justify_end' and `gutter_width` to
 1252    /// right align content with the line numbers
 1253    pub fn fold_area_width(&self) -> Pixels {
 1254        self.margin + self.right_padding
 1255    }
 1256}
 1257
 1258struct CharacterDimensions {
 1259    em_width: Pixels,
 1260    em_advance: Pixels,
 1261    line_height: Pixels,
 1262}
 1263
 1264#[derive(Debug)]
 1265pub struct RemoteSelection {
 1266    pub replica_id: ReplicaId,
 1267    pub selection: Selection<Anchor>,
 1268    pub cursor_shape: CursorShape,
 1269    pub collaborator_id: CollaboratorId,
 1270    pub line_mode: bool,
 1271    pub user_name: Option<SharedString>,
 1272    pub color: PlayerColor,
 1273}
 1274
 1275#[derive(Clone, Debug)]
 1276struct SelectionHistoryEntry {
 1277    selections: Arc<[Selection<Anchor>]>,
 1278    select_next_state: Option<SelectNextState>,
 1279    select_prev_state: Option<SelectNextState>,
 1280    add_selections_state: Option<AddSelectionsState>,
 1281}
 1282
 1283#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1284enum SelectionHistoryMode {
 1285    Normal,
 1286    Undoing,
 1287    Redoing,
 1288    Skipping,
 1289}
 1290
 1291#[derive(Clone, PartialEq, Eq, Hash)]
 1292struct HoveredCursor {
 1293    replica_id: u16,
 1294    selection_id: usize,
 1295}
 1296
 1297impl Default for SelectionHistoryMode {
 1298    fn default() -> Self {
 1299        Self::Normal
 1300    }
 1301}
 1302
 1303#[derive(Debug)]
 1304/// SelectionEffects controls the side-effects of updating the selection.
 1305///
 1306/// The default behaviour does "what you mostly want":
 1307/// - it pushes to the nav history if the cursor moved by >10 lines
 1308/// - it re-triggers completion requests
 1309/// - it scrolls to fit
 1310///
 1311/// You might want to modify these behaviours. For example when doing a "jump"
 1312/// like go to definition, we always want to add to nav history; but when scrolling
 1313/// in vim mode we never do.
 1314///
 1315/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1316/// move.
 1317#[derive(Clone)]
 1318pub struct SelectionEffects {
 1319    nav_history: Option<bool>,
 1320    completions: bool,
 1321    scroll: Option<Autoscroll>,
 1322}
 1323
 1324impl Default for SelectionEffects {
 1325    fn default() -> Self {
 1326        Self {
 1327            nav_history: None,
 1328            completions: true,
 1329            scroll: Some(Autoscroll::fit()),
 1330        }
 1331    }
 1332}
 1333impl SelectionEffects {
 1334    pub fn scroll(scroll: Autoscroll) -> Self {
 1335        Self {
 1336            scroll: Some(scroll),
 1337            ..Default::default()
 1338        }
 1339    }
 1340
 1341    pub fn no_scroll() -> Self {
 1342        Self {
 1343            scroll: None,
 1344            ..Default::default()
 1345        }
 1346    }
 1347
 1348    pub fn completions(self, completions: bool) -> Self {
 1349        Self {
 1350            completions,
 1351            ..self
 1352        }
 1353    }
 1354
 1355    pub fn nav_history(self, nav_history: bool) -> Self {
 1356        Self {
 1357            nav_history: Some(nav_history),
 1358            ..self
 1359        }
 1360    }
 1361}
 1362
 1363struct DeferredSelectionEffectsState {
 1364    changed: bool,
 1365    effects: SelectionEffects,
 1366    old_cursor_position: Anchor,
 1367    history_entry: SelectionHistoryEntry,
 1368}
 1369
 1370#[derive(Default)]
 1371struct SelectionHistory {
 1372    #[allow(clippy::type_complexity)]
 1373    selections_by_transaction:
 1374        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1375    mode: SelectionHistoryMode,
 1376    undo_stack: VecDeque<SelectionHistoryEntry>,
 1377    redo_stack: VecDeque<SelectionHistoryEntry>,
 1378}
 1379
 1380impl SelectionHistory {
 1381    #[track_caller]
 1382    fn insert_transaction(
 1383        &mut self,
 1384        transaction_id: TransactionId,
 1385        selections: Arc<[Selection<Anchor>]>,
 1386    ) {
 1387        if selections.is_empty() {
 1388            log::error!(
 1389                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1390                std::panic::Location::caller()
 1391            );
 1392            return;
 1393        }
 1394        self.selections_by_transaction
 1395            .insert(transaction_id, (selections, None));
 1396    }
 1397
 1398    #[allow(clippy::type_complexity)]
 1399    fn transaction(
 1400        &self,
 1401        transaction_id: TransactionId,
 1402    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1403        self.selections_by_transaction.get(&transaction_id)
 1404    }
 1405
 1406    #[allow(clippy::type_complexity)]
 1407    fn transaction_mut(
 1408        &mut self,
 1409        transaction_id: TransactionId,
 1410    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1411        self.selections_by_transaction.get_mut(&transaction_id)
 1412    }
 1413
 1414    fn push(&mut self, entry: SelectionHistoryEntry) {
 1415        if !entry.selections.is_empty() {
 1416            match self.mode {
 1417                SelectionHistoryMode::Normal => {
 1418                    self.push_undo(entry);
 1419                    self.redo_stack.clear();
 1420                }
 1421                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1422                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1423                SelectionHistoryMode::Skipping => {}
 1424            }
 1425        }
 1426    }
 1427
 1428    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1429        if self
 1430            .undo_stack
 1431            .back()
 1432            .map_or(true, |e| e.selections != entry.selections)
 1433        {
 1434            self.undo_stack.push_back(entry);
 1435            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1436                self.undo_stack.pop_front();
 1437            }
 1438        }
 1439    }
 1440
 1441    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1442        if self
 1443            .redo_stack
 1444            .back()
 1445            .map_or(true, |e| e.selections != entry.selections)
 1446        {
 1447            self.redo_stack.push_back(entry);
 1448            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1449                self.redo_stack.pop_front();
 1450            }
 1451        }
 1452    }
 1453}
 1454
 1455#[derive(Clone, Copy)]
 1456pub struct RowHighlightOptions {
 1457    pub autoscroll: bool,
 1458    pub include_gutter: bool,
 1459}
 1460
 1461impl Default for RowHighlightOptions {
 1462    fn default() -> Self {
 1463        Self {
 1464            autoscroll: Default::default(),
 1465            include_gutter: true,
 1466        }
 1467    }
 1468}
 1469
 1470struct RowHighlight {
 1471    index: usize,
 1472    range: Range<Anchor>,
 1473    color: Hsla,
 1474    options: RowHighlightOptions,
 1475    type_id: TypeId,
 1476}
 1477
 1478#[derive(Clone, Debug)]
 1479struct AddSelectionsState {
 1480    groups: Vec<AddSelectionsGroup>,
 1481}
 1482
 1483#[derive(Clone, Debug)]
 1484struct AddSelectionsGroup {
 1485    above: bool,
 1486    stack: Vec<usize>,
 1487}
 1488
 1489#[derive(Clone)]
 1490struct SelectNextState {
 1491    query: AhoCorasick,
 1492    wordwise: bool,
 1493    done: bool,
 1494}
 1495
 1496impl std::fmt::Debug for SelectNextState {
 1497    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1498        f.debug_struct(std::any::type_name::<Self>())
 1499            .field("wordwise", &self.wordwise)
 1500            .field("done", &self.done)
 1501            .finish()
 1502    }
 1503}
 1504
 1505#[derive(Debug)]
 1506struct AutocloseRegion {
 1507    selection_id: usize,
 1508    range: Range<Anchor>,
 1509    pair: BracketPair,
 1510}
 1511
 1512#[derive(Debug)]
 1513struct SnippetState {
 1514    ranges: Vec<Vec<Range<Anchor>>>,
 1515    active_index: usize,
 1516    choices: Vec<Option<Vec<String>>>,
 1517}
 1518
 1519#[doc(hidden)]
 1520pub struct RenameState {
 1521    pub range: Range<Anchor>,
 1522    pub old_name: Arc<str>,
 1523    pub editor: Entity<Editor>,
 1524    block_id: CustomBlockId,
 1525}
 1526
 1527struct InvalidationStack<T>(Vec<T>);
 1528
 1529struct RegisteredEditPredictionProvider {
 1530    provider: Arc<dyn EditPredictionProviderHandle>,
 1531    _subscription: Subscription,
 1532}
 1533
 1534#[derive(Debug, PartialEq, Eq)]
 1535pub struct ActiveDiagnosticGroup {
 1536    pub active_range: Range<Anchor>,
 1537    pub active_message: String,
 1538    pub group_id: usize,
 1539    pub blocks: HashSet<CustomBlockId>,
 1540}
 1541
 1542#[derive(Debug, PartialEq, Eq)]
 1543
 1544pub(crate) enum ActiveDiagnostic {
 1545    None,
 1546    All,
 1547    Group(ActiveDiagnosticGroup),
 1548}
 1549
 1550#[derive(Serialize, Deserialize, Clone, Debug)]
 1551pub struct ClipboardSelection {
 1552    /// The number of bytes in this selection.
 1553    pub len: usize,
 1554    /// Whether this was a full-line selection.
 1555    pub is_entire_line: bool,
 1556    /// The indentation of the first line when this content was originally copied.
 1557    pub first_line_indent: u32,
 1558}
 1559
 1560// selections, scroll behavior, was newest selection reversed
 1561type SelectSyntaxNodeHistoryState = (
 1562    Box<[Selection<usize>]>,
 1563    SelectSyntaxNodeScrollBehavior,
 1564    bool,
 1565);
 1566
 1567#[derive(Default)]
 1568struct SelectSyntaxNodeHistory {
 1569    stack: Vec<SelectSyntaxNodeHistoryState>,
 1570    // disable temporarily to allow changing selections without losing the stack
 1571    pub disable_clearing: bool,
 1572}
 1573
 1574impl SelectSyntaxNodeHistory {
 1575    pub fn try_clear(&mut self) {
 1576        if !self.disable_clearing {
 1577            self.stack.clear();
 1578        }
 1579    }
 1580
 1581    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1582        self.stack.push(selection);
 1583    }
 1584
 1585    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1586        self.stack.pop()
 1587    }
 1588}
 1589
 1590enum SelectSyntaxNodeScrollBehavior {
 1591    CursorTop,
 1592    FitSelection,
 1593    CursorBottom,
 1594}
 1595
 1596#[derive(Debug)]
 1597pub(crate) struct NavigationData {
 1598    cursor_anchor: Anchor,
 1599    cursor_position: Point,
 1600    scroll_anchor: ScrollAnchor,
 1601    scroll_top_row: u32,
 1602}
 1603
 1604#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1605pub enum GotoDefinitionKind {
 1606    Symbol,
 1607    Declaration,
 1608    Type,
 1609    Implementation,
 1610}
 1611
 1612#[derive(Debug, Clone)]
 1613enum InlayHintRefreshReason {
 1614    ModifiersChanged(bool),
 1615    Toggle(bool),
 1616    SettingsChange(InlayHintSettings),
 1617    NewLinesShown,
 1618    BufferEdited(HashSet<Arc<Language>>),
 1619    RefreshRequested,
 1620    ExcerptsRemoved(Vec<ExcerptId>),
 1621}
 1622
 1623impl InlayHintRefreshReason {
 1624    fn description(&self) -> &'static str {
 1625        match self {
 1626            Self::ModifiersChanged(_) => "modifiers changed",
 1627            Self::Toggle(_) => "toggle",
 1628            Self::SettingsChange(_) => "settings change",
 1629            Self::NewLinesShown => "new lines shown",
 1630            Self::BufferEdited(_) => "buffer edited",
 1631            Self::RefreshRequested => "refresh requested",
 1632            Self::ExcerptsRemoved(_) => "excerpts removed",
 1633        }
 1634    }
 1635}
 1636
 1637pub enum FormatTarget {
 1638    Buffers(HashSet<Entity<Buffer>>),
 1639    Ranges(Vec<Range<MultiBufferPoint>>),
 1640}
 1641
 1642pub(crate) struct FocusedBlock {
 1643    id: BlockId,
 1644    focus_handle: WeakFocusHandle,
 1645}
 1646
 1647#[derive(Clone)]
 1648enum JumpData {
 1649    MultiBufferRow {
 1650        row: MultiBufferRow,
 1651        line_offset_from_top: u32,
 1652    },
 1653    MultiBufferPoint {
 1654        excerpt_id: ExcerptId,
 1655        position: Point,
 1656        anchor: text::Anchor,
 1657        line_offset_from_top: u32,
 1658    },
 1659}
 1660
 1661pub enum MultibufferSelectionMode {
 1662    First,
 1663    All,
 1664}
 1665
 1666#[derive(Clone, Copy, Debug, Default)]
 1667pub struct RewrapOptions {
 1668    pub override_language_settings: bool,
 1669    pub preserve_existing_whitespace: bool,
 1670}
 1671
 1672impl Editor {
 1673    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1674        let buffer = cx.new(|cx| Buffer::local("", cx));
 1675        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1676        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1677    }
 1678
 1679    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1680        let buffer = cx.new(|cx| Buffer::local("", cx));
 1681        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1682        Self::new(EditorMode::full(), buffer, None, window, cx)
 1683    }
 1684
 1685    pub fn auto_height(
 1686        min_lines: usize,
 1687        max_lines: usize,
 1688        window: &mut Window,
 1689        cx: &mut Context<Self>,
 1690    ) -> Self {
 1691        let buffer = cx.new(|cx| Buffer::local("", cx));
 1692        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1693        Self::new(
 1694            EditorMode::AutoHeight {
 1695                min_lines,
 1696                max_lines: Some(max_lines),
 1697            },
 1698            buffer,
 1699            None,
 1700            window,
 1701            cx,
 1702        )
 1703    }
 1704
 1705    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1706    /// The editor grows as tall as needed to fit its content.
 1707    pub fn auto_height_unbounded(
 1708        min_lines: usize,
 1709        window: &mut Window,
 1710        cx: &mut Context<Self>,
 1711    ) -> Self {
 1712        let buffer = cx.new(|cx| Buffer::local("", cx));
 1713        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1714        Self::new(
 1715            EditorMode::AutoHeight {
 1716                min_lines,
 1717                max_lines: None,
 1718            },
 1719            buffer,
 1720            None,
 1721            window,
 1722            cx,
 1723        )
 1724    }
 1725
 1726    pub fn for_buffer(
 1727        buffer: Entity<Buffer>,
 1728        project: Option<Entity<Project>>,
 1729        window: &mut Window,
 1730        cx: &mut Context<Self>,
 1731    ) -> Self {
 1732        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1733        Self::new(EditorMode::full(), buffer, project, window, cx)
 1734    }
 1735
 1736    pub fn for_multibuffer(
 1737        buffer: Entity<MultiBuffer>,
 1738        project: Option<Entity<Project>>,
 1739        window: &mut Window,
 1740        cx: &mut Context<Self>,
 1741    ) -> Self {
 1742        Self::new(EditorMode::full(), buffer, project, window, cx)
 1743    }
 1744
 1745    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1746        let mut clone = Self::new(
 1747            self.mode.clone(),
 1748            self.buffer.clone(),
 1749            self.project.clone(),
 1750            window,
 1751            cx,
 1752        );
 1753        self.display_map.update(cx, |display_map, cx| {
 1754            let snapshot = display_map.snapshot(cx);
 1755            clone.display_map.update(cx, |display_map, cx| {
 1756                display_map.set_state(&snapshot, cx);
 1757            });
 1758        });
 1759        clone.folds_did_change(cx);
 1760        clone.selections.clone_state(&self.selections);
 1761        clone.scroll_manager.clone_state(&self.scroll_manager);
 1762        clone.searchable = self.searchable;
 1763        clone.read_only = self.read_only;
 1764        clone
 1765    }
 1766
 1767    pub fn new(
 1768        mode: EditorMode,
 1769        buffer: Entity<MultiBuffer>,
 1770        project: Option<Entity<Project>>,
 1771        window: &mut Window,
 1772        cx: &mut Context<Self>,
 1773    ) -> Self {
 1774        Editor::new_internal(mode, buffer, project, None, window, cx)
 1775    }
 1776
 1777    fn new_internal(
 1778        mode: EditorMode,
 1779        buffer: Entity<MultiBuffer>,
 1780        project: Option<Entity<Project>>,
 1781        display_map: Option<Entity<DisplayMap>>,
 1782        window: &mut Window,
 1783        cx: &mut Context<Self>,
 1784    ) -> Self {
 1785        debug_assert!(
 1786            display_map.is_none() || mode.is_minimap(),
 1787            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1788        );
 1789
 1790        let full_mode = mode.is_full();
 1791        let is_minimap = mode.is_minimap();
 1792        let diagnostics_max_severity = if full_mode {
 1793            EditorSettings::get_global(cx)
 1794                .diagnostics_max_severity
 1795                .unwrap_or(DiagnosticSeverity::Hint)
 1796        } else {
 1797            DiagnosticSeverity::Off
 1798        };
 1799        let style = window.text_style();
 1800        let font_size = style.font_size.to_pixels(window.rem_size());
 1801        let editor = cx.entity().downgrade();
 1802        let fold_placeholder = FoldPlaceholder {
 1803            constrain_width: true,
 1804            render: Arc::new(move |fold_id, fold_range, cx| {
 1805                let editor = editor.clone();
 1806                div()
 1807                    .id(fold_id)
 1808                    .bg(cx.theme().colors().ghost_element_background)
 1809                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1810                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1811                    .rounded_xs()
 1812                    .size_full()
 1813                    .cursor_pointer()
 1814                    .child("")
 1815                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1816                    .on_click(move |_, _window, cx| {
 1817                        editor
 1818                            .update(cx, |editor, cx| {
 1819                                editor.unfold_ranges(
 1820                                    &[fold_range.start..fold_range.end],
 1821                                    true,
 1822                                    false,
 1823                                    cx,
 1824                                );
 1825                                cx.stop_propagation();
 1826                            })
 1827                            .ok();
 1828                    })
 1829                    .into_any()
 1830            }),
 1831            merge_adjacent: true,
 1832            ..FoldPlaceholder::default()
 1833        };
 1834        let display_map = display_map.unwrap_or_else(|| {
 1835            cx.new(|cx| {
 1836                DisplayMap::new(
 1837                    buffer.clone(),
 1838                    style.font(),
 1839                    font_size,
 1840                    None,
 1841                    FILE_HEADER_HEIGHT,
 1842                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1843                    fold_placeholder,
 1844                    diagnostics_max_severity,
 1845                    cx,
 1846                )
 1847            })
 1848        });
 1849
 1850        let selections = SelectionsCollection::new(display_map.clone(), buffer.clone());
 1851
 1852        let blink_manager = cx.new(|cx| {
 1853            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1854            if is_minimap {
 1855                blink_manager.disable(cx);
 1856            }
 1857            blink_manager
 1858        });
 1859
 1860        let soft_wrap_mode_override = matches!(mode, EditorMode::SingleLine { .. })
 1861            .then(|| language_settings::SoftWrap::None);
 1862
 1863        let mut project_subscriptions = Vec::new();
 1864        if full_mode && let Some(project) = project.as_ref() {
 1865            project_subscriptions.push(cx.subscribe_in(
 1866                project,
 1867                window,
 1868                |editor, _, event, window, cx| match event {
 1869                    project::Event::RefreshCodeLens => {
 1870                        // we always query lens with actions, without storing them, always refreshing them
 1871                    }
 1872                    project::Event::RefreshInlayHints => {
 1873                        editor.refresh_inlay_hints(InlayHintRefreshReason::RefreshRequested, cx);
 1874                    }
 1875                    project::Event::LanguageServerAdded(..)
 1876                    | project::Event::LanguageServerRemoved(..) => {
 1877                        if editor.tasks_update_task.is_none() {
 1878                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1879                        }
 1880                    }
 1881                    project::Event::SnippetEdit(id, snippet_edits) => {
 1882                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1883                            let focus_handle = editor.focus_handle(cx);
 1884                            if focus_handle.is_focused(window) {
 1885                                let snapshot = buffer.read(cx).snapshot();
 1886                                for (range, snippet) in snippet_edits {
 1887                                    let editor_range =
 1888                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1889                                    editor
 1890                                        .insert_snippet(
 1891                                            &[editor_range],
 1892                                            snippet.clone(),
 1893                                            window,
 1894                                            cx,
 1895                                        )
 1896                                        .ok();
 1897                                }
 1898                            }
 1899                        }
 1900                    }
 1901                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1902                        if editor.buffer().read(cx).buffer(*buffer_id).is_some() {
 1903                            editor.update_lsp_data(false, Some(*buffer_id), window, cx);
 1904                        }
 1905                    }
 1906                    _ => {}
 1907                },
 1908            ));
 1909            if let Some(task_inventory) = project
 1910                .read(cx)
 1911                .task_store()
 1912                .read(cx)
 1913                .task_inventory()
 1914                .cloned()
 1915            {
 1916                project_subscriptions.push(cx.observe_in(
 1917                    &task_inventory,
 1918                    window,
 1919                    |editor, _, window, cx| {
 1920                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1921                    },
 1922                ));
 1923            };
 1924
 1925            project_subscriptions.push(cx.subscribe_in(
 1926                &project.read(cx).breakpoint_store(),
 1927                window,
 1928                |editor, _, event, window, cx| match event {
 1929                    BreakpointStoreEvent::ClearDebugLines => {
 1930                        editor.clear_row_highlights::<ActiveDebugLine>();
 1931                        editor.refresh_inline_values(cx);
 1932                    }
 1933                    BreakpointStoreEvent::SetDebugLine => {
 1934                        if editor.go_to_active_debug_line(window, cx) {
 1935                            cx.stop_propagation();
 1936                        }
 1937
 1938                        editor.refresh_inline_values(cx);
 1939                    }
 1940                    _ => {}
 1941                },
 1942            ));
 1943            let git_store = project.read(cx).git_store().clone();
 1944            let project = project.clone();
 1945            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1946                match event {
 1947                    GitStoreEvent::RepositoryUpdated(
 1948                        _,
 1949                        RepositoryEvent::Updated {
 1950                            new_instance: true, ..
 1951                        },
 1952                        _,
 1953                    ) => {
 1954                        this.load_diff_task = Some(
 1955                            update_uncommitted_diff_for_buffer(
 1956                                cx.entity(),
 1957                                &project,
 1958                                this.buffer.read(cx).all_buffers(),
 1959                                this.buffer.clone(),
 1960                                cx,
 1961                            )
 1962                            .shared(),
 1963                        );
 1964                    }
 1965                    _ => {}
 1966                }
 1967            }));
 1968        }
 1969
 1970        let buffer_snapshot = buffer.read(cx).snapshot(cx);
 1971
 1972        let inlay_hint_settings =
 1973            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 1974        let focus_handle = cx.focus_handle();
 1975        if !is_minimap {
 1976            cx.on_focus(&focus_handle, window, Self::handle_focus)
 1977                .detach();
 1978            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 1979                .detach();
 1980            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 1981                .detach();
 1982            cx.on_blur(&focus_handle, window, Self::handle_blur)
 1983                .detach();
 1984            cx.observe_pending_input(window, Self::observe_pending_input)
 1985                .detach();
 1986        }
 1987
 1988        let show_indent_guides = if matches!(
 1989            mode,
 1990            EditorMode::SingleLine { .. } | EditorMode::Minimap { .. }
 1991        ) {
 1992            Some(false)
 1993        } else {
 1994            None
 1995        };
 1996
 1997        let breakpoint_store = match (&mode, project.as_ref()) {
 1998            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 1999            _ => None,
 2000        };
 2001
 2002        let mut code_action_providers = Vec::new();
 2003        let mut load_uncommitted_diff = None;
 2004        if let Some(project) = project.clone() {
 2005            load_uncommitted_diff = Some(
 2006                update_uncommitted_diff_for_buffer(
 2007                    cx.entity(),
 2008                    &project,
 2009                    buffer.read(cx).all_buffers(),
 2010                    buffer.clone(),
 2011                    cx,
 2012                )
 2013                .shared(),
 2014            );
 2015            code_action_providers.push(Rc::new(project) as Rc<_>);
 2016        }
 2017
 2018        let mut editor = Self {
 2019            focus_handle,
 2020            show_cursor_when_unfocused: false,
 2021            last_focused_descendant: None,
 2022            buffer: buffer.clone(),
 2023            display_map: display_map.clone(),
 2024            selections,
 2025            scroll_manager: ScrollManager::new(cx),
 2026            columnar_selection_state: None,
 2027            add_selections_state: None,
 2028            select_next_state: None,
 2029            select_prev_state: None,
 2030            selection_history: SelectionHistory::default(),
 2031            defer_selection_effects: false,
 2032            deferred_selection_effects_state: None,
 2033            autoclose_regions: Vec::new(),
 2034            snippet_stack: InvalidationStack::default(),
 2035            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2036            ime_transaction: None,
 2037            active_diagnostics: ActiveDiagnostic::None,
 2038            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2039            inline_diagnostics_update: Task::ready(()),
 2040            inline_diagnostics: Vec::new(),
 2041            soft_wrap_mode_override,
 2042            diagnostics_max_severity,
 2043            hard_wrap: None,
 2044            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2045            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2046            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2047            project,
 2048            blink_manager: blink_manager.clone(),
 2049            show_local_selections: true,
 2050            show_scrollbars: ScrollbarAxes {
 2051                horizontal: full_mode,
 2052                vertical: full_mode,
 2053            },
 2054            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2055            offset_content: !matches!(mode, EditorMode::SingleLine { .. }),
 2056            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2057            show_gutter: full_mode,
 2058            show_line_numbers: (!full_mode).then_some(false),
 2059            use_relative_line_numbers: None,
 2060            disable_expand_excerpt_buttons: !full_mode,
 2061            show_git_diff_gutter: None,
 2062            show_code_actions: None,
 2063            show_runnables: None,
 2064            show_breakpoints: None,
 2065            show_wrap_guides: None,
 2066            show_indent_guides,
 2067            placeholder_text: None,
 2068            highlight_order: 0,
 2069            highlighted_rows: HashMap::default(),
 2070            background_highlights: TreeMap::default(),
 2071            gutter_highlights: TreeMap::default(),
 2072            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2073            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2074            nav_history: None,
 2075            context_menu: RefCell::new(None),
 2076            context_menu_options: None,
 2077            mouse_context_menu: None,
 2078            completion_tasks: Vec::new(),
 2079            inline_blame_popover: None,
 2080            inline_blame_popover_show_task: None,
 2081            signature_help_state: SignatureHelpState::default(),
 2082            auto_signature_help: None,
 2083            find_all_references_task_sources: Vec::new(),
 2084            next_completion_id: 0,
 2085            next_inlay_id: 0,
 2086            code_action_providers,
 2087            available_code_actions: None,
 2088            code_actions_task: None,
 2089            quick_selection_highlight_task: None,
 2090            debounced_selection_highlight_task: None,
 2091            document_highlights_task: None,
 2092            linked_editing_range_task: None,
 2093            pending_rename: None,
 2094            searchable: !is_minimap,
 2095            cursor_shape: EditorSettings::get_global(cx)
 2096                .cursor_shape
 2097                .unwrap_or_default(),
 2098            current_line_highlight: None,
 2099            autoindent_mode: Some(AutoindentMode::EachLine),
 2100            collapse_matches: false,
 2101            workspace: None,
 2102            input_enabled: !is_minimap,
 2103            use_modal_editing: full_mode,
 2104            read_only: is_minimap,
 2105            use_autoclose: true,
 2106            use_auto_surround: true,
 2107            auto_replace_emoji_shortcode: false,
 2108            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2109            leader_id: None,
 2110            remote_id: None,
 2111            hover_state: HoverState::default(),
 2112            pending_mouse_down: None,
 2113            hovered_link_state: None,
 2114            edit_prediction_provider: None,
 2115            active_edit_prediction: None,
 2116            stale_edit_prediction_in_menu: None,
 2117            edit_prediction_preview: EditPredictionPreview::Inactive {
 2118                released_too_fast: false,
 2119            },
 2120            inline_diagnostics_enabled: full_mode,
 2121            diagnostics_enabled: full_mode,
 2122            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2123            inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
 2124            gutter_hovered: false,
 2125            pixel_position_of_newest_cursor: None,
 2126            last_bounds: None,
 2127            last_position_map: None,
 2128            expect_bounds_change: None,
 2129            gutter_dimensions: GutterDimensions::default(),
 2130            style: None,
 2131            show_cursor_names: false,
 2132            hovered_cursors: HashMap::default(),
 2133            next_editor_action_id: EditorActionId::default(),
 2134            editor_actions: Rc::default(),
 2135            edit_predictions_hidden_for_vim_mode: false,
 2136            show_edit_predictions_override: None,
 2137            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2138            edit_prediction_settings: EditPredictionSettings::Disabled,
 2139            edit_prediction_indent_conflict: false,
 2140            edit_prediction_requires_modifier_in_indent_conflict: true,
 2141            custom_context_menu: None,
 2142            show_git_blame_gutter: false,
 2143            show_git_blame_inline: false,
 2144            show_selection_menu: None,
 2145            show_git_blame_inline_delay_task: None,
 2146            git_blame_inline_enabled: full_mode
 2147                && ProjectSettings::get_global(cx).git.inline_blame_enabled(),
 2148            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2149            serialize_dirty_buffers: !is_minimap
 2150                && ProjectSettings::get_global(cx)
 2151                    .session
 2152                    .restore_unsaved_buffers,
 2153            blame: None,
 2154            blame_subscription: None,
 2155            tasks: BTreeMap::default(),
 2156
 2157            breakpoint_store,
 2158            gutter_breakpoint_indicator: (None, None),
 2159            hovered_diff_hunk_row: None,
 2160            _subscriptions: (!is_minimap)
 2161                .then(|| {
 2162                    vec![
 2163                        cx.observe(&buffer, Self::on_buffer_changed),
 2164                        cx.subscribe_in(&buffer, window, Self::on_buffer_event),
 2165                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2166                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2167                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2168                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2169                        cx.observe_window_activation(window, |editor, window, cx| {
 2170                            let active = window.is_window_active();
 2171                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2172                                if active {
 2173                                    blink_manager.enable(cx);
 2174                                } else {
 2175                                    blink_manager.disable(cx);
 2176                                }
 2177                            });
 2178                            if active {
 2179                                editor.show_mouse_cursor(cx);
 2180                            }
 2181                        }),
 2182                    ]
 2183                })
 2184                .unwrap_or_default(),
 2185            tasks_update_task: None,
 2186            pull_diagnostics_task: Task::ready(()),
 2187            colors: None,
 2188            next_color_inlay_id: 0,
 2189            linked_edit_ranges: Default::default(),
 2190            in_project_search: false,
 2191            previous_search_ranges: None,
 2192            breadcrumb_header: None,
 2193            focused_block: None,
 2194            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2195            addons: HashMap::default(),
 2196            registered_buffers: HashMap::default(),
 2197            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2198            selection_mark_mode: false,
 2199            toggle_fold_multiple_buffers: Task::ready(()),
 2200            serialize_selections: Task::ready(()),
 2201            serialize_folds: Task::ready(()),
 2202            text_style_refinement: None,
 2203            load_diff_task: load_uncommitted_diff,
 2204            temporary_diff_override: false,
 2205            mouse_cursor_hidden: false,
 2206            minimap: None,
 2207            hide_mouse_mode: EditorSettings::get_global(cx)
 2208                .hide_mouse
 2209                .unwrap_or_default(),
 2210            change_list: ChangeList::new(),
 2211            mode,
 2212            selection_drag_state: SelectionDragState::None,
 2213            folding_newlines: Task::ready(()),
 2214        };
 2215
 2216        if is_minimap {
 2217            return editor;
 2218        }
 2219
 2220        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2221            editor
 2222                ._subscriptions
 2223                .push(cx.observe(breakpoints, |_, _, cx| {
 2224                    cx.notify();
 2225                }));
 2226        }
 2227        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2228        editor._subscriptions.extend(project_subscriptions);
 2229
 2230        editor._subscriptions.push(cx.subscribe_in(
 2231            &cx.entity(),
 2232            window,
 2233            |editor, _, e: &EditorEvent, window, cx| match e {
 2234                EditorEvent::ScrollPositionChanged { local, .. } => {
 2235                    if *local {
 2236                        let new_anchor = editor.scroll_manager.anchor();
 2237                        let snapshot = editor.snapshot(window, cx);
 2238                        editor.update_restoration_data(cx, move |data| {
 2239                            data.scroll_position = (
 2240                                new_anchor.top_row(&snapshot.buffer_snapshot),
 2241                                new_anchor.offset,
 2242                            );
 2243                        });
 2244                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2245                        editor.inline_blame_popover.take();
 2246                    }
 2247                }
 2248                EditorEvent::Edited { .. } => {
 2249                    if !vim_enabled(cx) {
 2250                        let (map, selections) = editor.selections.all_adjusted_display(cx);
 2251                        let pop_state = editor
 2252                            .change_list
 2253                            .last()
 2254                            .map(|previous| {
 2255                                previous.len() == selections.len()
 2256                                    && previous.iter().enumerate().all(|(ix, p)| {
 2257                                        p.to_display_point(&map).row()
 2258                                            == selections[ix].head().row()
 2259                                    })
 2260                            })
 2261                            .unwrap_or(false);
 2262                        let new_positions = selections
 2263                            .into_iter()
 2264                            .map(|s| map.display_point_to_anchor(s.head(), Bias::Left))
 2265                            .collect();
 2266                        editor
 2267                            .change_list
 2268                            .push_to_change_list(pop_state, new_positions);
 2269                    }
 2270                }
 2271                _ => (),
 2272            },
 2273        ));
 2274
 2275        if let Some(dap_store) = editor
 2276            .project
 2277            .as_ref()
 2278            .map(|project| project.read(cx).dap_store())
 2279        {
 2280            let weak_editor = cx.weak_entity();
 2281
 2282            editor
 2283                ._subscriptions
 2284                .push(
 2285                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2286                        let session_entity = cx.entity();
 2287                        weak_editor
 2288                            .update(cx, |editor, cx| {
 2289                                editor._subscriptions.push(
 2290                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2291                                );
 2292                            })
 2293                            .ok();
 2294                    }),
 2295                );
 2296
 2297            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2298                editor
 2299                    ._subscriptions
 2300                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2301            }
 2302        }
 2303
 2304        // skip adding the initial selection to selection history
 2305        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2306        editor.end_selection(window, cx);
 2307        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2308
 2309        editor.scroll_manager.show_scrollbars(window, cx);
 2310        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &buffer, cx);
 2311
 2312        if full_mode {
 2313            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2314            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2315
 2316            if editor.git_blame_inline_enabled {
 2317                editor.start_git_blame_inline(false, window, cx);
 2318            }
 2319
 2320            editor.go_to_active_debug_line(window, cx);
 2321
 2322            if let Some(buffer) = buffer.read(cx).as_singleton()
 2323                && let Some(project) = editor.project()
 2324            {
 2325                let handle = project.update(cx, |project, cx| {
 2326                    project.register_buffer_with_language_servers(&buffer, cx)
 2327                });
 2328                editor
 2329                    .registered_buffers
 2330                    .insert(buffer.read(cx).remote_id(), handle);
 2331            }
 2332
 2333            editor.minimap =
 2334                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2335            editor.colors = Some(LspColorData::new(cx));
 2336            editor.update_lsp_data(false, None, window, cx);
 2337        }
 2338
 2339        if editor.mode.is_full() {
 2340            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2341        }
 2342
 2343        editor
 2344    }
 2345
 2346    pub fn deploy_mouse_context_menu(
 2347        &mut self,
 2348        position: gpui::Point<Pixels>,
 2349        context_menu: Entity<ContextMenu>,
 2350        window: &mut Window,
 2351        cx: &mut Context<Self>,
 2352    ) {
 2353        self.mouse_context_menu = Some(MouseContextMenu::new(
 2354            self,
 2355            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2356            context_menu,
 2357            window,
 2358            cx,
 2359        ));
 2360    }
 2361
 2362    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2363        self.mouse_context_menu
 2364            .as_ref()
 2365            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2366    }
 2367
 2368    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2369        if self
 2370            .selections
 2371            .pending
 2372            .as_ref()
 2373            .is_some_and(|pending_selection| {
 2374                let snapshot = self.buffer().read(cx).snapshot(cx);
 2375                pending_selection
 2376                    .selection
 2377                    .range()
 2378                    .includes(range, &snapshot)
 2379            })
 2380        {
 2381            return true;
 2382        }
 2383
 2384        self.selections
 2385            .disjoint_in_range::<usize>(range.clone(), cx)
 2386            .into_iter()
 2387            .any(|selection| {
 2388                // This is needed to cover a corner case, if we just check for an existing
 2389                // selection in the fold range, having a cursor at the start of the fold
 2390                // marks it as selected. Non-empty selections don't cause this.
 2391                let length = selection.end - selection.start;
 2392                length > 0
 2393            })
 2394    }
 2395
 2396    pub fn key_context(&self, window: &Window, cx: &App) -> KeyContext {
 2397        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2398    }
 2399
 2400    fn key_context_internal(
 2401        &self,
 2402        has_active_edit_prediction: bool,
 2403        window: &Window,
 2404        cx: &App,
 2405    ) -> KeyContext {
 2406        let mut key_context = KeyContext::new_with_defaults();
 2407        key_context.add("Editor");
 2408        let mode = match self.mode {
 2409            EditorMode::SingleLine { .. } => "single_line",
 2410            EditorMode::AutoHeight { .. } => "auto_height",
 2411            EditorMode::Minimap { .. } => "minimap",
 2412            EditorMode::Full { .. } => "full",
 2413        };
 2414
 2415        if EditorSettings::jupyter_enabled(cx) {
 2416            key_context.add("jupyter");
 2417        }
 2418
 2419        key_context.set("mode", mode);
 2420        if self.pending_rename.is_some() {
 2421            key_context.add("renaming");
 2422        }
 2423
 2424        match self.context_menu.borrow().as_ref() {
 2425            Some(CodeContextMenu::Completions(menu)) => {
 2426                if menu.visible() {
 2427                    key_context.add("menu");
 2428                    key_context.add("showing_completions");
 2429                }
 2430            }
 2431            Some(CodeContextMenu::CodeActions(menu)) => {
 2432                if menu.visible() {
 2433                    key_context.add("menu");
 2434                    key_context.add("showing_code_actions")
 2435                }
 2436            }
 2437            None => {}
 2438        }
 2439
 2440        if self.signature_help_state.has_multiple_signatures() {
 2441            key_context.add("showing_signature_help");
 2442        }
 2443
 2444        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2445        if !self.focus_handle(cx).contains_focused(window, cx)
 2446            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2447        {
 2448            for addon in self.addons.values() {
 2449                addon.extend_key_context(&mut key_context, cx)
 2450            }
 2451        }
 2452
 2453        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2454            if let Some(extension) = singleton_buffer
 2455                .read(cx)
 2456                .file()
 2457                .and_then(|file| file.path().extension()?.to_str())
 2458            {
 2459                key_context.set("extension", extension.to_string());
 2460            }
 2461        } else {
 2462            key_context.add("multibuffer");
 2463        }
 2464
 2465        if has_active_edit_prediction {
 2466            if self.edit_prediction_in_conflict() {
 2467                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2468            } else {
 2469                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2470                key_context.add("copilot_suggestion");
 2471            }
 2472        }
 2473
 2474        if self.selection_mark_mode {
 2475            key_context.add("selection_mode");
 2476        }
 2477
 2478        key_context
 2479    }
 2480
 2481    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2482        if self.mouse_cursor_hidden {
 2483            self.mouse_cursor_hidden = false;
 2484            cx.notify();
 2485        }
 2486    }
 2487
 2488    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2489        let hide_mouse_cursor = match origin {
 2490            HideMouseCursorOrigin::TypingAction => {
 2491                matches!(
 2492                    self.hide_mouse_mode,
 2493                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2494                )
 2495            }
 2496            HideMouseCursorOrigin::MovementAction => {
 2497                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2498            }
 2499        };
 2500        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2501            self.mouse_cursor_hidden = hide_mouse_cursor;
 2502            cx.notify();
 2503        }
 2504    }
 2505
 2506    pub fn edit_prediction_in_conflict(&self) -> bool {
 2507        if !self.show_edit_predictions_in_menu() {
 2508            return false;
 2509        }
 2510
 2511        let showing_completions = self
 2512            .context_menu
 2513            .borrow()
 2514            .as_ref()
 2515            .map_or(false, |context| {
 2516                matches!(context, CodeContextMenu::Completions(_))
 2517            });
 2518
 2519        showing_completions
 2520            || self.edit_prediction_requires_modifier()
 2521            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2522            // bindings to insert tab characters.
 2523            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2524    }
 2525
 2526    pub fn accept_edit_prediction_keybind(
 2527        &self,
 2528        accept_partial: bool,
 2529        window: &Window,
 2530        cx: &App,
 2531    ) -> AcceptEditPredictionBinding {
 2532        let key_context = self.key_context_internal(true, window, cx);
 2533        let in_conflict = self.edit_prediction_in_conflict();
 2534
 2535        let bindings = if accept_partial {
 2536            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2537        } else {
 2538            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2539        };
 2540
 2541        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2542        // just the first one.
 2543        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2544            !in_conflict
 2545                || binding
 2546                    .keystrokes()
 2547                    .first()
 2548                    .map_or(false, |keystroke| keystroke.modifiers.modified())
 2549        }))
 2550    }
 2551
 2552    pub fn new_file(
 2553        workspace: &mut Workspace,
 2554        _: &workspace::NewFile,
 2555        window: &mut Window,
 2556        cx: &mut Context<Workspace>,
 2557    ) {
 2558        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2559            "Failed to create buffer",
 2560            window,
 2561            cx,
 2562            |e, _, _| match e.error_code() {
 2563                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2564                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2565                e.error_tag("required").unwrap_or("the latest version")
 2566            )),
 2567                _ => None,
 2568            },
 2569        );
 2570    }
 2571
 2572    pub fn new_in_workspace(
 2573        workspace: &mut Workspace,
 2574        window: &mut Window,
 2575        cx: &mut Context<Workspace>,
 2576    ) -> Task<Result<Entity<Editor>>> {
 2577        let project = workspace.project().clone();
 2578        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2579
 2580        cx.spawn_in(window, async move |workspace, cx| {
 2581            let buffer = create.await?;
 2582            workspace.update_in(cx, |workspace, window, cx| {
 2583                let editor =
 2584                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2585                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2586                editor
 2587            })
 2588        })
 2589    }
 2590
 2591    fn new_file_vertical(
 2592        workspace: &mut Workspace,
 2593        _: &workspace::NewFileSplitVertical,
 2594        window: &mut Window,
 2595        cx: &mut Context<Workspace>,
 2596    ) {
 2597        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2598    }
 2599
 2600    fn new_file_horizontal(
 2601        workspace: &mut Workspace,
 2602        _: &workspace::NewFileSplitHorizontal,
 2603        window: &mut Window,
 2604        cx: &mut Context<Workspace>,
 2605    ) {
 2606        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2607    }
 2608
 2609    fn new_file_in_direction(
 2610        workspace: &mut Workspace,
 2611        direction: SplitDirection,
 2612        window: &mut Window,
 2613        cx: &mut Context<Workspace>,
 2614    ) {
 2615        let project = workspace.project().clone();
 2616        let create = project.update(cx, |project, cx| project.create_buffer(cx));
 2617
 2618        cx.spawn_in(window, async move |workspace, cx| {
 2619            let buffer = create.await?;
 2620            workspace.update_in(cx, move |workspace, window, cx| {
 2621                workspace.split_item(
 2622                    direction,
 2623                    Box::new(
 2624                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2625                    ),
 2626                    window,
 2627                    cx,
 2628                )
 2629            })?;
 2630            anyhow::Ok(())
 2631        })
 2632        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2633            match e.error_code() {
 2634                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2635                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2636                e.error_tag("required").unwrap_or("the latest version")
 2637            )),
 2638                _ => None,
 2639            }
 2640        });
 2641    }
 2642
 2643    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2644        self.leader_id
 2645    }
 2646
 2647    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2648        &self.buffer
 2649    }
 2650
 2651    pub fn project(&self) -> Option<&Entity<Project>> {
 2652        self.project.as_ref()
 2653    }
 2654
 2655    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2656        self.workspace.as_ref()?.0.upgrade()
 2657    }
 2658
 2659    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2660        self.buffer().read(cx).title(cx)
 2661    }
 2662
 2663    pub fn snapshot(&self, window: &mut Window, cx: &mut App) -> EditorSnapshot {
 2664        let git_blame_gutter_max_author_length = self
 2665            .render_git_blame_gutter(cx)
 2666            .then(|| {
 2667                if let Some(blame) = self.blame.as_ref() {
 2668                    let max_author_length =
 2669                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2670                    Some(max_author_length)
 2671                } else {
 2672                    None
 2673                }
 2674            })
 2675            .flatten();
 2676
 2677        EditorSnapshot {
 2678            mode: self.mode.clone(),
 2679            show_gutter: self.show_gutter,
 2680            show_line_numbers: self.show_line_numbers,
 2681            show_git_diff_gutter: self.show_git_diff_gutter,
 2682            show_code_actions: self.show_code_actions,
 2683            show_runnables: self.show_runnables,
 2684            show_breakpoints: self.show_breakpoints,
 2685            git_blame_gutter_max_author_length,
 2686            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2687            scroll_anchor: self.scroll_manager.anchor(),
 2688            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2689            placeholder_text: self.placeholder_text.clone(),
 2690            is_focused: self.focus_handle.is_focused(window),
 2691            current_line_highlight: self
 2692                .current_line_highlight
 2693                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2694            gutter_hovered: self.gutter_hovered,
 2695        }
 2696    }
 2697
 2698    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2699        self.buffer.read(cx).language_at(point, cx)
 2700    }
 2701
 2702    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2703        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2704    }
 2705
 2706    pub fn active_excerpt(
 2707        &self,
 2708        cx: &App,
 2709    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2710        self.buffer
 2711            .read(cx)
 2712            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2713    }
 2714
 2715    pub fn mode(&self) -> &EditorMode {
 2716        &self.mode
 2717    }
 2718
 2719    pub fn set_mode(&mut self, mode: EditorMode) {
 2720        self.mode = mode;
 2721    }
 2722
 2723    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2724        self.collaboration_hub.as_deref()
 2725    }
 2726
 2727    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2728        self.collaboration_hub = Some(hub);
 2729    }
 2730
 2731    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2732        self.in_project_search = in_project_search;
 2733    }
 2734
 2735    pub fn set_custom_context_menu(
 2736        &mut self,
 2737        f: impl 'static
 2738        + Fn(
 2739            &mut Self,
 2740            DisplayPoint,
 2741            &mut Window,
 2742            &mut Context<Self>,
 2743        ) -> Option<Entity<ui::ContextMenu>>,
 2744    ) {
 2745        self.custom_context_menu = Some(Box::new(f))
 2746    }
 2747
 2748    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2749        self.completion_provider = provider;
 2750    }
 2751
 2752    #[cfg(any(test, feature = "test-support"))]
 2753    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2754        self.completion_provider.clone()
 2755    }
 2756
 2757    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2758        self.semantics_provider.clone()
 2759    }
 2760
 2761    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2762        self.semantics_provider = provider;
 2763    }
 2764
 2765    pub fn set_edit_prediction_provider<T>(
 2766        &mut self,
 2767        provider: Option<Entity<T>>,
 2768        window: &mut Window,
 2769        cx: &mut Context<Self>,
 2770    ) where
 2771        T: EditPredictionProvider,
 2772    {
 2773        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2774            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2775                if this.focus_handle.is_focused(window) {
 2776                    this.update_visible_edit_prediction(window, cx);
 2777                }
 2778            }),
 2779            provider: Arc::new(provider),
 2780        });
 2781        self.update_edit_prediction_settings(cx);
 2782        self.refresh_edit_prediction(false, false, window, cx);
 2783    }
 2784
 2785    pub fn placeholder_text(&self) -> Option<&str> {
 2786        self.placeholder_text.as_deref()
 2787    }
 2788
 2789    pub fn set_placeholder_text(
 2790        &mut self,
 2791        placeholder_text: impl Into<Arc<str>>,
 2792        cx: &mut Context<Self>,
 2793    ) {
 2794        let placeholder_text = Some(placeholder_text.into());
 2795        if self.placeholder_text != placeholder_text {
 2796            self.placeholder_text = placeholder_text;
 2797            cx.notify();
 2798        }
 2799    }
 2800
 2801    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2802        self.cursor_shape = cursor_shape;
 2803
 2804        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2805        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2806
 2807        cx.notify();
 2808    }
 2809
 2810    pub fn set_current_line_highlight(
 2811        &mut self,
 2812        current_line_highlight: Option<CurrentLineHighlight>,
 2813    ) {
 2814        self.current_line_highlight = current_line_highlight;
 2815    }
 2816
 2817    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 2818        self.collapse_matches = collapse_matches;
 2819    }
 2820
 2821    fn register_buffers_with_language_servers(&mut self, cx: &mut Context<Self>) {
 2822        let buffers = self.buffer.read(cx).all_buffers();
 2823        let Some(project) = self.project.as_ref() else {
 2824            return;
 2825        };
 2826        project.update(cx, |project, cx| {
 2827            for buffer in buffers {
 2828                self.registered_buffers
 2829                    .entry(buffer.read(cx).remote_id())
 2830                    .or_insert_with(|| project.register_buffer_with_language_servers(&buffer, cx));
 2831            }
 2832        })
 2833    }
 2834
 2835    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 2836        if self.collapse_matches {
 2837            return range.start..range.start;
 2838        }
 2839        range.clone()
 2840    }
 2841
 2842    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2843        if self.display_map.read(cx).clip_at_line_ends != clip {
 2844            self.display_map
 2845                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2846        }
 2847    }
 2848
 2849    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2850        self.input_enabled = input_enabled;
 2851    }
 2852
 2853    pub fn set_edit_predictions_hidden_for_vim_mode(
 2854        &mut self,
 2855        hidden: bool,
 2856        window: &mut Window,
 2857        cx: &mut Context<Self>,
 2858    ) {
 2859        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2860            self.edit_predictions_hidden_for_vim_mode = hidden;
 2861            if hidden {
 2862                self.update_visible_edit_prediction(window, cx);
 2863            } else {
 2864                self.refresh_edit_prediction(true, false, window, cx);
 2865            }
 2866        }
 2867    }
 2868
 2869    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2870        self.menu_edit_predictions_policy = value;
 2871    }
 2872
 2873    pub fn set_autoindent(&mut self, autoindent: bool) {
 2874        if autoindent {
 2875            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2876        } else {
 2877            self.autoindent_mode = None;
 2878        }
 2879    }
 2880
 2881    pub fn read_only(&self, cx: &App) -> bool {
 2882        self.read_only || self.buffer.read(cx).read_only()
 2883    }
 2884
 2885    pub fn set_read_only(&mut self, read_only: bool) {
 2886        self.read_only = read_only;
 2887    }
 2888
 2889    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2890        self.use_autoclose = autoclose;
 2891    }
 2892
 2893    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2894        self.use_auto_surround = auto_surround;
 2895    }
 2896
 2897    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2898        self.auto_replace_emoji_shortcode = auto_replace;
 2899    }
 2900
 2901    pub fn toggle_edit_predictions(
 2902        &mut self,
 2903        _: &ToggleEditPrediction,
 2904        window: &mut Window,
 2905        cx: &mut Context<Self>,
 2906    ) {
 2907        if self.show_edit_predictions_override.is_some() {
 2908            self.set_show_edit_predictions(None, window, cx);
 2909        } else {
 2910            let show_edit_predictions = !self.edit_predictions_enabled();
 2911            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2912        }
 2913    }
 2914
 2915    pub fn set_show_edit_predictions(
 2916        &mut self,
 2917        show_edit_predictions: Option<bool>,
 2918        window: &mut Window,
 2919        cx: &mut Context<Self>,
 2920    ) {
 2921        self.show_edit_predictions_override = show_edit_predictions;
 2922        self.update_edit_prediction_settings(cx);
 2923
 2924        if let Some(false) = show_edit_predictions {
 2925            self.discard_edit_prediction(false, cx);
 2926        } else {
 2927            self.refresh_edit_prediction(false, true, window, cx);
 2928        }
 2929    }
 2930
 2931    fn edit_predictions_disabled_in_scope(
 2932        &self,
 2933        buffer: &Entity<Buffer>,
 2934        buffer_position: language::Anchor,
 2935        cx: &App,
 2936    ) -> bool {
 2937        let snapshot = buffer.read(cx).snapshot();
 2938        let settings = snapshot.settings_at(buffer_position, cx);
 2939
 2940        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 2941            return false;
 2942        };
 2943
 2944        scope.override_name().map_or(false, |scope_name| {
 2945            settings
 2946                .edit_predictions_disabled_in
 2947                .iter()
 2948                .any(|s| s == scope_name)
 2949        })
 2950    }
 2951
 2952    pub fn set_use_modal_editing(&mut self, to: bool) {
 2953        self.use_modal_editing = to;
 2954    }
 2955
 2956    pub fn use_modal_editing(&self) -> bool {
 2957        self.use_modal_editing
 2958    }
 2959
 2960    fn selections_did_change(
 2961        &mut self,
 2962        local: bool,
 2963        old_cursor_position: &Anchor,
 2964        effects: SelectionEffects,
 2965        window: &mut Window,
 2966        cx: &mut Context<Self>,
 2967    ) {
 2968        window.invalidate_character_coordinates();
 2969
 2970        // Copy selections to primary selection buffer
 2971        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 2972        if local {
 2973            let selections = self.selections.all::<usize>(cx);
 2974            let buffer_handle = self.buffer.read(cx).read(cx);
 2975
 2976            let mut text = String::new();
 2977            for (index, selection) in selections.iter().enumerate() {
 2978                let text_for_selection = buffer_handle
 2979                    .text_for_range(selection.start..selection.end)
 2980                    .collect::<String>();
 2981
 2982                text.push_str(&text_for_selection);
 2983                if index != selections.len() - 1 {
 2984                    text.push('\n');
 2985                }
 2986            }
 2987
 2988            if !text.is_empty() {
 2989                cx.write_to_primary(ClipboardItem::new_string(text));
 2990            }
 2991        }
 2992
 2993        let selection_anchors = self.selections.disjoint_anchors();
 2994
 2995        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 2996            self.buffer.update(cx, |buffer, cx| {
 2997                buffer.set_active_selections(
 2998                    &selection_anchors,
 2999                    self.selections.line_mode,
 3000                    self.cursor_shape,
 3001                    cx,
 3002                )
 3003            });
 3004        }
 3005        let display_map = self
 3006            .display_map
 3007            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3008        let buffer = &display_map.buffer_snapshot;
 3009        if self.selections.count() == 1 {
 3010            self.add_selections_state = None;
 3011        }
 3012        self.select_next_state = None;
 3013        self.select_prev_state = None;
 3014        self.select_syntax_node_history.try_clear();
 3015        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3016        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3017        self.take_rename(false, window, cx);
 3018
 3019        let newest_selection = self.selections.newest_anchor();
 3020        let new_cursor_position = newest_selection.head();
 3021        let selection_start = newest_selection.start;
 3022
 3023        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3024            self.push_to_nav_history(
 3025                *old_cursor_position,
 3026                Some(new_cursor_position.to_point(buffer)),
 3027                false,
 3028                effects.nav_history == Some(true),
 3029                cx,
 3030            );
 3031        }
 3032
 3033        if local {
 3034            if let Some(buffer_id) = new_cursor_position.buffer_id
 3035                && !self.registered_buffers.contains_key(&buffer_id)
 3036                && let Some(project) = self.project.as_ref()
 3037            {
 3038                project.update(cx, |project, cx| {
 3039                    let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) else {
 3040                        return;
 3041                    };
 3042                    self.registered_buffers.insert(
 3043                        buffer_id,
 3044                        project.register_buffer_with_language_servers(&buffer, cx),
 3045                    );
 3046                })
 3047            }
 3048
 3049            let mut context_menu = self.context_menu.borrow_mut();
 3050            let completion_menu = match context_menu.as_ref() {
 3051                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3052                Some(CodeContextMenu::CodeActions(_)) => {
 3053                    *context_menu = None;
 3054                    None
 3055                }
 3056                None => None,
 3057            };
 3058            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3059            drop(context_menu);
 3060
 3061            if effects.completions
 3062                && let Some(completion_position) = completion_position
 3063            {
 3064                let start_offset = selection_start.to_offset(buffer);
 3065                let position_matches = start_offset == completion_position.to_offset(buffer);
 3066                let continue_showing = if position_matches {
 3067                    if self.snippet_stack.is_empty() {
 3068                        buffer.char_kind_before(start_offset, true) == Some(CharKind::Word)
 3069                    } else {
 3070                        // Snippet choices can be shown even when the cursor is in whitespace.
 3071                        // Dismissing the menu with actions like backspace is handled by
 3072                        // invalidation regions.
 3073                        true
 3074                    }
 3075                } else {
 3076                    false
 3077                };
 3078
 3079                if continue_showing {
 3080                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3081                } else {
 3082                    self.hide_context_menu(window, cx);
 3083                }
 3084            }
 3085
 3086            hide_hover(self, cx);
 3087
 3088            if old_cursor_position.to_display_point(&display_map).row()
 3089                != new_cursor_position.to_display_point(&display_map).row()
 3090            {
 3091                self.available_code_actions.take();
 3092            }
 3093            self.refresh_code_actions(window, cx);
 3094            self.refresh_document_highlights(cx);
 3095            self.refresh_selected_text_highlights(false, window, cx);
 3096            refresh_matching_bracket_highlights(self, window, cx);
 3097            self.update_visible_edit_prediction(window, cx);
 3098            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3099            linked_editing_ranges::refresh_linked_ranges(self, window, cx);
 3100            self.inline_blame_popover.take();
 3101            if self.git_blame_inline_enabled {
 3102                self.start_inline_blame_timer(window, cx);
 3103            }
 3104        }
 3105
 3106        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3107        cx.emit(EditorEvent::SelectionsChanged { local });
 3108
 3109        let selections = &self.selections.disjoint;
 3110        if selections.len() == 1 {
 3111            cx.emit(SearchEvent::ActiveMatchChanged)
 3112        }
 3113        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3114            let inmemory_selections = selections
 3115                .iter()
 3116                .map(|s| {
 3117                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3118                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3119                })
 3120                .collect();
 3121            self.update_restoration_data(cx, |data| {
 3122                data.selections = inmemory_selections;
 3123            });
 3124
 3125            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3126                && let Some(workspace_id) =
 3127                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3128            {
 3129                let snapshot = self.buffer().read(cx).snapshot(cx);
 3130                let selections = selections.clone();
 3131                let background_executor = cx.background_executor().clone();
 3132                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3133                self.serialize_selections = cx.background_spawn(async move {
 3134                            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3135                            let db_selections = selections
 3136                                .iter()
 3137                                .map(|selection| {
 3138                                    (
 3139                                        selection.start.to_offset(&snapshot),
 3140                                        selection.end.to_offset(&snapshot),
 3141                                    )
 3142                                })
 3143                                .collect();
 3144
 3145                            DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3146                                .await
 3147                                .with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
 3148                                .log_err();
 3149                        });
 3150            }
 3151        }
 3152
 3153        cx.notify();
 3154    }
 3155
 3156    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3157        use text::ToOffset as _;
 3158        use text::ToPoint as _;
 3159
 3160        if self.mode.is_minimap()
 3161            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3162        {
 3163            return;
 3164        }
 3165
 3166        let Some(singleton) = self.buffer().read(cx).as_singleton() else {
 3167            return;
 3168        };
 3169
 3170        let snapshot = singleton.read(cx).snapshot();
 3171        let inmemory_folds = self.display_map.update(cx, |display_map, cx| {
 3172            let display_snapshot = display_map.snapshot(cx);
 3173
 3174            display_snapshot
 3175                .folds_in_range(0..display_snapshot.buffer_snapshot.len())
 3176                .map(|fold| {
 3177                    fold.range.start.text_anchor.to_point(&snapshot)
 3178                        ..fold.range.end.text_anchor.to_point(&snapshot)
 3179                })
 3180                .collect()
 3181        });
 3182        self.update_restoration_data(cx, |data| {
 3183            data.folds = inmemory_folds;
 3184        });
 3185
 3186        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3187            return;
 3188        };
 3189        let background_executor = cx.background_executor().clone();
 3190        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3191        let db_folds = self.display_map.update(cx, |display_map, cx| {
 3192            display_map
 3193                .snapshot(cx)
 3194                .folds_in_range(0..snapshot.len())
 3195                .map(|fold| {
 3196                    (
 3197                        fold.range.start.text_anchor.to_offset(&snapshot),
 3198                        fold.range.end.text_anchor.to_offset(&snapshot),
 3199                    )
 3200                })
 3201                .collect()
 3202        });
 3203        self.serialize_folds = cx.background_spawn(async move {
 3204            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3205            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3206                .await
 3207                .with_context(|| {
 3208                    format!(
 3209                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3210                    )
 3211                })
 3212                .log_err();
 3213        });
 3214    }
 3215
 3216    pub fn sync_selections(
 3217        &mut self,
 3218        other: Entity<Editor>,
 3219        cx: &mut Context<Self>,
 3220    ) -> gpui::Subscription {
 3221        let other_selections = other.read(cx).selections.disjoint.to_vec();
 3222        self.selections.change_with(cx, |selections| {
 3223            selections.select_anchors(other_selections);
 3224        });
 3225
 3226        let other_subscription =
 3227            cx.subscribe(&other, |this, other, other_evt, cx| match other_evt {
 3228                EditorEvent::SelectionsChanged { local: true } => {
 3229                    let other_selections = other.read(cx).selections.disjoint.to_vec();
 3230                    if other_selections.is_empty() {
 3231                        return;
 3232                    }
 3233                    this.selections.change_with(cx, |selections| {
 3234                        selections.select_anchors(other_selections);
 3235                    });
 3236                }
 3237                _ => {}
 3238            });
 3239
 3240        let this_subscription =
 3241            cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| match this_evt {
 3242                EditorEvent::SelectionsChanged { local: true } => {
 3243                    let these_selections = this.selections.disjoint.to_vec();
 3244                    if these_selections.is_empty() {
 3245                        return;
 3246                    }
 3247                    other.update(cx, |other_editor, cx| {
 3248                        other_editor.selections.change_with(cx, |selections| {
 3249                            selections.select_anchors(these_selections);
 3250                        })
 3251                    });
 3252                }
 3253                _ => {}
 3254            });
 3255
 3256        Subscription::join(other_subscription, this_subscription)
 3257    }
 3258
 3259    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3260    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3261    /// effects of selection change occur at the end of the transaction.
 3262    pub fn change_selections<R>(
 3263        &mut self,
 3264        effects: SelectionEffects,
 3265        window: &mut Window,
 3266        cx: &mut Context<Self>,
 3267        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3268    ) -> R {
 3269        if let Some(state) = &mut self.deferred_selection_effects_state {
 3270            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3271            state.effects.completions = effects.completions;
 3272            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3273            let (changed, result) = self.selections.change_with(cx, change);
 3274            state.changed |= changed;
 3275            return result;
 3276        }
 3277        let mut state = DeferredSelectionEffectsState {
 3278            changed: false,
 3279            effects,
 3280            old_cursor_position: self.selections.newest_anchor().head(),
 3281            history_entry: SelectionHistoryEntry {
 3282                selections: self.selections.disjoint_anchors(),
 3283                select_next_state: self.select_next_state.clone(),
 3284                select_prev_state: self.select_prev_state.clone(),
 3285                add_selections_state: self.add_selections_state.clone(),
 3286            },
 3287        };
 3288        let (changed, result) = self.selections.change_with(cx, change);
 3289        state.changed = state.changed || changed;
 3290        if self.defer_selection_effects {
 3291            self.deferred_selection_effects_state = Some(state);
 3292        } else {
 3293            self.apply_selection_effects(state, window, cx);
 3294        }
 3295        result
 3296    }
 3297
 3298    /// Defers the effects of selection change, so that the effects of multiple calls to
 3299    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3300    /// to selection history and the state of popovers based on selection position aren't
 3301    /// erroneously updated.
 3302    pub fn with_selection_effects_deferred<R>(
 3303        &mut self,
 3304        window: &mut Window,
 3305        cx: &mut Context<Self>,
 3306        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3307    ) -> R {
 3308        let already_deferred = self.defer_selection_effects;
 3309        self.defer_selection_effects = true;
 3310        let result = update(self, window, cx);
 3311        if !already_deferred {
 3312            self.defer_selection_effects = false;
 3313            if let Some(state) = self.deferred_selection_effects_state.take() {
 3314                self.apply_selection_effects(state, window, cx);
 3315            }
 3316        }
 3317        result
 3318    }
 3319
 3320    fn apply_selection_effects(
 3321        &mut self,
 3322        state: DeferredSelectionEffectsState,
 3323        window: &mut Window,
 3324        cx: &mut Context<Self>,
 3325    ) {
 3326        if state.changed {
 3327            self.selection_history.push(state.history_entry);
 3328
 3329            if let Some(autoscroll) = state.effects.scroll {
 3330                self.request_autoscroll(autoscroll, cx);
 3331            }
 3332
 3333            let old_cursor_position = &state.old_cursor_position;
 3334
 3335            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3336
 3337            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3338                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3339            }
 3340        }
 3341    }
 3342
 3343    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3344    where
 3345        I: IntoIterator<Item = (Range<S>, T)>,
 3346        S: ToOffset,
 3347        T: Into<Arc<str>>,
 3348    {
 3349        if self.read_only(cx) {
 3350            return;
 3351        }
 3352
 3353        self.buffer
 3354            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3355    }
 3356
 3357    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3358    where
 3359        I: IntoIterator<Item = (Range<S>, T)>,
 3360        S: ToOffset,
 3361        T: Into<Arc<str>>,
 3362    {
 3363        if self.read_only(cx) {
 3364            return;
 3365        }
 3366
 3367        self.buffer.update(cx, |buffer, cx| {
 3368            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3369        });
 3370    }
 3371
 3372    pub fn edit_with_block_indent<I, S, T>(
 3373        &mut self,
 3374        edits: I,
 3375        original_indent_columns: Vec<Option<u32>>,
 3376        cx: &mut Context<Self>,
 3377    ) where
 3378        I: IntoIterator<Item = (Range<S>, T)>,
 3379        S: ToOffset,
 3380        T: Into<Arc<str>>,
 3381    {
 3382        if self.read_only(cx) {
 3383            return;
 3384        }
 3385
 3386        self.buffer.update(cx, |buffer, cx| {
 3387            buffer.edit(
 3388                edits,
 3389                Some(AutoindentMode::Block {
 3390                    original_indent_columns,
 3391                }),
 3392                cx,
 3393            )
 3394        });
 3395    }
 3396
 3397    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3398        self.hide_context_menu(window, cx);
 3399
 3400        match phase {
 3401            SelectPhase::Begin {
 3402                position,
 3403                add,
 3404                click_count,
 3405            } => self.begin_selection(position, add, click_count, window, cx),
 3406            SelectPhase::BeginColumnar {
 3407                position,
 3408                goal_column,
 3409                reset,
 3410                mode,
 3411            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3412            SelectPhase::Extend {
 3413                position,
 3414                click_count,
 3415            } => self.extend_selection(position, click_count, window, cx),
 3416            SelectPhase::Update {
 3417                position,
 3418                goal_column,
 3419                scroll_delta,
 3420            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3421            SelectPhase::End => self.end_selection(window, cx),
 3422        }
 3423    }
 3424
 3425    fn extend_selection(
 3426        &mut self,
 3427        position: DisplayPoint,
 3428        click_count: usize,
 3429        window: &mut Window,
 3430        cx: &mut Context<Self>,
 3431    ) {
 3432        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3433        let tail = self.selections.newest::<usize>(cx).tail();
 3434        self.begin_selection(position, false, click_count, window, cx);
 3435
 3436        let position = position.to_offset(&display_map, Bias::Left);
 3437        let tail_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3438
 3439        let mut pending_selection = self
 3440            .selections
 3441            .pending_anchor()
 3442            .expect("extend_selection not called with pending selection");
 3443        if position >= tail {
 3444            pending_selection.start = tail_anchor;
 3445        } else {
 3446            pending_selection.end = tail_anchor;
 3447            pending_selection.reversed = true;
 3448        }
 3449
 3450        let mut pending_mode = self.selections.pending_mode().unwrap();
 3451        match &mut pending_mode {
 3452            SelectMode::Word(range) | SelectMode::Line(range) => *range = tail_anchor..tail_anchor,
 3453            _ => {}
 3454        }
 3455
 3456        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3457            SelectionEffects::scroll(Autoscroll::fit())
 3458        } else {
 3459            SelectionEffects::no_scroll()
 3460        };
 3461
 3462        self.change_selections(effects, window, cx, |s| {
 3463            s.set_pending(pending_selection, pending_mode)
 3464        });
 3465    }
 3466
 3467    fn begin_selection(
 3468        &mut self,
 3469        position: DisplayPoint,
 3470        add: bool,
 3471        click_count: usize,
 3472        window: &mut Window,
 3473        cx: &mut Context<Self>,
 3474    ) {
 3475        if !self.focus_handle.is_focused(window) {
 3476            self.last_focused_descendant = None;
 3477            window.focus(&self.focus_handle);
 3478        }
 3479
 3480        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3481        let buffer = &display_map.buffer_snapshot;
 3482        let position = display_map.clip_point(position, Bias::Left);
 3483
 3484        let start;
 3485        let end;
 3486        let mode;
 3487        let mut auto_scroll;
 3488        match click_count {
 3489            1 => {
 3490                start = buffer.anchor_before(position.to_point(&display_map));
 3491                end = start;
 3492                mode = SelectMode::Character;
 3493                auto_scroll = true;
 3494            }
 3495            2 => {
 3496                let position = display_map
 3497                    .clip_point(position, Bias::Left)
 3498                    .to_offset(&display_map, Bias::Left);
 3499                let (range, _) = buffer.surrounding_word(position, false);
 3500                start = buffer.anchor_before(range.start);
 3501                end = buffer.anchor_before(range.end);
 3502                mode = SelectMode::Word(start..end);
 3503                auto_scroll = true;
 3504            }
 3505            3 => {
 3506                let position = display_map
 3507                    .clip_point(position, Bias::Left)
 3508                    .to_point(&display_map);
 3509                let line_start = display_map.prev_line_boundary(position).0;
 3510                let next_line_start = buffer.clip_point(
 3511                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3512                    Bias::Left,
 3513                );
 3514                start = buffer.anchor_before(line_start);
 3515                end = buffer.anchor_before(next_line_start);
 3516                mode = SelectMode::Line(start..end);
 3517                auto_scroll = true;
 3518            }
 3519            _ => {
 3520                start = buffer.anchor_before(0);
 3521                end = buffer.anchor_before(buffer.len());
 3522                mode = SelectMode::All;
 3523                auto_scroll = false;
 3524            }
 3525        }
 3526        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3527
 3528        let point_to_delete: Option<usize> = {
 3529            let selected_points: Vec<Selection<Point>> =
 3530                self.selections.disjoint_in_range(start..end, cx);
 3531
 3532            if !add || click_count > 1 {
 3533                None
 3534            } else if !selected_points.is_empty() {
 3535                Some(selected_points[0].id)
 3536            } else {
 3537                let clicked_point_already_selected =
 3538                    self.selections.disjoint.iter().find(|selection| {
 3539                        selection.start.to_point(buffer) == start.to_point(buffer)
 3540                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3541                    });
 3542
 3543                clicked_point_already_selected.map(|selection| selection.id)
 3544            }
 3545        };
 3546
 3547        let selections_count = self.selections.count();
 3548        let effects = if auto_scroll {
 3549            SelectionEffects::default()
 3550        } else {
 3551            SelectionEffects::no_scroll()
 3552        };
 3553
 3554        self.change_selections(effects, window, cx, |s| {
 3555            if let Some(point_to_delete) = point_to_delete {
 3556                s.delete(point_to_delete);
 3557
 3558                if selections_count == 1 {
 3559                    s.set_pending_anchor_range(start..end, mode);
 3560                }
 3561            } else {
 3562                if !add {
 3563                    s.clear_disjoint();
 3564                }
 3565
 3566                s.set_pending_anchor_range(start..end, mode);
 3567            }
 3568        });
 3569    }
 3570
 3571    fn begin_columnar_selection(
 3572        &mut self,
 3573        position: DisplayPoint,
 3574        goal_column: u32,
 3575        reset: bool,
 3576        mode: ColumnarMode,
 3577        window: &mut Window,
 3578        cx: &mut Context<Self>,
 3579    ) {
 3580        if !self.focus_handle.is_focused(window) {
 3581            self.last_focused_descendant = None;
 3582            window.focus(&self.focus_handle);
 3583        }
 3584
 3585        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3586
 3587        if reset {
 3588            let pointer_position = display_map
 3589                .buffer_snapshot
 3590                .anchor_before(position.to_point(&display_map));
 3591
 3592            self.change_selections(
 3593                SelectionEffects::scroll(Autoscroll::newest()),
 3594                window,
 3595                cx,
 3596                |s| {
 3597                    s.clear_disjoint();
 3598                    s.set_pending_anchor_range(
 3599                        pointer_position..pointer_position,
 3600                        SelectMode::Character,
 3601                    );
 3602                },
 3603            );
 3604        };
 3605
 3606        let tail = self.selections.newest::<Point>(cx).tail();
 3607        let selection_anchor = display_map.buffer_snapshot.anchor_before(tail);
 3608        self.columnar_selection_state = match mode {
 3609            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3610                selection_tail: selection_anchor,
 3611                display_point: if reset {
 3612                    if position.column() != goal_column {
 3613                        Some(DisplayPoint::new(position.row(), goal_column))
 3614                    } else {
 3615                        None
 3616                    }
 3617                } else {
 3618                    None
 3619                },
 3620            }),
 3621            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3622                selection_tail: selection_anchor,
 3623            }),
 3624        };
 3625
 3626        if !reset {
 3627            self.select_columns(position, goal_column, &display_map, window, cx);
 3628        }
 3629    }
 3630
 3631    fn update_selection(
 3632        &mut self,
 3633        position: DisplayPoint,
 3634        goal_column: u32,
 3635        scroll_delta: gpui::Point<f32>,
 3636        window: &mut Window,
 3637        cx: &mut Context<Self>,
 3638    ) {
 3639        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3640
 3641        if self.columnar_selection_state.is_some() {
 3642            self.select_columns(position, goal_column, &display_map, window, cx);
 3643        } else if let Some(mut pending) = self.selections.pending_anchor() {
 3644            let buffer = &display_map.buffer_snapshot;
 3645            let head;
 3646            let tail;
 3647            let mode = self.selections.pending_mode().unwrap();
 3648            match &mode {
 3649                SelectMode::Character => {
 3650                    head = position.to_point(&display_map);
 3651                    tail = pending.tail().to_point(buffer);
 3652                }
 3653                SelectMode::Word(original_range) => {
 3654                    let offset = display_map
 3655                        .clip_point(position, Bias::Left)
 3656                        .to_offset(&display_map, Bias::Left);
 3657                    let original_range = original_range.to_offset(buffer);
 3658
 3659                    let head_offset = if buffer.is_inside_word(offset, false)
 3660                        || original_range.contains(&offset)
 3661                    {
 3662                        let (word_range, _) = buffer.surrounding_word(offset, false);
 3663                        if word_range.start < original_range.start {
 3664                            word_range.start
 3665                        } else {
 3666                            word_range.end
 3667                        }
 3668                    } else {
 3669                        offset
 3670                    };
 3671
 3672                    head = head_offset.to_point(buffer);
 3673                    if head_offset <= original_range.start {
 3674                        tail = original_range.end.to_point(buffer);
 3675                    } else {
 3676                        tail = original_range.start.to_point(buffer);
 3677                    }
 3678                }
 3679                SelectMode::Line(original_range) => {
 3680                    let original_range = original_range.to_point(&display_map.buffer_snapshot);
 3681
 3682                    let position = display_map
 3683                        .clip_point(position, Bias::Left)
 3684                        .to_point(&display_map);
 3685                    let line_start = display_map.prev_line_boundary(position).0;
 3686                    let next_line_start = buffer.clip_point(
 3687                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3688                        Bias::Left,
 3689                    );
 3690
 3691                    if line_start < original_range.start {
 3692                        head = line_start
 3693                    } else {
 3694                        head = next_line_start
 3695                    }
 3696
 3697                    if head <= original_range.start {
 3698                        tail = original_range.end;
 3699                    } else {
 3700                        tail = original_range.start;
 3701                    }
 3702                }
 3703                SelectMode::All => {
 3704                    return;
 3705                }
 3706            };
 3707
 3708            if head < tail {
 3709                pending.start = buffer.anchor_before(head);
 3710                pending.end = buffer.anchor_before(tail);
 3711                pending.reversed = true;
 3712            } else {
 3713                pending.start = buffer.anchor_before(tail);
 3714                pending.end = buffer.anchor_before(head);
 3715                pending.reversed = false;
 3716            }
 3717
 3718            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3719                s.set_pending(pending, mode);
 3720            });
 3721        } else {
 3722            log::error!("update_selection dispatched with no pending selection");
 3723            return;
 3724        }
 3725
 3726        self.apply_scroll_delta(scroll_delta, window, cx);
 3727        cx.notify();
 3728    }
 3729
 3730    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3731        self.columnar_selection_state.take();
 3732        if self.selections.pending_anchor().is_some() {
 3733            let selections = self.selections.all::<usize>(cx);
 3734            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3735                s.select(selections);
 3736                s.clear_pending();
 3737            });
 3738        }
 3739    }
 3740
 3741    fn select_columns(
 3742        &mut self,
 3743        head: DisplayPoint,
 3744        goal_column: u32,
 3745        display_map: &DisplaySnapshot,
 3746        window: &mut Window,
 3747        cx: &mut Context<Self>,
 3748    ) {
 3749        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3750            return;
 3751        };
 3752
 3753        let tail = match columnar_state {
 3754            ColumnarSelectionState::FromMouse {
 3755                selection_tail,
 3756                display_point,
 3757            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3758            ColumnarSelectionState::FromSelection { selection_tail } => {
 3759                selection_tail.to_display_point(display_map)
 3760            }
 3761        };
 3762
 3763        let start_row = cmp::min(tail.row(), head.row());
 3764        let end_row = cmp::max(tail.row(), head.row());
 3765        let start_column = cmp::min(tail.column(), goal_column);
 3766        let end_column = cmp::max(tail.column(), goal_column);
 3767        let reversed = start_column < tail.column();
 3768
 3769        let selection_ranges = (start_row.0..=end_row.0)
 3770            .map(DisplayRow)
 3771            .filter_map(|row| {
 3772                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3773                    || start_column <= display_map.line_len(row))
 3774                    && !display_map.is_block_line(row)
 3775                {
 3776                    let start = display_map
 3777                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3778                        .to_point(display_map);
 3779                    let end = display_map
 3780                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3781                        .to_point(display_map);
 3782                    if reversed {
 3783                        Some(end..start)
 3784                    } else {
 3785                        Some(start..end)
 3786                    }
 3787                } else {
 3788                    None
 3789                }
 3790            })
 3791            .collect::<Vec<_>>();
 3792
 3793        let ranges = match columnar_state {
 3794            ColumnarSelectionState::FromMouse { .. } => {
 3795                let mut non_empty_ranges = selection_ranges
 3796                    .iter()
 3797                    .filter(|selection_range| selection_range.start != selection_range.end)
 3798                    .peekable();
 3799                if non_empty_ranges.peek().is_some() {
 3800                    non_empty_ranges.cloned().collect()
 3801                } else {
 3802                    selection_ranges
 3803                }
 3804            }
 3805            _ => selection_ranges,
 3806        };
 3807
 3808        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3809            s.select_ranges(ranges);
 3810        });
 3811        cx.notify();
 3812    }
 3813
 3814    pub fn has_non_empty_selection(&self, cx: &mut App) -> bool {
 3815        self.selections
 3816            .all_adjusted(cx)
 3817            .iter()
 3818            .any(|selection| !selection.is_empty())
 3819    }
 3820
 3821    pub fn has_pending_nonempty_selection(&self) -> bool {
 3822        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3823            Some(Selection { start, end, .. }) => start != end,
 3824            None => false,
 3825        };
 3826
 3827        pending_nonempty_selection
 3828            || (self.columnar_selection_state.is_some() && self.selections.disjoint.len() > 1)
 3829    }
 3830
 3831    pub fn has_pending_selection(&self) -> bool {
 3832        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3833    }
 3834
 3835    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3836        self.selection_mark_mode = false;
 3837        self.selection_drag_state = SelectionDragState::None;
 3838
 3839        if self.clear_expanded_diff_hunks(cx) {
 3840            cx.notify();
 3841            return;
 3842        }
 3843        if self.dismiss_menus_and_popups(true, window, cx) {
 3844            return;
 3845        }
 3846
 3847        if self.mode.is_full()
 3848            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3849        {
 3850            return;
 3851        }
 3852
 3853        cx.propagate();
 3854    }
 3855
 3856    pub fn dismiss_menus_and_popups(
 3857        &mut self,
 3858        is_user_requested: bool,
 3859        window: &mut Window,
 3860        cx: &mut Context<Self>,
 3861    ) -> bool {
 3862        if self.take_rename(false, window, cx).is_some() {
 3863            return true;
 3864        }
 3865
 3866        if hide_hover(self, cx) {
 3867            return true;
 3868        }
 3869
 3870        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3871            return true;
 3872        }
 3873
 3874        if self.hide_context_menu(window, cx).is_some() {
 3875            return true;
 3876        }
 3877
 3878        if self.mouse_context_menu.take().is_some() {
 3879            return true;
 3880        }
 3881
 3882        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3883            return true;
 3884        }
 3885
 3886        if self.snippet_stack.pop().is_some() {
 3887            return true;
 3888        }
 3889
 3890        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3891            self.dismiss_diagnostics(cx);
 3892            return true;
 3893        }
 3894
 3895        false
 3896    }
 3897
 3898    fn linked_editing_ranges_for(
 3899        &self,
 3900        selection: Range<text::Anchor>,
 3901        cx: &App,
 3902    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 3903        if self.linked_edit_ranges.is_empty() {
 3904            return None;
 3905        }
 3906        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 3907            selection.end.buffer_id.and_then(|end_buffer_id| {
 3908                if selection.start.buffer_id != Some(end_buffer_id) {
 3909                    return None;
 3910                }
 3911                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 3912                let snapshot = buffer.read(cx).snapshot();
 3913                self.linked_edit_ranges
 3914                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 3915                    .map(|ranges| (ranges, snapshot, buffer))
 3916            })?;
 3917        use text::ToOffset as TO;
 3918        // find offset from the start of current range to current cursor position
 3919        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 3920
 3921        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 3922        let start_difference = start_offset - start_byte_offset;
 3923        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 3924        let end_difference = end_offset - start_byte_offset;
 3925        // Current range has associated linked ranges.
 3926        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3927        for range in linked_ranges.iter() {
 3928            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 3929            let end_offset = start_offset + end_difference;
 3930            let start_offset = start_offset + start_difference;
 3931            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 3932                continue;
 3933            }
 3934            if self.selections.disjoint_anchor_ranges().any(|s| {
 3935                if s.start.buffer_id != selection.start.buffer_id
 3936                    || s.end.buffer_id != selection.end.buffer_id
 3937                {
 3938                    return false;
 3939                }
 3940                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 3941                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 3942            }) {
 3943                continue;
 3944            }
 3945            let start = buffer_snapshot.anchor_after(start_offset);
 3946            let end = buffer_snapshot.anchor_after(end_offset);
 3947            linked_edits
 3948                .entry(buffer.clone())
 3949                .or_default()
 3950                .push(start..end);
 3951        }
 3952        Some(linked_edits)
 3953    }
 3954
 3955    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 3956        let text: Arc<str> = text.into();
 3957
 3958        if self.read_only(cx) {
 3959            return;
 3960        }
 3961
 3962        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 3963
 3964        let selections = self.selections.all_adjusted(cx);
 3965        let mut bracket_inserted = false;
 3966        let mut edits = Vec::new();
 3967        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 3968        let mut new_selections = Vec::with_capacity(selections.len());
 3969        let mut new_autoclose_regions = Vec::new();
 3970        let snapshot = self.buffer.read(cx).read(cx);
 3971        let mut clear_linked_edit_ranges = false;
 3972
 3973        for (selection, autoclose_region) in
 3974            self.selections_with_autoclose_regions(selections, &snapshot)
 3975        {
 3976            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 3977                // Determine if the inserted text matches the opening or closing
 3978                // bracket of any of this language's bracket pairs.
 3979                let mut bracket_pair = None;
 3980                let mut is_bracket_pair_start = false;
 3981                let mut is_bracket_pair_end = false;
 3982                if !text.is_empty() {
 3983                    let mut bracket_pair_matching_end = None;
 3984                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 3985                    //  and they are removing the character that triggered IME popup.
 3986                    for (pair, enabled) in scope.brackets() {
 3987                        if !pair.close && !pair.surround {
 3988                            continue;
 3989                        }
 3990
 3991                        if enabled && pair.start.ends_with(text.as_ref()) {
 3992                            let prefix_len = pair.start.len() - text.len();
 3993                            let preceding_text_matches_prefix = prefix_len == 0
 3994                                || (selection.start.column >= (prefix_len as u32)
 3995                                    && snapshot.contains_str_at(
 3996                                        Point::new(
 3997                                            selection.start.row,
 3998                                            selection.start.column - (prefix_len as u32),
 3999                                        ),
 4000                                        &pair.start[..prefix_len],
 4001                                    ));
 4002                            if preceding_text_matches_prefix {
 4003                                bracket_pair = Some(pair.clone());
 4004                                is_bracket_pair_start = true;
 4005                                break;
 4006                            }
 4007                        }
 4008                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4009                        {
 4010                            // take first bracket pair matching end, but don't break in case a later bracket
 4011                            // pair matches start
 4012                            bracket_pair_matching_end = Some(pair.clone());
 4013                        }
 4014                    }
 4015                    if let Some(end) = bracket_pair_matching_end
 4016                        && bracket_pair.is_none()
 4017                    {
 4018                        bracket_pair = Some(end);
 4019                        is_bracket_pair_end = true;
 4020                    }
 4021                }
 4022
 4023                if let Some(bracket_pair) = bracket_pair {
 4024                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4025                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4026                    let auto_surround =
 4027                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4028                    if selection.is_empty() {
 4029                        if is_bracket_pair_start {
 4030                            // If the inserted text is a suffix of an opening bracket and the
 4031                            // selection is preceded by the rest of the opening bracket, then
 4032                            // insert the closing bracket.
 4033                            let following_text_allows_autoclose = snapshot
 4034                                .chars_at(selection.start)
 4035                                .next()
 4036                                .map_or(true, |c| scope.should_autoclose_before(c));
 4037
 4038                            let preceding_text_allows_autoclose = selection.start.column == 0
 4039                                || snapshot.reversed_chars_at(selection.start).next().map_or(
 4040                                    true,
 4041                                    |c| {
 4042                                        bracket_pair.start != bracket_pair.end
 4043                                            || !snapshot
 4044                                                .char_classifier_at(selection.start)
 4045                                                .is_word(c)
 4046                                    },
 4047                                );
 4048
 4049                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4050                                && bracket_pair.start.len() == 1
 4051                            {
 4052                                let target = bracket_pair.start.chars().next().unwrap();
 4053                                let current_line_count = snapshot
 4054                                    .reversed_chars_at(selection.start)
 4055                                    .take_while(|&c| c != '\n')
 4056                                    .filter(|&c| c == target)
 4057                                    .count();
 4058                                current_line_count % 2 == 1
 4059                            } else {
 4060                                false
 4061                            };
 4062
 4063                            if autoclose
 4064                                && bracket_pair.close
 4065                                && following_text_allows_autoclose
 4066                                && preceding_text_allows_autoclose
 4067                                && !is_closing_quote
 4068                            {
 4069                                let anchor = snapshot.anchor_before(selection.end);
 4070                                new_selections.push((selection.map(|_| anchor), text.len()));
 4071                                new_autoclose_regions.push((
 4072                                    anchor,
 4073                                    text.len(),
 4074                                    selection.id,
 4075                                    bracket_pair.clone(),
 4076                                ));
 4077                                edits.push((
 4078                                    selection.range(),
 4079                                    format!("{}{}", text, bracket_pair.end).into(),
 4080                                ));
 4081                                bracket_inserted = true;
 4082                                continue;
 4083                            }
 4084                        }
 4085
 4086                        if let Some(region) = autoclose_region {
 4087                            // If the selection is followed by an auto-inserted closing bracket,
 4088                            // then don't insert that closing bracket again; just move the selection
 4089                            // past the closing bracket.
 4090                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4091                                && text.as_ref() == region.pair.end.as_str()
 4092                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4093                            if should_skip {
 4094                                let anchor = snapshot.anchor_after(selection.end);
 4095                                new_selections
 4096                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4097                                continue;
 4098                            }
 4099                        }
 4100
 4101                        let always_treat_brackets_as_autoclosed = snapshot
 4102                            .language_settings_at(selection.start, cx)
 4103                            .always_treat_brackets_as_autoclosed;
 4104                        if always_treat_brackets_as_autoclosed
 4105                            && is_bracket_pair_end
 4106                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4107                        {
 4108                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4109                            // and the inserted text is a closing bracket and the selection is followed
 4110                            // by the closing bracket then move the selection past the closing bracket.
 4111                            let anchor = snapshot.anchor_after(selection.end);
 4112                            new_selections.push((selection.map(|_| anchor), text.len()));
 4113                            continue;
 4114                        }
 4115                    }
 4116                    // If an opening bracket is 1 character long and is typed while
 4117                    // text is selected, then surround that text with the bracket pair.
 4118                    else if auto_surround
 4119                        && bracket_pair.surround
 4120                        && is_bracket_pair_start
 4121                        && bracket_pair.start.chars().count() == 1
 4122                    {
 4123                        edits.push((selection.start..selection.start, text.clone()));
 4124                        edits.push((
 4125                            selection.end..selection.end,
 4126                            bracket_pair.end.as_str().into(),
 4127                        ));
 4128                        bracket_inserted = true;
 4129                        new_selections.push((
 4130                            Selection {
 4131                                id: selection.id,
 4132                                start: snapshot.anchor_after(selection.start),
 4133                                end: snapshot.anchor_before(selection.end),
 4134                                reversed: selection.reversed,
 4135                                goal: selection.goal,
 4136                            },
 4137                            0,
 4138                        ));
 4139                        continue;
 4140                    }
 4141                }
 4142            }
 4143
 4144            if self.auto_replace_emoji_shortcode
 4145                && selection.is_empty()
 4146                && text.as_ref().ends_with(':')
 4147                && let Some(possible_emoji_short_code) =
 4148                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4149                && !possible_emoji_short_code.is_empty()
 4150                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4151            {
 4152                let emoji_shortcode_start = Point::new(
 4153                    selection.start.row,
 4154                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4155                );
 4156
 4157                // Remove shortcode from buffer
 4158                edits.push((
 4159                    emoji_shortcode_start..selection.start,
 4160                    "".to_string().into(),
 4161                ));
 4162                new_selections.push((
 4163                    Selection {
 4164                        id: selection.id,
 4165                        start: snapshot.anchor_after(emoji_shortcode_start),
 4166                        end: snapshot.anchor_before(selection.start),
 4167                        reversed: selection.reversed,
 4168                        goal: selection.goal,
 4169                    },
 4170                    0,
 4171                ));
 4172
 4173                // Insert emoji
 4174                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4175                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4176                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4177
 4178                continue;
 4179            }
 4180
 4181            // If not handling any auto-close operation, then just replace the selected
 4182            // text with the given input and move the selection to the end of the
 4183            // newly inserted text.
 4184            let anchor = snapshot.anchor_after(selection.end);
 4185            if !self.linked_edit_ranges.is_empty() {
 4186                let start_anchor = snapshot.anchor_before(selection.start);
 4187
 4188                let is_word_char = text.chars().next().map_or(true, |char| {
 4189                    let classifier = snapshot
 4190                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4191                        .ignore_punctuation(true);
 4192                    classifier.is_word(char)
 4193                });
 4194
 4195                if is_word_char {
 4196                    if let Some(ranges) = self
 4197                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4198                    {
 4199                        for (buffer, edits) in ranges {
 4200                            linked_edits
 4201                                .entry(buffer.clone())
 4202                                .or_default()
 4203                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4204                        }
 4205                    }
 4206                } else {
 4207                    clear_linked_edit_ranges = true;
 4208                }
 4209            }
 4210
 4211            new_selections.push((selection.map(|_| anchor), 0));
 4212            edits.push((selection.start..selection.end, text.clone()));
 4213        }
 4214
 4215        drop(snapshot);
 4216
 4217        self.transact(window, cx, |this, window, cx| {
 4218            if clear_linked_edit_ranges {
 4219                this.linked_edit_ranges.clear();
 4220            }
 4221            let initial_buffer_versions =
 4222                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4223
 4224            this.buffer.update(cx, |buffer, cx| {
 4225                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4226            });
 4227            for (buffer, edits) in linked_edits {
 4228                buffer.update(cx, |buffer, cx| {
 4229                    let snapshot = buffer.snapshot();
 4230                    let edits = edits
 4231                        .into_iter()
 4232                        .map(|(range, text)| {
 4233                            use text::ToPoint as TP;
 4234                            let end_point = TP::to_point(&range.end, &snapshot);
 4235                            let start_point = TP::to_point(&range.start, &snapshot);
 4236                            (start_point..end_point, text)
 4237                        })
 4238                        .sorted_by_key(|(range, _)| range.start);
 4239                    buffer.edit(edits, None, cx);
 4240                })
 4241            }
 4242            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4243            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4244            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4245            let new_selections = resolve_selections::<usize, _>(new_anchor_selections, &map)
 4246                .zip(new_selection_deltas)
 4247                .map(|(selection, delta)| Selection {
 4248                    id: selection.id,
 4249                    start: selection.start + delta,
 4250                    end: selection.end + delta,
 4251                    reversed: selection.reversed,
 4252                    goal: SelectionGoal::None,
 4253                })
 4254                .collect::<Vec<_>>();
 4255
 4256            let mut i = 0;
 4257            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4258                let position = position.to_offset(&map.buffer_snapshot) + delta;
 4259                let start = map.buffer_snapshot.anchor_before(position);
 4260                let end = map.buffer_snapshot.anchor_after(position);
 4261                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4262                    match existing_state.range.start.cmp(&start, &map.buffer_snapshot) {
 4263                        Ordering::Less => i += 1,
 4264                        Ordering::Greater => break,
 4265                        Ordering::Equal => {
 4266                            match end.cmp(&existing_state.range.end, &map.buffer_snapshot) {
 4267                                Ordering::Less => i += 1,
 4268                                Ordering::Equal => break,
 4269                                Ordering::Greater => break,
 4270                            }
 4271                        }
 4272                    }
 4273                }
 4274                this.autoclose_regions.insert(
 4275                    i,
 4276                    AutocloseRegion {
 4277                        selection_id,
 4278                        range: start..end,
 4279                        pair,
 4280                    },
 4281                );
 4282            }
 4283
 4284            let had_active_edit_prediction = this.has_active_edit_prediction();
 4285            this.change_selections(
 4286                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4287                window,
 4288                cx,
 4289                |s| s.select(new_selections),
 4290            );
 4291
 4292            if !bracket_inserted
 4293                && let Some(on_type_format_task) =
 4294                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4295            {
 4296                on_type_format_task.detach_and_log_err(cx);
 4297            }
 4298
 4299            let editor_settings = EditorSettings::get_global(cx);
 4300            if bracket_inserted
 4301                && (editor_settings.auto_signature_help
 4302                    || editor_settings.show_signature_help_after_edits)
 4303            {
 4304                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4305            }
 4306
 4307            let trigger_in_words =
 4308                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4309            if this.hard_wrap.is_some() {
 4310                let latest: Range<Point> = this.selections.newest(cx).range();
 4311                if latest.is_empty()
 4312                    && this
 4313                        .buffer()
 4314                        .read(cx)
 4315                        .snapshot(cx)
 4316                        .line_len(MultiBufferRow(latest.start.row))
 4317                        == latest.start.column
 4318                {
 4319                    this.rewrap_impl(
 4320                        RewrapOptions {
 4321                            override_language_settings: true,
 4322                            preserve_existing_whitespace: true,
 4323                        },
 4324                        cx,
 4325                    )
 4326                }
 4327            }
 4328            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4329            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 4330            this.refresh_edit_prediction(true, false, window, cx);
 4331            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4332        });
 4333    }
 4334
 4335    fn find_possible_emoji_shortcode_at_position(
 4336        snapshot: &MultiBufferSnapshot,
 4337        position: Point,
 4338    ) -> Option<String> {
 4339        let mut chars = Vec::new();
 4340        let mut found_colon = false;
 4341        for char in snapshot.reversed_chars_at(position).take(100) {
 4342            // Found a possible emoji shortcode in the middle of the buffer
 4343            if found_colon {
 4344                if char.is_whitespace() {
 4345                    chars.reverse();
 4346                    return Some(chars.iter().collect());
 4347                }
 4348                // If the previous character is not a whitespace, we are in the middle of a word
 4349                // and we only want to complete the shortcode if the word is made up of other emojis
 4350                let mut containing_word = String::new();
 4351                for ch in snapshot
 4352                    .reversed_chars_at(position)
 4353                    .skip(chars.len() + 1)
 4354                    .take(100)
 4355                {
 4356                    if ch.is_whitespace() {
 4357                        break;
 4358                    }
 4359                    containing_word.push(ch);
 4360                }
 4361                let containing_word = containing_word.chars().rev().collect::<String>();
 4362                if util::word_consists_of_emojis(containing_word.as_str()) {
 4363                    chars.reverse();
 4364                    return Some(chars.iter().collect());
 4365                }
 4366            }
 4367
 4368            if char.is_whitespace() || !char.is_ascii() {
 4369                return None;
 4370            }
 4371            if char == ':' {
 4372                found_colon = true;
 4373            } else {
 4374                chars.push(char);
 4375            }
 4376        }
 4377        // Found a possible emoji shortcode at the beginning of the buffer
 4378        chars.reverse();
 4379        Some(chars.iter().collect())
 4380    }
 4381
 4382    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4383        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4384        self.transact(window, cx, |this, window, cx| {
 4385            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4386                let selections = this.selections.all::<usize>(cx);
 4387                let multi_buffer = this.buffer.read(cx);
 4388                let buffer = multi_buffer.snapshot(cx);
 4389                selections
 4390                    .iter()
 4391                    .map(|selection| {
 4392                        let start_point = selection.start.to_point(&buffer);
 4393                        let mut existing_indent =
 4394                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4395                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4396                        let start = selection.start;
 4397                        let end = selection.end;
 4398                        let selection_is_empty = start == end;
 4399                        let language_scope = buffer.language_scope_at(start);
 4400                        let (
 4401                            comment_delimiter,
 4402                            doc_delimiter,
 4403                            insert_extra_newline,
 4404                            indent_on_newline,
 4405                            indent_on_extra_newline,
 4406                        ) = if let Some(language) = &language_scope {
 4407                            let mut insert_extra_newline =
 4408                                insert_extra_newline_brackets(&buffer, start..end, language)
 4409                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4410
 4411                            // Comment extension on newline is allowed only for cursor selections
 4412                            let comment_delimiter = maybe!({
 4413                                if !selection_is_empty {
 4414                                    return None;
 4415                                }
 4416
 4417                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4418                                    return None;
 4419                                }
 4420
 4421                                let delimiters = language.line_comment_prefixes();
 4422                                let max_len_of_delimiter =
 4423                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4424                                let (snapshot, range) =
 4425                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4426
 4427                                let num_of_whitespaces = snapshot
 4428                                    .chars_for_range(range.clone())
 4429                                    .take_while(|c| c.is_whitespace())
 4430                                    .count();
 4431                                let comment_candidate = snapshot
 4432                                    .chars_for_range(range.clone())
 4433                                    .skip(num_of_whitespaces)
 4434                                    .take(max_len_of_delimiter)
 4435                                    .collect::<String>();
 4436                                let (delimiter, trimmed_len) = delimiters
 4437                                    .iter()
 4438                                    .filter_map(|delimiter| {
 4439                                        let prefix = delimiter.trim_end();
 4440                                        if comment_candidate.starts_with(prefix) {
 4441                                            Some((delimiter, prefix.len()))
 4442                                        } else {
 4443                                            None
 4444                                        }
 4445                                    })
 4446                                    .max_by_key(|(_, len)| *len)?;
 4447
 4448                                if let Some(BlockCommentConfig {
 4449                                    start: block_start, ..
 4450                                }) = language.block_comment()
 4451                                {
 4452                                    let block_start_trimmed = block_start.trim_end();
 4453                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4454                                        let line_content = snapshot
 4455                                            .chars_for_range(range)
 4456                                            .skip(num_of_whitespaces)
 4457                                            .take(block_start_trimmed.len())
 4458                                            .collect::<String>();
 4459
 4460                                        if line_content.starts_with(block_start_trimmed) {
 4461                                            return None;
 4462                                        }
 4463                                    }
 4464                                }
 4465
 4466                                let cursor_is_placed_after_comment_marker =
 4467                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4468                                if cursor_is_placed_after_comment_marker {
 4469                                    Some(delimiter.clone())
 4470                                } else {
 4471                                    None
 4472                                }
 4473                            });
 4474
 4475                            let mut indent_on_newline = IndentSize::spaces(0);
 4476                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4477
 4478                            let doc_delimiter = maybe!({
 4479                                if !selection_is_empty {
 4480                                    return None;
 4481                                }
 4482
 4483                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4484                                    return None;
 4485                                }
 4486
 4487                                let BlockCommentConfig {
 4488                                    start: start_tag,
 4489                                    end: end_tag,
 4490                                    prefix: delimiter,
 4491                                    tab_size: len,
 4492                                } = language.documentation_comment()?;
 4493                                let is_within_block_comment = buffer
 4494                                    .language_scope_at(start_point)
 4495                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4496                                if !is_within_block_comment {
 4497                                    return None;
 4498                                }
 4499
 4500                                let (snapshot, range) =
 4501                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4502
 4503                                let num_of_whitespaces = snapshot
 4504                                    .chars_for_range(range.clone())
 4505                                    .take_while(|c| c.is_whitespace())
 4506                                    .count();
 4507
 4508                                // 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.
 4509                                let column = start_point.column;
 4510                                let cursor_is_after_start_tag = {
 4511                                    let start_tag_len = start_tag.len();
 4512                                    let start_tag_line = snapshot
 4513                                        .chars_for_range(range.clone())
 4514                                        .skip(num_of_whitespaces)
 4515                                        .take(start_tag_len)
 4516                                        .collect::<String>();
 4517                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4518                                        num_of_whitespaces + start_tag_len <= column as usize
 4519                                    } else {
 4520                                        false
 4521                                    }
 4522                                };
 4523
 4524                                let cursor_is_after_delimiter = {
 4525                                    let delimiter_trim = delimiter.trim_end();
 4526                                    let delimiter_line = snapshot
 4527                                        .chars_for_range(range.clone())
 4528                                        .skip(num_of_whitespaces)
 4529                                        .take(delimiter_trim.len())
 4530                                        .collect::<String>();
 4531                                    if delimiter_line.starts_with(delimiter_trim) {
 4532                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4533                                    } else {
 4534                                        false
 4535                                    }
 4536                                };
 4537
 4538                                let cursor_is_before_end_tag_if_exists = {
 4539                                    let mut char_position = 0u32;
 4540                                    let mut end_tag_offset = None;
 4541
 4542                                    'outer: for chunk in snapshot.text_for_range(range.clone()) {
 4543                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4544                                            let chars_before_match =
 4545                                                chunk[..byte_pos].chars().count() as u32;
 4546                                            end_tag_offset =
 4547                                                Some(char_position + chars_before_match);
 4548                                            break 'outer;
 4549                                        }
 4550                                        char_position += chunk.chars().count() as u32;
 4551                                    }
 4552
 4553                                    if let Some(end_tag_offset) = end_tag_offset {
 4554                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4555                                        if cursor_is_after_start_tag {
 4556                                            if cursor_is_before_end_tag {
 4557                                                insert_extra_newline = true;
 4558                                            }
 4559                                            let cursor_is_at_start_of_end_tag =
 4560                                                column == end_tag_offset;
 4561                                            if cursor_is_at_start_of_end_tag {
 4562                                                indent_on_extra_newline.len = *len;
 4563                                            }
 4564                                        }
 4565                                        cursor_is_before_end_tag
 4566                                    } else {
 4567                                        true
 4568                                    }
 4569                                };
 4570
 4571                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4572                                    && cursor_is_before_end_tag_if_exists
 4573                                {
 4574                                    if cursor_is_after_start_tag {
 4575                                        indent_on_newline.len = *len;
 4576                                    }
 4577                                    Some(delimiter.clone())
 4578                                } else {
 4579                                    None
 4580                                }
 4581                            });
 4582
 4583                            (
 4584                                comment_delimiter,
 4585                                doc_delimiter,
 4586                                insert_extra_newline,
 4587                                indent_on_newline,
 4588                                indent_on_extra_newline,
 4589                            )
 4590                        } else {
 4591                            (
 4592                                None,
 4593                                None,
 4594                                false,
 4595                                IndentSize::default(),
 4596                                IndentSize::default(),
 4597                            )
 4598                        };
 4599
 4600                        let prevent_auto_indent = doc_delimiter.is_some();
 4601                        let delimiter = comment_delimiter.or(doc_delimiter);
 4602
 4603                        let capacity_for_delimiter =
 4604                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4605                        let mut new_text = String::with_capacity(
 4606                            1 + capacity_for_delimiter
 4607                                + existing_indent.len as usize
 4608                                + indent_on_newline.len as usize
 4609                                + indent_on_extra_newline.len as usize,
 4610                        );
 4611                        new_text.push('\n');
 4612                        new_text.extend(existing_indent.chars());
 4613                        new_text.extend(indent_on_newline.chars());
 4614
 4615                        if let Some(delimiter) = &delimiter {
 4616                            new_text.push_str(delimiter);
 4617                        }
 4618
 4619                        if insert_extra_newline {
 4620                            new_text.push('\n');
 4621                            new_text.extend(existing_indent.chars());
 4622                            new_text.extend(indent_on_extra_newline.chars());
 4623                        }
 4624
 4625                        let anchor = buffer.anchor_after(end);
 4626                        let new_selection = selection.map(|_| anchor);
 4627                        (
 4628                            ((start..end, new_text), prevent_auto_indent),
 4629                            (insert_extra_newline, new_selection),
 4630                        )
 4631                    })
 4632                    .unzip()
 4633            };
 4634
 4635            let mut auto_indent_edits = Vec::new();
 4636            let mut edits = Vec::new();
 4637            for (edit, prevent_auto_indent) in edits_with_flags {
 4638                if prevent_auto_indent {
 4639                    edits.push(edit);
 4640                } else {
 4641                    auto_indent_edits.push(edit);
 4642                }
 4643            }
 4644            if !edits.is_empty() {
 4645                this.edit(edits, cx);
 4646            }
 4647            if !auto_indent_edits.is_empty() {
 4648                this.edit_with_autoindent(auto_indent_edits, cx);
 4649            }
 4650
 4651            let buffer = this.buffer.read(cx).snapshot(cx);
 4652            let new_selections = selection_info
 4653                .into_iter()
 4654                .map(|(extra_newline_inserted, new_selection)| {
 4655                    let mut cursor = new_selection.end.to_point(&buffer);
 4656                    if extra_newline_inserted {
 4657                        cursor.row -= 1;
 4658                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4659                    }
 4660                    new_selection.map(|_| cursor)
 4661                })
 4662                .collect();
 4663
 4664            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4665            this.refresh_edit_prediction(true, false, window, cx);
 4666        });
 4667    }
 4668
 4669    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4670        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4671
 4672        let buffer = self.buffer.read(cx);
 4673        let snapshot = buffer.snapshot(cx);
 4674
 4675        let mut edits = Vec::new();
 4676        let mut rows = Vec::new();
 4677
 4678        for (rows_inserted, selection) in self.selections.all_adjusted(cx).into_iter().enumerate() {
 4679            let cursor = selection.head();
 4680            let row = cursor.row;
 4681
 4682            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4683
 4684            let newline = "\n".to_string();
 4685            edits.push((start_of_line..start_of_line, newline));
 4686
 4687            rows.push(row + rows_inserted as u32);
 4688        }
 4689
 4690        self.transact(window, cx, |editor, window, cx| {
 4691            editor.edit(edits, cx);
 4692
 4693            editor.change_selections(Default::default(), window, cx, |s| {
 4694                let mut index = 0;
 4695                s.move_cursors_with(|map, _, _| {
 4696                    let row = rows[index];
 4697                    index += 1;
 4698
 4699                    let point = Point::new(row, 0);
 4700                    let boundary = map.next_line_boundary(point).1;
 4701                    let clipped = map.clip_point(boundary, Bias::Left);
 4702
 4703                    (clipped, SelectionGoal::None)
 4704                });
 4705            });
 4706
 4707            let mut indent_edits = Vec::new();
 4708            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4709            for row in rows {
 4710                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4711                for (row, indent) in indents {
 4712                    if indent.len == 0 {
 4713                        continue;
 4714                    }
 4715
 4716                    let text = match indent.kind {
 4717                        IndentKind::Space => " ".repeat(indent.len as usize),
 4718                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4719                    };
 4720                    let point = Point::new(row.0, 0);
 4721                    indent_edits.push((point..point, text));
 4722                }
 4723            }
 4724            editor.edit(indent_edits, cx);
 4725        });
 4726    }
 4727
 4728    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4729        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4730
 4731        let buffer = self.buffer.read(cx);
 4732        let snapshot = buffer.snapshot(cx);
 4733
 4734        let mut edits = Vec::new();
 4735        let mut rows = Vec::new();
 4736        let mut rows_inserted = 0;
 4737
 4738        for selection in self.selections.all_adjusted(cx) {
 4739            let cursor = selection.head();
 4740            let row = cursor.row;
 4741
 4742            let point = Point::new(row + 1, 0);
 4743            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4744
 4745            let newline = "\n".to_string();
 4746            edits.push((start_of_line..start_of_line, newline));
 4747
 4748            rows_inserted += 1;
 4749            rows.push(row + rows_inserted);
 4750        }
 4751
 4752        self.transact(window, cx, |editor, window, cx| {
 4753            editor.edit(edits, cx);
 4754
 4755            editor.change_selections(Default::default(), window, cx, |s| {
 4756                let mut index = 0;
 4757                s.move_cursors_with(|map, _, _| {
 4758                    let row = rows[index];
 4759                    index += 1;
 4760
 4761                    let point = Point::new(row, 0);
 4762                    let boundary = map.next_line_boundary(point).1;
 4763                    let clipped = map.clip_point(boundary, Bias::Left);
 4764
 4765                    (clipped, SelectionGoal::None)
 4766                });
 4767            });
 4768
 4769            let mut indent_edits = Vec::new();
 4770            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4771            for row in rows {
 4772                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4773                for (row, indent) in indents {
 4774                    if indent.len == 0 {
 4775                        continue;
 4776                    }
 4777
 4778                    let text = match indent.kind {
 4779                        IndentKind::Space => " ".repeat(indent.len as usize),
 4780                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4781                    };
 4782                    let point = Point::new(row.0, 0);
 4783                    indent_edits.push((point..point, text));
 4784                }
 4785            }
 4786            editor.edit(indent_edits, cx);
 4787        });
 4788    }
 4789
 4790    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4791        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4792            original_indent_columns: Vec::new(),
 4793        });
 4794        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4795    }
 4796
 4797    fn insert_with_autoindent_mode(
 4798        &mut self,
 4799        text: &str,
 4800        autoindent_mode: Option<AutoindentMode>,
 4801        window: &mut Window,
 4802        cx: &mut Context<Self>,
 4803    ) {
 4804        if self.read_only(cx) {
 4805            return;
 4806        }
 4807
 4808        let text: Arc<str> = text.into();
 4809        self.transact(window, cx, |this, window, cx| {
 4810            let old_selections = this.selections.all_adjusted(cx);
 4811            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4812                let anchors = {
 4813                    let snapshot = buffer.read(cx);
 4814                    old_selections
 4815                        .iter()
 4816                        .map(|s| {
 4817                            let anchor = snapshot.anchor_after(s.head());
 4818                            s.map(|_| anchor)
 4819                        })
 4820                        .collect::<Vec<_>>()
 4821                };
 4822                buffer.edit(
 4823                    old_selections
 4824                        .iter()
 4825                        .map(|s| (s.start..s.end, text.clone())),
 4826                    autoindent_mode,
 4827                    cx,
 4828                );
 4829                anchors
 4830            });
 4831
 4832            this.change_selections(Default::default(), window, cx, |s| {
 4833                s.select_anchors(selection_anchors);
 4834            });
 4835
 4836            cx.notify();
 4837        });
 4838    }
 4839
 4840    fn trigger_completion_on_input(
 4841        &mut self,
 4842        text: &str,
 4843        trigger_in_words: bool,
 4844        window: &mut Window,
 4845        cx: &mut Context<Self>,
 4846    ) {
 4847        let completions_source = self
 4848            .context_menu
 4849            .borrow()
 4850            .as_ref()
 4851            .and_then(|menu| match menu {
 4852                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4853                CodeContextMenu::CodeActions(_) => None,
 4854            });
 4855
 4856        match completions_source {
 4857            Some(CompletionsMenuSource::Words) => {
 4858                self.show_word_completions(&ShowWordCompletions, window, cx)
 4859            }
 4860            Some(CompletionsMenuSource::Normal)
 4861            | Some(CompletionsMenuSource::SnippetChoices)
 4862            | None
 4863                if self.is_completion_trigger(
 4864                    text,
 4865                    trigger_in_words,
 4866                    completions_source.is_some(),
 4867                    cx,
 4868                ) =>
 4869            {
 4870                self.show_completions(
 4871                    &ShowCompletions {
 4872                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4873                    },
 4874                    window,
 4875                    cx,
 4876                )
 4877            }
 4878            _ => {
 4879                self.hide_context_menu(window, cx);
 4880            }
 4881        }
 4882    }
 4883
 4884    fn is_completion_trigger(
 4885        &self,
 4886        text: &str,
 4887        trigger_in_words: bool,
 4888        menu_is_open: bool,
 4889        cx: &mut Context<Self>,
 4890    ) -> bool {
 4891        let position = self.selections.newest_anchor().head();
 4892        let multibuffer = self.buffer.read(cx);
 4893        let Some(buffer) = position
 4894            .buffer_id
 4895            .and_then(|buffer_id| multibuffer.buffer(buffer_id).clone())
 4896        else {
 4897            return false;
 4898        };
 4899
 4900        if let Some(completion_provider) = &self.completion_provider {
 4901            completion_provider.is_completion_trigger(
 4902                &buffer,
 4903                position.text_anchor,
 4904                text,
 4905                trigger_in_words,
 4906                menu_is_open,
 4907                cx,
 4908            )
 4909        } else {
 4910            false
 4911        }
 4912    }
 4913
 4914    /// If any empty selections is touching the start of its innermost containing autoclose
 4915    /// region, expand it to select the brackets.
 4916    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4917        let selections = self.selections.all::<usize>(cx);
 4918        let buffer = self.buffer.read(cx).read(cx);
 4919        let new_selections = self
 4920            .selections_with_autoclose_regions(selections, &buffer)
 4921            .map(|(mut selection, region)| {
 4922                if !selection.is_empty() {
 4923                    return selection;
 4924                }
 4925
 4926                if let Some(region) = region {
 4927                    let mut range = region.range.to_offset(&buffer);
 4928                    if selection.start == range.start && range.start >= region.pair.start.len() {
 4929                        range.start -= region.pair.start.len();
 4930                        if buffer.contains_str_at(range.start, &region.pair.start)
 4931                            && buffer.contains_str_at(range.end, &region.pair.end)
 4932                        {
 4933                            range.end += region.pair.end.len();
 4934                            selection.start = range.start;
 4935                            selection.end = range.end;
 4936
 4937                            return selection;
 4938                        }
 4939                    }
 4940                }
 4941
 4942                let always_treat_brackets_as_autoclosed = buffer
 4943                    .language_settings_at(selection.start, cx)
 4944                    .always_treat_brackets_as_autoclosed;
 4945
 4946                if !always_treat_brackets_as_autoclosed {
 4947                    return selection;
 4948                }
 4949
 4950                if let Some(scope) = buffer.language_scope_at(selection.start) {
 4951                    for (pair, enabled) in scope.brackets() {
 4952                        if !enabled || !pair.close {
 4953                            continue;
 4954                        }
 4955
 4956                        if buffer.contains_str_at(selection.start, &pair.end) {
 4957                            let pair_start_len = pair.start.len();
 4958                            if buffer.contains_str_at(
 4959                                selection.start.saturating_sub(pair_start_len),
 4960                                &pair.start,
 4961                            ) {
 4962                                selection.start -= pair_start_len;
 4963                                selection.end += pair.end.len();
 4964
 4965                                return selection;
 4966                            }
 4967                        }
 4968                    }
 4969                }
 4970
 4971                selection
 4972            })
 4973            .collect();
 4974
 4975        drop(buffer);
 4976        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 4977            selections.select(new_selections)
 4978        });
 4979    }
 4980
 4981    /// Iterate the given selections, and for each one, find the smallest surrounding
 4982    /// autoclose region. This uses the ordering of the selections and the autoclose
 4983    /// regions to avoid repeated comparisons.
 4984    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 4985        &'a self,
 4986        selections: impl IntoIterator<Item = Selection<D>>,
 4987        buffer: &'a MultiBufferSnapshot,
 4988    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 4989        let mut i = 0;
 4990        let mut regions = self.autoclose_regions.as_slice();
 4991        selections.into_iter().map(move |selection| {
 4992            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 4993
 4994            let mut enclosing = None;
 4995            while let Some(pair_state) = regions.get(i) {
 4996                if pair_state.range.end.to_offset(buffer) < range.start {
 4997                    regions = &regions[i + 1..];
 4998                    i = 0;
 4999                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5000                    break;
 5001                } else {
 5002                    if pair_state.selection_id == selection.id {
 5003                        enclosing = Some(pair_state);
 5004                    }
 5005                    i += 1;
 5006                }
 5007            }
 5008
 5009            (selection, enclosing)
 5010        })
 5011    }
 5012
 5013    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5014    fn invalidate_autoclose_regions(
 5015        &mut self,
 5016        mut selections: &[Selection<Anchor>],
 5017        buffer: &MultiBufferSnapshot,
 5018    ) {
 5019        self.autoclose_regions.retain(|state| {
 5020            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5021                return false;
 5022            }
 5023
 5024            let mut i = 0;
 5025            while let Some(selection) = selections.get(i) {
 5026                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5027                    selections = &selections[1..];
 5028                    continue;
 5029                }
 5030                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5031                    break;
 5032                }
 5033                if selection.id == state.selection_id {
 5034                    return true;
 5035                } else {
 5036                    i += 1;
 5037                }
 5038            }
 5039            false
 5040        });
 5041    }
 5042
 5043    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5044        let offset = position.to_offset(buffer);
 5045        let (word_range, kind) = buffer.surrounding_word(offset, true);
 5046        if offset > word_range.start && kind == Some(CharKind::Word) {
 5047            Some(
 5048                buffer
 5049                    .text_for_range(word_range.start..offset)
 5050                    .collect::<String>(),
 5051            )
 5052        } else {
 5053            None
 5054        }
 5055    }
 5056
 5057    pub fn toggle_inline_values(
 5058        &mut self,
 5059        _: &ToggleInlineValues,
 5060        _: &mut Window,
 5061        cx: &mut Context<Self>,
 5062    ) {
 5063        self.inline_value_cache.enabled = !self.inline_value_cache.enabled;
 5064
 5065        self.refresh_inline_values(cx);
 5066    }
 5067
 5068    pub fn toggle_inlay_hints(
 5069        &mut self,
 5070        _: &ToggleInlayHints,
 5071        _: &mut Window,
 5072        cx: &mut Context<Self>,
 5073    ) {
 5074        self.refresh_inlay_hints(
 5075            InlayHintRefreshReason::Toggle(!self.inlay_hints_enabled()),
 5076            cx,
 5077        );
 5078    }
 5079
 5080    pub fn inlay_hints_enabled(&self) -> bool {
 5081        self.inlay_hint_cache.enabled
 5082    }
 5083
 5084    pub fn inline_values_enabled(&self) -> bool {
 5085        self.inline_value_cache.enabled
 5086    }
 5087
 5088    #[cfg(any(test, feature = "test-support"))]
 5089    pub fn inline_value_inlays(&self, cx: &App) -> Vec<Inlay> {
 5090        self.display_map
 5091            .read(cx)
 5092            .current_inlays()
 5093            .filter(|inlay| matches!(inlay.id, InlayId::DebuggerValue(_)))
 5094            .cloned()
 5095            .collect()
 5096    }
 5097
 5098    #[cfg(any(test, feature = "test-support"))]
 5099    pub fn all_inlays(&self, cx: &App) -> Vec<Inlay> {
 5100        self.display_map
 5101            .read(cx)
 5102            .current_inlays()
 5103            .cloned()
 5104            .collect()
 5105    }
 5106
 5107    fn refresh_inlay_hints(&mut self, reason: InlayHintRefreshReason, cx: &mut Context<Self>) {
 5108        if self.semantics_provider.is_none() || !self.mode.is_full() {
 5109            return;
 5110        }
 5111
 5112        let reason_description = reason.description();
 5113        let ignore_debounce = matches!(
 5114            reason,
 5115            InlayHintRefreshReason::SettingsChange(_)
 5116                | InlayHintRefreshReason::Toggle(_)
 5117                | InlayHintRefreshReason::ExcerptsRemoved(_)
 5118                | InlayHintRefreshReason::ModifiersChanged(_)
 5119        );
 5120        let (invalidate_cache, required_languages) = match reason {
 5121            InlayHintRefreshReason::ModifiersChanged(enabled) => {
 5122                match self.inlay_hint_cache.modifiers_override(enabled) {
 5123                    Some(enabled) => {
 5124                        if enabled {
 5125                            (InvalidationStrategy::RefreshRequested, None)
 5126                        } else {
 5127                            self.splice_inlays(
 5128                                &self
 5129                                    .visible_inlay_hints(cx)
 5130                                    .iter()
 5131                                    .map(|inlay| inlay.id)
 5132                                    .collect::<Vec<InlayId>>(),
 5133                                Vec::new(),
 5134                                cx,
 5135                            );
 5136                            return;
 5137                        }
 5138                    }
 5139                    None => return,
 5140                }
 5141            }
 5142            InlayHintRefreshReason::Toggle(enabled) => {
 5143                if self.inlay_hint_cache.toggle(enabled) {
 5144                    if enabled {
 5145                        (InvalidationStrategy::RefreshRequested, None)
 5146                    } else {
 5147                        self.splice_inlays(
 5148                            &self
 5149                                .visible_inlay_hints(cx)
 5150                                .iter()
 5151                                .map(|inlay| inlay.id)
 5152                                .collect::<Vec<InlayId>>(),
 5153                            Vec::new(),
 5154                            cx,
 5155                        );
 5156                        return;
 5157                    }
 5158                } else {
 5159                    return;
 5160                }
 5161            }
 5162            InlayHintRefreshReason::SettingsChange(new_settings) => {
 5163                match self.inlay_hint_cache.update_settings(
 5164                    &self.buffer,
 5165                    new_settings,
 5166                    self.visible_inlay_hints(cx),
 5167                    cx,
 5168                ) {
 5169                    ControlFlow::Break(Some(InlaySplice {
 5170                        to_remove,
 5171                        to_insert,
 5172                    })) => {
 5173                        self.splice_inlays(&to_remove, to_insert, cx);
 5174                        return;
 5175                    }
 5176                    ControlFlow::Break(None) => return,
 5177                    ControlFlow::Continue(()) => (InvalidationStrategy::RefreshRequested, None),
 5178                }
 5179            }
 5180            InlayHintRefreshReason::ExcerptsRemoved(excerpts_removed) => {
 5181                if let Some(InlaySplice {
 5182                    to_remove,
 5183                    to_insert,
 5184                }) = self.inlay_hint_cache.remove_excerpts(&excerpts_removed)
 5185                {
 5186                    self.splice_inlays(&to_remove, to_insert, cx);
 5187                }
 5188                self.display_map.update(cx, |display_map, _| {
 5189                    display_map.remove_inlays_for_excerpts(&excerpts_removed)
 5190                });
 5191                return;
 5192            }
 5193            InlayHintRefreshReason::NewLinesShown => (InvalidationStrategy::None, None),
 5194            InlayHintRefreshReason::BufferEdited(buffer_languages) => {
 5195                (InvalidationStrategy::BufferEdited, Some(buffer_languages))
 5196            }
 5197            InlayHintRefreshReason::RefreshRequested => {
 5198                (InvalidationStrategy::RefreshRequested, None)
 5199            }
 5200        };
 5201
 5202        if let Some(InlaySplice {
 5203            to_remove,
 5204            to_insert,
 5205        }) = self.inlay_hint_cache.spawn_hint_refresh(
 5206            reason_description,
 5207            self.visible_excerpts(required_languages.as_ref(), cx),
 5208            invalidate_cache,
 5209            ignore_debounce,
 5210            cx,
 5211        ) {
 5212            self.splice_inlays(&to_remove, to_insert, cx);
 5213        }
 5214    }
 5215
 5216    fn visible_inlay_hints(&self, cx: &Context<Editor>) -> Vec<Inlay> {
 5217        self.display_map
 5218            .read(cx)
 5219            .current_inlays()
 5220            .filter(move |inlay| matches!(inlay.id, InlayId::Hint(_)))
 5221            .cloned()
 5222            .collect()
 5223    }
 5224
 5225    pub fn visible_excerpts(
 5226        &self,
 5227        restrict_to_languages: Option<&HashSet<Arc<Language>>>,
 5228        cx: &mut Context<Editor>,
 5229    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5230        let Some(project) = self.project() else {
 5231            return HashMap::default();
 5232        };
 5233        let project = project.read(cx);
 5234        let multi_buffer = self.buffer().read(cx);
 5235        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5236        let multi_buffer_visible_start = self
 5237            .scroll_manager
 5238            .anchor()
 5239            .anchor
 5240            .to_point(&multi_buffer_snapshot);
 5241        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5242            multi_buffer_visible_start
 5243                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5244            Bias::Left,
 5245        );
 5246        let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 5247        multi_buffer_snapshot
 5248            .range_to_buffer_ranges(multi_buffer_visible_range)
 5249            .into_iter()
 5250            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5251            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5252                let buffer_file = project::File::from_dyn(buffer.file())?;
 5253                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5254                let worktree_entry = buffer_worktree
 5255                    .read(cx)
 5256                    .entry_for_id(buffer_file.project_entry_id(cx)?)?;
 5257                if worktree_entry.is_ignored {
 5258                    return None;
 5259                }
 5260
 5261                let language = buffer.language()?;
 5262                if let Some(restrict_to_languages) = restrict_to_languages
 5263                    && !restrict_to_languages.contains(language)
 5264                {
 5265                    return None;
 5266                }
 5267                Some((
 5268                    excerpt_id,
 5269                    (
 5270                        multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5271                        buffer.version().clone(),
 5272                        excerpt_visible_range,
 5273                    ),
 5274                ))
 5275            })
 5276            .collect()
 5277    }
 5278
 5279    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5280        TextLayoutDetails {
 5281            text_system: window.text_system().clone(),
 5282            editor_style: self.style.clone().unwrap(),
 5283            rem_size: window.rem_size(),
 5284            scroll_anchor: self.scroll_manager.anchor(),
 5285            visible_rows: self.visible_line_count(),
 5286            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5287        }
 5288    }
 5289
 5290    pub fn splice_inlays(
 5291        &self,
 5292        to_remove: &[InlayId],
 5293        to_insert: Vec<Inlay>,
 5294        cx: &mut Context<Self>,
 5295    ) {
 5296        self.display_map.update(cx, |display_map, cx| {
 5297            display_map.splice_inlays(to_remove, to_insert, cx)
 5298        });
 5299        cx.notify();
 5300    }
 5301
 5302    fn trigger_on_type_formatting(
 5303        &self,
 5304        input: String,
 5305        window: &mut Window,
 5306        cx: &mut Context<Self>,
 5307    ) -> Option<Task<Result<()>>> {
 5308        if input.len() != 1 {
 5309            return None;
 5310        }
 5311
 5312        let project = self.project()?;
 5313        let position = self.selections.newest_anchor().head();
 5314        let (buffer, buffer_position) = self
 5315            .buffer
 5316            .read(cx)
 5317            .text_anchor_for_position(position, cx)?;
 5318
 5319        let settings = language_settings::language_settings(
 5320            buffer
 5321                .read(cx)
 5322                .language_at(buffer_position)
 5323                .map(|l| l.name()),
 5324            buffer.read(cx).file(),
 5325            cx,
 5326        );
 5327        if !settings.use_on_type_format {
 5328            return None;
 5329        }
 5330
 5331        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5332        // hence we do LSP request & edit on host side only — add formats to host's history.
 5333        let push_to_lsp_host_history = true;
 5334        // If this is not the host, append its history with new edits.
 5335        let push_to_client_history = project.read(cx).is_via_collab();
 5336
 5337        let on_type_formatting = project.update(cx, |project, cx| {
 5338            project.on_type_format(
 5339                buffer.clone(),
 5340                buffer_position,
 5341                input,
 5342                push_to_lsp_host_history,
 5343                cx,
 5344            )
 5345        });
 5346        Some(cx.spawn_in(window, async move |editor, cx| {
 5347            if let Some(transaction) = on_type_formatting.await? {
 5348                if push_to_client_history {
 5349                    buffer
 5350                        .update(cx, |buffer, _| {
 5351                            buffer.push_transaction(transaction, Instant::now());
 5352                            buffer.finalize_last_transaction();
 5353                        })
 5354                        .ok();
 5355                }
 5356                editor.update(cx, |editor, cx| {
 5357                    editor.refresh_document_highlights(cx);
 5358                })?;
 5359            }
 5360            Ok(())
 5361        }))
 5362    }
 5363
 5364    pub fn show_word_completions(
 5365        &mut self,
 5366        _: &ShowWordCompletions,
 5367        window: &mut Window,
 5368        cx: &mut Context<Self>,
 5369    ) {
 5370        self.open_or_update_completions_menu(Some(CompletionsMenuSource::Words), None, window, cx);
 5371    }
 5372
 5373    pub fn show_completions(
 5374        &mut self,
 5375        options: &ShowCompletions,
 5376        window: &mut Window,
 5377        cx: &mut Context<Self>,
 5378    ) {
 5379        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5380    }
 5381
 5382    fn open_or_update_completions_menu(
 5383        &mut self,
 5384        requested_source: Option<CompletionsMenuSource>,
 5385        trigger: Option<&str>,
 5386        window: &mut Window,
 5387        cx: &mut Context<Self>,
 5388    ) {
 5389        if self.pending_rename.is_some() {
 5390            return;
 5391        }
 5392
 5393        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5394
 5395        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5396        // inserted and selected. To handle that case, the start of the selection is used so that
 5397        // the menu starts with all choices.
 5398        let position = self
 5399            .selections
 5400            .newest_anchor()
 5401            .start
 5402            .bias_right(&multibuffer_snapshot);
 5403        if position.diff_base_anchor.is_some() {
 5404            return;
 5405        }
 5406        let (buffer, buffer_position) =
 5407            if let Some(output) = self.buffer.read(cx).text_anchor_for_position(position, cx) {
 5408                output
 5409            } else {
 5410                return;
 5411            };
 5412        let buffer_snapshot = buffer.read(cx).snapshot();
 5413
 5414        let query: Option<Arc<String>> =
 5415            Self::completion_query(&multibuffer_snapshot, position).map(|query| query.into());
 5416
 5417        drop(multibuffer_snapshot);
 5418
 5419        let provider = match requested_source {
 5420            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5421            Some(CompletionsMenuSource::Words) => None,
 5422            Some(CompletionsMenuSource::SnippetChoices) => {
 5423                log::error!("bug: SnippetChoices requested_source is not handled");
 5424                None
 5425            }
 5426        };
 5427
 5428        let sort_completions = provider
 5429            .as_ref()
 5430            .map_or(false, |provider| provider.sort_completions());
 5431
 5432        let filter_completions = provider
 5433            .as_ref()
 5434            .map_or(true, |provider| provider.filter_completions());
 5435
 5436        let trigger_kind = match trigger {
 5437            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5438                CompletionTriggerKind::TRIGGER_CHARACTER
 5439            }
 5440            _ => CompletionTriggerKind::INVOKED,
 5441        };
 5442        let completion_context = CompletionContext {
 5443            trigger_character: trigger.and_then(|trigger| {
 5444                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5445                    Some(String::from(trigger))
 5446                } else {
 5447                    None
 5448                }
 5449            }),
 5450            trigger_kind,
 5451        };
 5452
 5453        // Hide the current completions menu when a trigger char is typed. Without this, cached
 5454        // completions from before the trigger char may be reused (#32774). Snippet choices could
 5455        // involve trigger chars, so this is skipped in that case.
 5456        if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
 5457        {
 5458            let menu_is_open = matches!(
 5459                self.context_menu.borrow().as_ref(),
 5460                Some(CodeContextMenu::Completions(_))
 5461            );
 5462            if menu_is_open {
 5463                self.hide_context_menu(window, cx);
 5464            }
 5465        }
 5466
 5467        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5468            if filter_completions {
 5469                menu.filter(query.clone(), provider.clone(), window, cx);
 5470            }
 5471            // When `is_incomplete` is false, no need to re-query completions when the current query
 5472            // is a suffix of the initial query.
 5473            if !menu.is_incomplete {
 5474                // If the new query is a suffix of the old query (typing more characters) and
 5475                // the previous result was complete, the existing completions can be filtered.
 5476                //
 5477                // Note that this is always true for snippet completions.
 5478                let query_matches = match (&menu.initial_query, &query) {
 5479                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5480                    (None, _) => true,
 5481                    _ => false,
 5482                };
 5483                if query_matches {
 5484                    let position_matches = if menu.initial_position == position {
 5485                        true
 5486                    } else {
 5487                        let snapshot = self.buffer.read(cx).read(cx);
 5488                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5489                    };
 5490                    if position_matches {
 5491                        return;
 5492                    }
 5493                }
 5494            }
 5495        };
 5496
 5497        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5498            buffer_snapshot.surrounding_word(buffer_position, false)
 5499        {
 5500            let word_to_exclude = buffer_snapshot
 5501                .text_for_range(word_range.clone())
 5502                .collect::<String>();
 5503            (
 5504                buffer_snapshot.anchor_before(word_range.start)
 5505                    ..buffer_snapshot.anchor_after(buffer_position),
 5506                Some(word_to_exclude),
 5507            )
 5508        } else {
 5509            (buffer_position..buffer_position, None)
 5510        };
 5511
 5512        let language = buffer_snapshot
 5513            .language_at(buffer_position)
 5514            .map(|language| language.name());
 5515
 5516        let completion_settings =
 5517            language_settings(language.clone(), buffer_snapshot.file(), cx).completions;
 5518
 5519        let show_completion_documentation = buffer_snapshot
 5520            .settings_at(buffer_position, cx)
 5521            .show_completion_documentation;
 5522
 5523        // The document can be large, so stay in reasonable bounds when searching for words,
 5524        // otherwise completion pop-up might be slow to appear.
 5525        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5526        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5527        let min_word_search = buffer_snapshot.clip_point(
 5528            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5529            Bias::Left,
 5530        );
 5531        let max_word_search = buffer_snapshot.clip_point(
 5532            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5533            Bias::Right,
 5534        );
 5535        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5536            ..buffer_snapshot.point_to_offset(max_word_search);
 5537
 5538        let skip_digits = query
 5539            .as_ref()
 5540            .map_or(true, |query| !query.chars().any(|c| c.is_digit(10)));
 5541
 5542        let (mut words, provider_responses) = match &provider {
 5543            Some(provider) => {
 5544                let provider_responses = provider.completions(
 5545                    position.excerpt_id,
 5546                    &buffer,
 5547                    buffer_position,
 5548                    completion_context,
 5549                    window,
 5550                    cx,
 5551                );
 5552
 5553                let words = match completion_settings.words {
 5554                    WordsCompletionMode::Disabled => Task::ready(BTreeMap::default()),
 5555                    WordsCompletionMode::Enabled | WordsCompletionMode::Fallback => cx
 5556                        .background_spawn(async move {
 5557                            buffer_snapshot.words_in_range(WordsQuery {
 5558                                fuzzy_contents: None,
 5559                                range: word_search_range,
 5560                                skip_digits,
 5561                            })
 5562                        }),
 5563                };
 5564
 5565                (words, provider_responses)
 5566            }
 5567            None => (
 5568                cx.background_spawn(async move {
 5569                    buffer_snapshot.words_in_range(WordsQuery {
 5570                        fuzzy_contents: None,
 5571                        range: word_search_range,
 5572                        skip_digits,
 5573                    })
 5574                }),
 5575                Task::ready(Ok(Vec::new())),
 5576            ),
 5577        };
 5578
 5579        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5580
 5581        let id = post_inc(&mut self.next_completion_id);
 5582        let task = cx.spawn_in(window, async move |editor, cx| {
 5583            let Ok(()) = editor.update(cx, |this, _| {
 5584                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5585            }) else {
 5586                return;
 5587            };
 5588
 5589            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5590            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5591            let mut completions = Vec::new();
 5592            let mut is_incomplete = false;
 5593            if let Some(provider_responses) = provider_responses.await.log_err()
 5594                && !provider_responses.is_empty()
 5595            {
 5596                for response in provider_responses {
 5597                    completions.extend(response.completions);
 5598                    is_incomplete = is_incomplete || response.is_incomplete;
 5599                }
 5600                if completion_settings.words == WordsCompletionMode::Fallback {
 5601                    words = Task::ready(BTreeMap::default());
 5602                }
 5603            }
 5604
 5605            let mut words = words.await;
 5606            if let Some(word_to_exclude) = &word_to_exclude {
 5607                words.remove(word_to_exclude);
 5608            }
 5609            for lsp_completion in &completions {
 5610                words.remove(&lsp_completion.new_text);
 5611            }
 5612            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5613                replace_range: word_replace_range.clone(),
 5614                new_text: word.clone(),
 5615                label: CodeLabel::plain(word, None),
 5616                icon_path: None,
 5617                documentation: None,
 5618                source: CompletionSource::BufferWord {
 5619                    word_range,
 5620                    resolved: false,
 5621                },
 5622                insert_text_mode: Some(InsertTextMode::AS_IS),
 5623                confirm: None,
 5624            }));
 5625
 5626            let menu = if completions.is_empty() {
 5627                None
 5628            } else {
 5629                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5630                    let languages = editor
 5631                        .workspace
 5632                        .as_ref()
 5633                        .and_then(|(workspace, _)| workspace.upgrade())
 5634                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5635                    let menu = CompletionsMenu::new(
 5636                        id,
 5637                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5638                        sort_completions,
 5639                        show_completion_documentation,
 5640                        position,
 5641                        query.clone(),
 5642                        is_incomplete,
 5643                        buffer.clone(),
 5644                        completions.into(),
 5645                        snippet_sort_order,
 5646                        languages,
 5647                        language,
 5648                        cx,
 5649                    );
 5650
 5651                    let query = if filter_completions { query } else { None };
 5652                    let matches_task = if let Some(query) = query {
 5653                        menu.do_async_filtering(query, cx)
 5654                    } else {
 5655                        Task::ready(menu.unfiltered_matches())
 5656                    };
 5657                    (menu, matches_task)
 5658                }) else {
 5659                    return;
 5660                };
 5661
 5662                let matches = matches_task.await;
 5663
 5664                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5665                    // Newer menu already set, so exit.
 5666                    match editor.context_menu.borrow().as_ref() {
 5667                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5668                            if prev_menu.id > id {
 5669                                return;
 5670                            }
 5671                        }
 5672                        _ => {}
 5673                    };
 5674
 5675                    // Only valid to take prev_menu because it the new menu is immediately set
 5676                    // below, or the menu is hidden.
 5677                    match editor.context_menu.borrow_mut().take() {
 5678                        Some(CodeContextMenu::Completions(prev_menu)) => {
 5679                            let position_matches =
 5680                                if prev_menu.initial_position == menu.initial_position {
 5681                                    true
 5682                                } else {
 5683                                    let snapshot = editor.buffer.read(cx).read(cx);
 5684                                    prev_menu.initial_position.to_offset(&snapshot)
 5685                                        == menu.initial_position.to_offset(&snapshot)
 5686                                };
 5687                            if position_matches {
 5688                                // Preserve markdown cache before `set_filter_results` because it will
 5689                                // try to populate the documentation cache.
 5690                                menu.preserve_markdown_cache(prev_menu);
 5691                            }
 5692                        }
 5693                        _ => {}
 5694                    };
 5695
 5696                    menu.set_filter_results(matches, provider, window, cx);
 5697                }) else {
 5698                    return;
 5699                };
 5700
 5701                menu.visible().then_some(menu)
 5702            };
 5703
 5704            editor
 5705                .update_in(cx, |editor, window, cx| {
 5706                    if editor.focus_handle.is_focused(window)
 5707                        && let Some(menu) = menu
 5708                    {
 5709                        *editor.context_menu.borrow_mut() =
 5710                            Some(CodeContextMenu::Completions(menu));
 5711
 5712                        crate::hover_popover::hide_hover(editor, cx);
 5713                        if editor.show_edit_predictions_in_menu() {
 5714                            editor.update_visible_edit_prediction(window, cx);
 5715                        } else {
 5716                            editor.discard_edit_prediction(false, cx);
 5717                        }
 5718
 5719                        cx.notify();
 5720                        return;
 5721                    }
 5722
 5723                    if editor.completion_tasks.len() <= 1 {
 5724                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5725                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5726                        // If it was already hidden and we don't show edit predictions in the menu,
 5727                        // we should also show the edit prediction when available.
 5728                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5729                            editor.update_visible_edit_prediction(window, cx);
 5730                        }
 5731                    }
 5732                })
 5733                .ok();
 5734        });
 5735
 5736        self.completion_tasks.push((id, task));
 5737    }
 5738
 5739    #[cfg(feature = "test-support")]
 5740    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5741        let menu = self.context_menu.borrow();
 5742        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5743            let completions = menu.completions.borrow();
 5744            Some(completions.to_vec())
 5745        } else {
 5746            None
 5747        }
 5748    }
 5749
 5750    pub fn with_completions_menu_matching_id<R>(
 5751        &self,
 5752        id: CompletionId,
 5753        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5754    ) -> R {
 5755        let mut context_menu = self.context_menu.borrow_mut();
 5756        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5757            return f(None);
 5758        };
 5759        if completions_menu.id != id {
 5760            return f(None);
 5761        }
 5762        f(Some(completions_menu))
 5763    }
 5764
 5765    pub fn confirm_completion(
 5766        &mut self,
 5767        action: &ConfirmCompletion,
 5768        window: &mut Window,
 5769        cx: &mut Context<Self>,
 5770    ) -> Option<Task<Result<()>>> {
 5771        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5772        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5773    }
 5774
 5775    pub fn confirm_completion_insert(
 5776        &mut self,
 5777        _: &ConfirmCompletionInsert,
 5778        window: &mut Window,
 5779        cx: &mut Context<Self>,
 5780    ) -> Option<Task<Result<()>>> {
 5781        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5782        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5783    }
 5784
 5785    pub fn confirm_completion_replace(
 5786        &mut self,
 5787        _: &ConfirmCompletionReplace,
 5788        window: &mut Window,
 5789        cx: &mut Context<Self>,
 5790    ) -> Option<Task<Result<()>>> {
 5791        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5792        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5793    }
 5794
 5795    pub fn compose_completion(
 5796        &mut self,
 5797        action: &ComposeCompletion,
 5798        window: &mut Window,
 5799        cx: &mut Context<Self>,
 5800    ) -> Option<Task<Result<()>>> {
 5801        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5802        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5803    }
 5804
 5805    fn do_completion(
 5806        &mut self,
 5807        item_ix: Option<usize>,
 5808        intent: CompletionIntent,
 5809        window: &mut Window,
 5810        cx: &mut Context<Editor>,
 5811    ) -> Option<Task<Result<()>>> {
 5812        use language::ToOffset as _;
 5813
 5814        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5815        else {
 5816            return None;
 5817        };
 5818
 5819        let candidate_id = {
 5820            let entries = completions_menu.entries.borrow();
 5821            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5822            if self.show_edit_predictions_in_menu() {
 5823                self.discard_edit_prediction(true, cx);
 5824            }
 5825            mat.candidate_id
 5826        };
 5827
 5828        let completion = completions_menu
 5829            .completions
 5830            .borrow()
 5831            .get(candidate_id)?
 5832            .clone();
 5833        cx.stop_propagation();
 5834
 5835        let buffer_handle = completions_menu.buffer.clone();
 5836
 5837        let CompletionEdit {
 5838            new_text,
 5839            snippet,
 5840            replace_range,
 5841        } = process_completion_for_edit(
 5842            &completion,
 5843            intent,
 5844            &buffer_handle,
 5845            &completions_menu.initial_position.text_anchor,
 5846            cx,
 5847        );
 5848
 5849        let buffer = buffer_handle.read(cx);
 5850        let snapshot = self.buffer.read(cx).snapshot(cx);
 5851        let newest_anchor = self.selections.newest_anchor();
 5852        let replace_range_multibuffer = {
 5853            let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5854            let multibuffer_anchor = snapshot
 5855                .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
 5856                .unwrap()
 5857                ..snapshot
 5858                    .anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
 5859                    .unwrap();
 5860            multibuffer_anchor.start.to_offset(&snapshot)
 5861                ..multibuffer_anchor.end.to_offset(&snapshot)
 5862        };
 5863        if newest_anchor.head().buffer_id != Some(buffer.remote_id()) {
 5864            return None;
 5865        }
 5866
 5867        let old_text = buffer
 5868            .text_for_range(replace_range.clone())
 5869            .collect::<String>();
 5870        let lookbehind = newest_anchor
 5871            .start
 5872            .text_anchor
 5873            .to_offset(buffer)
 5874            .saturating_sub(replace_range.start);
 5875        let lookahead = replace_range
 5876            .end
 5877            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5878        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5879        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5880
 5881        let selections = self.selections.all::<usize>(cx);
 5882        let mut ranges = Vec::new();
 5883        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5884
 5885        for selection in &selections {
 5886            let range = if selection.id == newest_anchor.id {
 5887                replace_range_multibuffer.clone()
 5888            } else {
 5889                let mut range = selection.range();
 5890
 5891                // if prefix is present, don't duplicate it
 5892                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5893                    range.start = range.start.saturating_sub(lookbehind);
 5894
 5895                    // if suffix is also present, mimic the newest cursor and replace it
 5896                    if selection.id != newest_anchor.id
 5897                        && snapshot.contains_str_at(range.end, suffix)
 5898                    {
 5899                        range.end += lookahead;
 5900                    }
 5901                }
 5902                range
 5903            };
 5904
 5905            ranges.push(range.clone());
 5906
 5907            if !self.linked_edit_ranges.is_empty() {
 5908                let start_anchor = snapshot.anchor_before(range.start);
 5909                let end_anchor = snapshot.anchor_after(range.end);
 5910                if let Some(ranges) = self
 5911                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5912                {
 5913                    for (buffer, edits) in ranges {
 5914                        linked_edits
 5915                            .entry(buffer.clone())
 5916                            .or_default()
 5917                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5918                    }
 5919                }
 5920            }
 5921        }
 5922
 5923        let common_prefix_len = old_text
 5924            .chars()
 5925            .zip(new_text.chars())
 5926            .take_while(|(a, b)| a == b)
 5927            .map(|(a, _)| a.len_utf8())
 5928            .sum::<usize>();
 5929
 5930        cx.emit(EditorEvent::InputHandled {
 5931            utf16_range_to_replace: None,
 5932            text: new_text[common_prefix_len..].into(),
 5933        });
 5934
 5935        self.transact(window, cx, |editor, window, cx| {
 5936            if let Some(mut snippet) = snippet {
 5937                snippet.text = new_text.to_string();
 5938                editor
 5939                    .insert_snippet(&ranges, snippet, window, cx)
 5940                    .log_err();
 5941            } else {
 5942                editor.buffer.update(cx, |multi_buffer, cx| {
 5943                    let auto_indent = match completion.insert_text_mode {
 5944                        Some(InsertTextMode::AS_IS) => None,
 5945                        _ => editor.autoindent_mode.clone(),
 5946                    };
 5947                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5948                    multi_buffer.edit(edits, auto_indent, cx);
 5949                });
 5950            }
 5951            for (buffer, edits) in linked_edits {
 5952                buffer.update(cx, |buffer, cx| {
 5953                    let snapshot = buffer.snapshot();
 5954                    let edits = edits
 5955                        .into_iter()
 5956                        .map(|(range, text)| {
 5957                            use text::ToPoint as TP;
 5958                            let end_point = TP::to_point(&range.end, &snapshot);
 5959                            let start_point = TP::to_point(&range.start, &snapshot);
 5960                            (start_point..end_point, text)
 5961                        })
 5962                        .sorted_by_key(|(range, _)| range.start);
 5963                    buffer.edit(edits, None, cx);
 5964                })
 5965            }
 5966
 5967            editor.refresh_edit_prediction(true, false, window, cx);
 5968        });
 5969        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors(), &snapshot);
 5970
 5971        let show_new_completions_on_confirm = completion
 5972            .confirm
 5973            .as_ref()
 5974            .map_or(false, |confirm| confirm(intent, window, cx));
 5975        if show_new_completions_on_confirm {
 5976            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5977        }
 5978
 5979        let provider = self.completion_provider.as_ref()?;
 5980        drop(completion);
 5981        let apply_edits = provider.apply_additional_edits_for_completion(
 5982            buffer_handle,
 5983            completions_menu.completions.clone(),
 5984            candidate_id,
 5985            true,
 5986            cx,
 5987        );
 5988
 5989        let editor_settings = EditorSettings::get_global(cx);
 5990        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5991            // After the code completion is finished, users often want to know what signatures are needed.
 5992            // so we should automatically call signature_help
 5993            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5994        }
 5995
 5996        Some(cx.foreground_executor().spawn(async move {
 5997            apply_edits.await?;
 5998            Ok(())
 5999        }))
 6000    }
 6001
 6002    pub fn toggle_code_actions(
 6003        &mut self,
 6004        action: &ToggleCodeActions,
 6005        window: &mut Window,
 6006        cx: &mut Context<Self>,
 6007    ) {
 6008        let quick_launch = action.quick_launch;
 6009        let mut context_menu = self.context_menu.borrow_mut();
 6010        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6011            if code_actions.deployed_from == action.deployed_from {
 6012                // Toggle if we're selecting the same one
 6013                *context_menu = None;
 6014                cx.notify();
 6015                return;
 6016            } else {
 6017                // Otherwise, clear it and start a new one
 6018                *context_menu = None;
 6019                cx.notify();
 6020            }
 6021        }
 6022        drop(context_menu);
 6023        let snapshot = self.snapshot(window, cx);
 6024        let deployed_from = action.deployed_from.clone();
 6025        let action = action.clone();
 6026        self.completion_tasks.clear();
 6027        self.discard_edit_prediction(false, cx);
 6028
 6029        let multibuffer_point = match &action.deployed_from {
 6030            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6031                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6032            }
 6033            _ => self.selections.newest::<Point>(cx).head(),
 6034        };
 6035        let Some((buffer, buffer_row)) = snapshot
 6036            .buffer_snapshot
 6037            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6038            .and_then(|(buffer_snapshot, range)| {
 6039                self.buffer()
 6040                    .read(cx)
 6041                    .buffer(buffer_snapshot.remote_id())
 6042                    .map(|buffer| (buffer, range.start.row))
 6043            })
 6044        else {
 6045            return;
 6046        };
 6047        let buffer_id = buffer.read(cx).remote_id();
 6048        let tasks = self
 6049            .tasks
 6050            .get(&(buffer_id, buffer_row))
 6051            .map(|t| Arc::new(t.to_owned()));
 6052
 6053        if !self.focus_handle.is_focused(window) {
 6054            return;
 6055        }
 6056        let project = self.project.clone();
 6057
 6058        let code_actions_task = match deployed_from {
 6059            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6060            _ => self.code_actions(buffer_row, window, cx),
 6061        };
 6062
 6063        let runnable_task = match deployed_from {
 6064            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6065            _ => {
 6066                let mut task_context_task = Task::ready(None);
 6067                if let Some(tasks) = &tasks
 6068                    && let Some(project) = project
 6069                {
 6070                    task_context_task =
 6071                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6072                }
 6073
 6074                cx.spawn_in(window, {
 6075                    let buffer = buffer.clone();
 6076                    async move |editor, cx| {
 6077                        let task_context = task_context_task.await;
 6078
 6079                        let resolved_tasks =
 6080                            tasks
 6081                                .zip(task_context.clone())
 6082                                .map(|(tasks, task_context)| ResolvedTasks {
 6083                                    templates: tasks.resolve(&task_context).collect(),
 6084                                    position: snapshot.buffer_snapshot.anchor_before(Point::new(
 6085                                        multibuffer_point.row,
 6086                                        tasks.column,
 6087                                    )),
 6088                                });
 6089                        let debug_scenarios = editor
 6090                            .update(cx, |editor, cx| {
 6091                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6092                            })?
 6093                            .await;
 6094                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6095                    }
 6096                })
 6097            }
 6098        };
 6099
 6100        cx.spawn_in(window, async move |editor, cx| {
 6101            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6102            let code_actions = code_actions_task.await;
 6103            let spawn_straight_away = quick_launch
 6104                && resolved_tasks
 6105                    .as_ref()
 6106                    .map_or(false, |tasks| tasks.templates.len() == 1)
 6107                && code_actions
 6108                    .as_ref()
 6109                    .map_or(true, |actions| actions.is_empty())
 6110                && debug_scenarios.is_empty();
 6111
 6112            editor.update_in(cx, |editor, window, cx| {
 6113                crate::hover_popover::hide_hover(editor, cx);
 6114                let actions = CodeActionContents::new(
 6115                    resolved_tasks,
 6116                    code_actions,
 6117                    debug_scenarios,
 6118                    task_context.unwrap_or_default(),
 6119                );
 6120
 6121                // Don't show the menu if there are no actions available
 6122                if actions.is_empty() {
 6123                    cx.notify();
 6124                    return Task::ready(Ok(()));
 6125                }
 6126
 6127                *editor.context_menu.borrow_mut() =
 6128                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6129                        buffer,
 6130                        actions,
 6131                        selected_item: Default::default(),
 6132                        scroll_handle: UniformListScrollHandle::default(),
 6133                        deployed_from,
 6134                    }));
 6135                cx.notify();
 6136                if spawn_straight_away
 6137                    && let Some(task) = editor.confirm_code_action(
 6138                        &ConfirmCodeAction { item_ix: Some(0) },
 6139                        window,
 6140                        cx,
 6141                    )
 6142                {
 6143                    return task;
 6144                }
 6145
 6146                Task::ready(Ok(()))
 6147            })
 6148        })
 6149        .detach_and_log_err(cx);
 6150    }
 6151
 6152    fn debug_scenarios(
 6153        &mut self,
 6154        resolved_tasks: &Option<ResolvedTasks>,
 6155        buffer: &Entity<Buffer>,
 6156        cx: &mut App,
 6157    ) -> Task<Vec<task::DebugScenario>> {
 6158        maybe!({
 6159            let project = self.project()?;
 6160            let dap_store = project.read(cx).dap_store();
 6161            let mut scenarios = vec![];
 6162            let resolved_tasks = resolved_tasks.as_ref()?;
 6163            let buffer = buffer.read(cx);
 6164            let language = buffer.language()?;
 6165            let file = buffer.file();
 6166            let debug_adapter = language_settings(language.name().into(), file, cx)
 6167                .debuggers
 6168                .first()
 6169                .map(SharedString::from)
 6170                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6171
 6172            dap_store.update(cx, |dap_store, cx| {
 6173                for (_, task) in &resolved_tasks.templates {
 6174                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6175                        task.original_task().clone(),
 6176                        debug_adapter.clone().into(),
 6177                        task.display_label().to_owned().into(),
 6178                        cx,
 6179                    );
 6180                    scenarios.push(maybe_scenario);
 6181                }
 6182            });
 6183            Some(cx.background_spawn(async move {
 6184                let scenarios = futures::future::join_all(scenarios)
 6185                    .await
 6186                    .into_iter()
 6187                    .flatten()
 6188                    .collect::<Vec<_>>();
 6189                scenarios
 6190            }))
 6191        })
 6192        .unwrap_or_else(|| Task::ready(vec![]))
 6193    }
 6194
 6195    fn code_actions(
 6196        &mut self,
 6197        buffer_row: u32,
 6198        window: &mut Window,
 6199        cx: &mut Context<Self>,
 6200    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6201        let mut task = self.code_actions_task.take();
 6202        cx.spawn_in(window, async move |editor, cx| {
 6203            while let Some(prev_task) = task {
 6204                prev_task.await.log_err();
 6205                task = editor
 6206                    .update(cx, |this, _| this.code_actions_task.take())
 6207                    .ok()?;
 6208            }
 6209
 6210            editor
 6211                .update(cx, |editor, cx| {
 6212                    editor
 6213                        .available_code_actions
 6214                        .clone()
 6215                        .and_then(|(location, code_actions)| {
 6216                            let snapshot = location.buffer.read(cx).snapshot();
 6217                            let point_range = location.range.to_point(&snapshot);
 6218                            let point_range = point_range.start.row..=point_range.end.row;
 6219                            if point_range.contains(&buffer_row) {
 6220                                Some(code_actions)
 6221                            } else {
 6222                                None
 6223                            }
 6224                        })
 6225                })
 6226                .ok()
 6227                .flatten()
 6228        })
 6229    }
 6230
 6231    pub fn confirm_code_action(
 6232        &mut self,
 6233        action: &ConfirmCodeAction,
 6234        window: &mut Window,
 6235        cx: &mut Context<Self>,
 6236    ) -> Option<Task<Result<()>>> {
 6237        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6238
 6239        let actions_menu =
 6240            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6241                menu
 6242            } else {
 6243                return None;
 6244            };
 6245
 6246        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6247        let action = actions_menu.actions.get(action_ix)?;
 6248        let title = action.label();
 6249        let buffer = actions_menu.buffer;
 6250        let workspace = self.workspace()?;
 6251
 6252        match action {
 6253            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6254                workspace.update(cx, |workspace, cx| {
 6255                    workspace.schedule_resolved_task(
 6256                        task_source_kind,
 6257                        resolved_task,
 6258                        false,
 6259                        window,
 6260                        cx,
 6261                    );
 6262
 6263                    Some(Task::ready(Ok(())))
 6264                })
 6265            }
 6266            CodeActionsItem::CodeAction {
 6267                excerpt_id,
 6268                action,
 6269                provider,
 6270            } => {
 6271                let apply_code_action =
 6272                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6273                let workspace = workspace.downgrade();
 6274                Some(cx.spawn_in(window, async move |editor, cx| {
 6275                    let project_transaction = apply_code_action.await?;
 6276                    Self::open_project_transaction(
 6277                        &editor,
 6278                        workspace,
 6279                        project_transaction,
 6280                        title,
 6281                        cx,
 6282                    )
 6283                    .await
 6284                }))
 6285            }
 6286            CodeActionsItem::DebugScenario(scenario) => {
 6287                let context = actions_menu.actions.context.clone();
 6288
 6289                workspace.update(cx, |workspace, cx| {
 6290                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6291                    workspace.start_debug_session(
 6292                        scenario,
 6293                        context,
 6294                        Some(buffer),
 6295                        None,
 6296                        window,
 6297                        cx,
 6298                    );
 6299                });
 6300                Some(Task::ready(Ok(())))
 6301            }
 6302        }
 6303    }
 6304
 6305    pub async fn open_project_transaction(
 6306        this: &WeakEntity<Editor>,
 6307        workspace: WeakEntity<Workspace>,
 6308        transaction: ProjectTransaction,
 6309        title: String,
 6310        cx: &mut AsyncWindowContext,
 6311    ) -> Result<()> {
 6312        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6313        cx.update(|_, cx| {
 6314            entries.sort_unstable_by_key(|(buffer, _)| {
 6315                buffer.read(cx).file().map(|f| f.path().clone())
 6316            });
 6317        })?;
 6318
 6319        // If the project transaction's edits are all contained within this editor, then
 6320        // avoid opening a new editor to display them.
 6321
 6322        if let Some((buffer, transaction)) = entries.first() {
 6323            if entries.len() == 1 {
 6324                let excerpt = this.update(cx, |editor, cx| {
 6325                    editor
 6326                        .buffer()
 6327                        .read(cx)
 6328                        .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6329                })?;
 6330                if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6331                    && excerpted_buffer == *buffer
 6332                {
 6333                    let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6334                        let excerpt_range = excerpt_range.to_offset(buffer);
 6335                        buffer
 6336                            .edited_ranges_for_transaction::<usize>(transaction)
 6337                            .all(|range| {
 6338                                excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6339                            })
 6340                    })?;
 6341
 6342                    if all_edits_within_excerpt {
 6343                        return Ok(());
 6344                    }
 6345                }
 6346            }
 6347        } else {
 6348            return Ok(());
 6349        }
 6350
 6351        let mut ranges_to_highlight = Vec::new();
 6352        let excerpt_buffer = cx.new(|cx| {
 6353            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6354            for (buffer_handle, transaction) in &entries {
 6355                let edited_ranges = buffer_handle
 6356                    .read(cx)
 6357                    .edited_ranges_for_transaction::<Point>(transaction)
 6358                    .collect::<Vec<_>>();
 6359                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6360                    PathKey::for_buffer(buffer_handle, cx),
 6361                    buffer_handle.clone(),
 6362                    edited_ranges,
 6363                    DEFAULT_MULTIBUFFER_CONTEXT,
 6364                    cx,
 6365                );
 6366
 6367                ranges_to_highlight.extend(ranges);
 6368            }
 6369            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6370            multibuffer
 6371        })?;
 6372
 6373        workspace.update_in(cx, |workspace, window, cx| {
 6374            let project = workspace.project().clone();
 6375            let editor =
 6376                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6377            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6378            editor.update(cx, |editor, cx| {
 6379                editor.highlight_background::<Self>(
 6380                    &ranges_to_highlight,
 6381                    |theme| theme.colors().editor_highlighted_line_background,
 6382                    cx,
 6383                );
 6384            });
 6385        })?;
 6386
 6387        Ok(())
 6388    }
 6389
 6390    pub fn clear_code_action_providers(&mut self) {
 6391        self.code_action_providers.clear();
 6392        self.available_code_actions.take();
 6393    }
 6394
 6395    pub fn add_code_action_provider(
 6396        &mut self,
 6397        provider: Rc<dyn CodeActionProvider>,
 6398        window: &mut Window,
 6399        cx: &mut Context<Self>,
 6400    ) {
 6401        if self
 6402            .code_action_providers
 6403            .iter()
 6404            .any(|existing_provider| existing_provider.id() == provider.id())
 6405        {
 6406            return;
 6407        }
 6408
 6409        self.code_action_providers.push(provider);
 6410        self.refresh_code_actions(window, cx);
 6411    }
 6412
 6413    pub fn remove_code_action_provider(
 6414        &mut self,
 6415        id: Arc<str>,
 6416        window: &mut Window,
 6417        cx: &mut Context<Self>,
 6418    ) {
 6419        self.code_action_providers
 6420            .retain(|provider| provider.id() != id);
 6421        self.refresh_code_actions(window, cx);
 6422    }
 6423
 6424    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6425        !self.code_action_providers.is_empty()
 6426            && EditorSettings::get_global(cx).toolbar.code_actions
 6427    }
 6428
 6429    pub fn has_available_code_actions(&self) -> bool {
 6430        self.available_code_actions
 6431            .as_ref()
 6432            .is_some_and(|(_, actions)| !actions.is_empty())
 6433    }
 6434
 6435    fn render_inline_code_actions(
 6436        &self,
 6437        icon_size: ui::IconSize,
 6438        display_row: DisplayRow,
 6439        is_active: bool,
 6440        cx: &mut Context<Self>,
 6441    ) -> AnyElement {
 6442        let show_tooltip = !self.context_menu_visible();
 6443        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6444            .icon_size(icon_size)
 6445            .shape(ui::IconButtonShape::Square)
 6446            .icon_color(ui::Color::Hidden)
 6447            .toggle_state(is_active)
 6448            .when(show_tooltip, |this| {
 6449                this.tooltip({
 6450                    let focus_handle = self.focus_handle.clone();
 6451                    move |window, cx| {
 6452                        Tooltip::for_action_in(
 6453                            "Toggle Code Actions",
 6454                            &ToggleCodeActions {
 6455                                deployed_from: None,
 6456                                quick_launch: false,
 6457                            },
 6458                            &focus_handle,
 6459                            window,
 6460                            cx,
 6461                        )
 6462                    }
 6463                })
 6464            })
 6465            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6466                window.focus(&editor.focus_handle(cx));
 6467                editor.toggle_code_actions(
 6468                    &crate::actions::ToggleCodeActions {
 6469                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6470                            display_row,
 6471                        )),
 6472                        quick_launch: false,
 6473                    },
 6474                    window,
 6475                    cx,
 6476                );
 6477            }))
 6478            .into_any_element()
 6479    }
 6480
 6481    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6482        &self.context_menu
 6483    }
 6484
 6485    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Option<()> {
 6486        let newest_selection = self.selections.newest_anchor().clone();
 6487        let newest_selection_adjusted = self.selections.newest_adjusted(cx).clone();
 6488        let buffer = self.buffer.read(cx);
 6489        if newest_selection.head().diff_base_anchor.is_some() {
 6490            return None;
 6491        }
 6492        let (start_buffer, start) =
 6493            buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6494        let (end_buffer, end) =
 6495            buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6496        if start_buffer != end_buffer {
 6497            return None;
 6498        }
 6499
 6500        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6501            cx.background_executor()
 6502                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6503                .await;
 6504
 6505            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6506                let providers = this.code_action_providers.clone();
 6507                let tasks = this
 6508                    .code_action_providers
 6509                    .iter()
 6510                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6511                    .collect::<Vec<_>>();
 6512                (providers, tasks)
 6513            })?;
 6514
 6515            let mut actions = Vec::new();
 6516            for (provider, provider_actions) in
 6517                providers.into_iter().zip(future::join_all(tasks).await)
 6518            {
 6519                if let Some(provider_actions) = provider_actions.log_err() {
 6520                    actions.extend(provider_actions.into_iter().map(|action| {
 6521                        AvailableCodeAction {
 6522                            excerpt_id: newest_selection.start.excerpt_id,
 6523                            action,
 6524                            provider: provider.clone(),
 6525                        }
 6526                    }));
 6527                }
 6528            }
 6529
 6530            this.update(cx, |this, cx| {
 6531                this.available_code_actions = if actions.is_empty() {
 6532                    None
 6533                } else {
 6534                    Some((
 6535                        Location {
 6536                            buffer: start_buffer,
 6537                            range: start..end,
 6538                        },
 6539                        actions.into(),
 6540                    ))
 6541                };
 6542                cx.notify();
 6543            })
 6544        }));
 6545        None
 6546    }
 6547
 6548    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6549        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6550            self.show_git_blame_inline = false;
 6551
 6552            self.show_git_blame_inline_delay_task =
 6553                Some(cx.spawn_in(window, async move |this, cx| {
 6554                    cx.background_executor().timer(delay).await;
 6555
 6556                    this.update(cx, |this, cx| {
 6557                        this.show_git_blame_inline = true;
 6558                        cx.notify();
 6559                    })
 6560                    .log_err();
 6561                }));
 6562        }
 6563    }
 6564
 6565    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6566        let snapshot = self.snapshot(window, cx);
 6567        let cursor = self.selections.newest::<Point>(cx).head();
 6568        let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
 6569        else {
 6570            return;
 6571        };
 6572
 6573        let Some(blame) = self.blame.as_ref() else {
 6574            return;
 6575        };
 6576
 6577        let row_info = RowInfo {
 6578            buffer_id: Some(buffer.remote_id()),
 6579            buffer_row: Some(point.row),
 6580            ..Default::default()
 6581        };
 6582        let Some(blame_entry) = blame
 6583            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6584            .flatten()
 6585        else {
 6586            return;
 6587        };
 6588
 6589        let anchor = self.selections.newest_anchor().head();
 6590        let position = self.to_pixel_point(anchor, &snapshot, window);
 6591        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6592            self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
 6593        };
 6594    }
 6595
 6596    fn show_blame_popover(
 6597        &mut self,
 6598        blame_entry: &BlameEntry,
 6599        position: gpui::Point<Pixels>,
 6600        ignore_timeout: bool,
 6601        cx: &mut Context<Self>,
 6602    ) {
 6603        if let Some(state) = &mut self.inline_blame_popover {
 6604            state.hide_task.take();
 6605        } else {
 6606            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
 6607            let blame_entry = blame_entry.clone();
 6608            let show_task = cx.spawn(async move |editor, cx| {
 6609                if !ignore_timeout {
 6610                    cx.background_executor()
 6611                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6612                        .await;
 6613                }
 6614                editor
 6615                    .update(cx, |editor, cx| {
 6616                        editor.inline_blame_popover_show_task.take();
 6617                        let Some(blame) = editor.blame.as_ref() else {
 6618                            return;
 6619                        };
 6620                        let blame = blame.read(cx);
 6621                        let details = blame.details_for_entry(&blame_entry);
 6622                        let markdown = cx.new(|cx| {
 6623                            Markdown::new(
 6624                                details
 6625                                    .as_ref()
 6626                                    .map(|message| message.message.clone())
 6627                                    .unwrap_or_default(),
 6628                                None,
 6629                                None,
 6630                                cx,
 6631                            )
 6632                        });
 6633                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6634                            position,
 6635                            hide_task: None,
 6636                            popover_bounds: None,
 6637                            popover_state: InlineBlamePopoverState {
 6638                                scroll_handle: ScrollHandle::new(),
 6639                                commit_message: details,
 6640                                markdown,
 6641                            },
 6642                            keyboard_grace: ignore_timeout,
 6643                        });
 6644                        cx.notify();
 6645                    })
 6646                    .ok();
 6647            });
 6648            self.inline_blame_popover_show_task = Some(show_task);
 6649        }
 6650    }
 6651
 6652    fn hide_blame_popover(&mut self, cx: &mut Context<Self>) {
 6653        self.inline_blame_popover_show_task.take();
 6654        if let Some(state) = &mut self.inline_blame_popover {
 6655            let hide_task = cx.spawn(async move |editor, cx| {
 6656                cx.background_executor()
 6657                    .timer(std::time::Duration::from_millis(100))
 6658                    .await;
 6659                editor
 6660                    .update(cx, |editor, cx| {
 6661                        editor.inline_blame_popover.take();
 6662                        cx.notify();
 6663                    })
 6664                    .ok();
 6665            });
 6666            state.hide_task = Some(hide_task);
 6667        }
 6668    }
 6669
 6670    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6671        if self.pending_rename.is_some() {
 6672            return None;
 6673        }
 6674
 6675        let provider = self.semantics_provider.clone()?;
 6676        let buffer = self.buffer.read(cx);
 6677        let newest_selection = self.selections.newest_anchor().clone();
 6678        let cursor_position = newest_selection.head();
 6679        let (cursor_buffer, cursor_buffer_position) =
 6680            buffer.text_anchor_for_position(cursor_position, cx)?;
 6681        let (tail_buffer, tail_buffer_position) =
 6682            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6683        if cursor_buffer != tail_buffer {
 6684            return None;
 6685        }
 6686
 6687        let snapshot = cursor_buffer.read(cx).snapshot();
 6688        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, false);
 6689        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, false);
 6690        if start_word_range != end_word_range {
 6691            self.document_highlights_task.take();
 6692            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6693            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6694            return None;
 6695        }
 6696
 6697        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce;
 6698        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6699            cx.background_executor()
 6700                .timer(Duration::from_millis(debounce))
 6701                .await;
 6702
 6703            let highlights = if let Some(highlights) = cx
 6704                .update(|cx| {
 6705                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6706                })
 6707                .ok()
 6708                .flatten()
 6709            {
 6710                highlights.await.log_err()
 6711            } else {
 6712                None
 6713            };
 6714
 6715            if let Some(highlights) = highlights {
 6716                this.update(cx, |this, cx| {
 6717                    if this.pending_rename.is_some() {
 6718                        return;
 6719                    }
 6720
 6721                    let buffer_id = cursor_position.buffer_id;
 6722                    let buffer = this.buffer.read(cx);
 6723                    if !buffer
 6724                        .text_anchor_for_position(cursor_position, cx)
 6725                        .map_or(false, |(buffer, _)| buffer == cursor_buffer)
 6726                    {
 6727                        return;
 6728                    }
 6729
 6730                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6731                    let mut write_ranges = Vec::new();
 6732                    let mut read_ranges = Vec::new();
 6733                    for highlight in highlights {
 6734                        for (excerpt_id, excerpt_range) in
 6735                            buffer.excerpts_for_buffer(cursor_buffer.read(cx).remote_id(), cx)
 6736                        {
 6737                            let start = highlight
 6738                                .range
 6739                                .start
 6740                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6741                            let end = highlight
 6742                                .range
 6743                                .end
 6744                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6745                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6746                                continue;
 6747                            }
 6748
 6749                            let range = Anchor {
 6750                                buffer_id,
 6751                                excerpt_id,
 6752                                text_anchor: start,
 6753                                diff_base_anchor: None,
 6754                            }..Anchor {
 6755                                buffer_id,
 6756                                excerpt_id,
 6757                                text_anchor: end,
 6758                                diff_base_anchor: None,
 6759                            };
 6760                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6761                                write_ranges.push(range);
 6762                            } else {
 6763                                read_ranges.push(range);
 6764                            }
 6765                        }
 6766                    }
 6767
 6768                    this.highlight_background::<DocumentHighlightRead>(
 6769                        &read_ranges,
 6770                        |theme| theme.colors().editor_document_highlight_read_background,
 6771                        cx,
 6772                    );
 6773                    this.highlight_background::<DocumentHighlightWrite>(
 6774                        &write_ranges,
 6775                        |theme| theme.colors().editor_document_highlight_write_background,
 6776                        cx,
 6777                    );
 6778                    cx.notify();
 6779                })
 6780                .log_err();
 6781            }
 6782        }));
 6783        None
 6784    }
 6785
 6786    fn prepare_highlight_query_from_selection(
 6787        &mut self,
 6788        cx: &mut Context<Editor>,
 6789    ) -> Option<(String, Range<Anchor>)> {
 6790        if matches!(self.mode, EditorMode::SingleLine { .. }) {
 6791            return None;
 6792        }
 6793        if !EditorSettings::get_global(cx).selection_highlight {
 6794            return None;
 6795        }
 6796        if self.selections.count() != 1 || self.selections.line_mode {
 6797            return None;
 6798        }
 6799        let selection = self.selections.newest::<Point>(cx);
 6800        if selection.is_empty() || selection.start.row != selection.end.row {
 6801            return None;
 6802        }
 6803        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6804        let selection_anchor_range = selection.range().to_anchors(&multi_buffer_snapshot);
 6805        let query = multi_buffer_snapshot
 6806            .text_for_range(selection_anchor_range.clone())
 6807            .collect::<String>();
 6808        if query.trim().is_empty() {
 6809            return None;
 6810        }
 6811        Some((query, selection_anchor_range))
 6812    }
 6813
 6814    fn update_selection_occurrence_highlights(
 6815        &mut self,
 6816        query_text: String,
 6817        query_range: Range<Anchor>,
 6818        multi_buffer_range_to_query: Range<Point>,
 6819        use_debounce: bool,
 6820        window: &mut Window,
 6821        cx: &mut Context<Editor>,
 6822    ) -> Task<()> {
 6823        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6824        cx.spawn_in(window, async move |editor, cx| {
 6825            if use_debounce {
 6826                cx.background_executor()
 6827                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6828                    .await;
 6829            }
 6830            let match_task = cx.background_spawn(async move {
 6831                let buffer_ranges = multi_buffer_snapshot
 6832                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6833                    .into_iter()
 6834                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6835                let mut match_ranges = Vec::new();
 6836                let Ok(regex) = project::search::SearchQuery::text(
 6837                    query_text.clone(),
 6838                    false,
 6839                    false,
 6840                    false,
 6841                    Default::default(),
 6842                    Default::default(),
 6843                    false,
 6844                    None,
 6845                ) else {
 6846                    return Vec::default();
 6847                };
 6848                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6849                    match_ranges.extend(
 6850                        regex
 6851                            .search(buffer_snapshot, Some(search_range.clone()))
 6852                            .await
 6853                            .into_iter()
 6854                            .filter_map(|match_range| {
 6855                                let match_start = buffer_snapshot
 6856                                    .anchor_after(search_range.start + match_range.start);
 6857                                let match_end = buffer_snapshot
 6858                                    .anchor_before(search_range.start + match_range.end);
 6859                                let match_anchor_range = Anchor::range_in_buffer(
 6860                                    excerpt_id,
 6861                                    buffer_snapshot.remote_id(),
 6862                                    match_start..match_end,
 6863                                );
 6864                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6865                            }),
 6866                    );
 6867                }
 6868                match_ranges
 6869            });
 6870            let match_ranges = match_task.await;
 6871            editor
 6872                .update_in(cx, |editor, _, cx| {
 6873                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6874                    if !match_ranges.is_empty() {
 6875                        editor.highlight_background::<SelectedTextHighlight>(
 6876                            &match_ranges,
 6877                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6878                            cx,
 6879                        )
 6880                    }
 6881                })
 6882                .log_err();
 6883        })
 6884    }
 6885
 6886    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6887        struct NewlineFold;
 6888        let type_id = std::any::TypeId::of::<NewlineFold>();
 6889        if !self.mode.is_single_line() {
 6890            return;
 6891        }
 6892        let snapshot = self.snapshot(window, cx);
 6893        if snapshot.buffer_snapshot.max_point().row == 0 {
 6894            return;
 6895        }
 6896        let task = cx.background_spawn(async move {
 6897            let new_newlines = snapshot
 6898                .buffer_chars_at(0)
 6899                .filter_map(|(c, i)| {
 6900                    if c == '\n' {
 6901                        Some(
 6902                            snapshot.buffer_snapshot.anchor_after(i)
 6903                                ..snapshot.buffer_snapshot.anchor_before(i + 1),
 6904                        )
 6905                    } else {
 6906                        None
 6907                    }
 6908                })
 6909                .collect::<Vec<_>>();
 6910            let existing_newlines = snapshot
 6911                .folds_in_range(0..snapshot.buffer_snapshot.len())
 6912                .filter_map(|fold| {
 6913                    if fold.placeholder.type_tag == Some(type_id) {
 6914                        Some(fold.range.start..fold.range.end)
 6915                    } else {
 6916                        None
 6917                    }
 6918                })
 6919                .collect::<Vec<_>>();
 6920
 6921            (new_newlines, existing_newlines)
 6922        });
 6923        self.folding_newlines = cx.spawn(async move |this, cx| {
 6924            let (new_newlines, existing_newlines) = task.await;
 6925            if new_newlines == existing_newlines {
 6926                return;
 6927            }
 6928            let placeholder = FoldPlaceholder {
 6929                render: Arc::new(move |_, _, cx| {
 6930                    div()
 6931                        .bg(cx.theme().status().hint_background)
 6932                        .border_b_1()
 6933                        .size_full()
 6934                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6935                        .border_color(cx.theme().status().hint)
 6936                        .child("\\n")
 6937                        .into_any()
 6938                }),
 6939                constrain_width: false,
 6940                merge_adjacent: false,
 6941                type_tag: Some(type_id),
 6942            };
 6943            let creases = new_newlines
 6944                .into_iter()
 6945                .map(|range| Crease::simple(range, placeholder.clone()))
 6946                .collect();
 6947            this.update(cx, |this, cx| {
 6948                this.display_map.update(cx, |display_map, cx| {
 6949                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6950                    display_map.fold(creases, cx);
 6951                });
 6952            })
 6953            .ok();
 6954        });
 6955    }
 6956
 6957    fn refresh_selected_text_highlights(
 6958        &mut self,
 6959        on_buffer_edit: bool,
 6960        window: &mut Window,
 6961        cx: &mut Context<Editor>,
 6962    ) {
 6963        let Some((query_text, query_range)) = self.prepare_highlight_query_from_selection(cx)
 6964        else {
 6965            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6966            self.quick_selection_highlight_task.take();
 6967            self.debounced_selection_highlight_task.take();
 6968            return;
 6969        };
 6970        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6971        if on_buffer_edit
 6972            || self
 6973                .quick_selection_highlight_task
 6974                .as_ref()
 6975                .map_or(true, |(prev_anchor_range, _)| {
 6976                    prev_anchor_range != &query_range
 6977                })
 6978        {
 6979            let multi_buffer_visible_start = self
 6980                .scroll_manager
 6981                .anchor()
 6982                .anchor
 6983                .to_point(&multi_buffer_snapshot);
 6984            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6985                multi_buffer_visible_start
 6986                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6987                Bias::Left,
 6988            );
 6989            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6990            self.quick_selection_highlight_task = Some((
 6991                query_range.clone(),
 6992                self.update_selection_occurrence_highlights(
 6993                    query_text.clone(),
 6994                    query_range.clone(),
 6995                    multi_buffer_visible_range,
 6996                    false,
 6997                    window,
 6998                    cx,
 6999                ),
 7000            ));
 7001        }
 7002        if on_buffer_edit
 7003            || self
 7004                .debounced_selection_highlight_task
 7005                .as_ref()
 7006                .map_or(true, |(prev_anchor_range, _)| {
 7007                    prev_anchor_range != &query_range
 7008                })
 7009        {
 7010            let multi_buffer_start = multi_buffer_snapshot
 7011                .anchor_before(0)
 7012                .to_point(&multi_buffer_snapshot);
 7013            let multi_buffer_end = multi_buffer_snapshot
 7014                .anchor_after(multi_buffer_snapshot.len())
 7015                .to_point(&multi_buffer_snapshot);
 7016            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7017            self.debounced_selection_highlight_task = Some((
 7018                query_range.clone(),
 7019                self.update_selection_occurrence_highlights(
 7020                    query_text,
 7021                    query_range,
 7022                    multi_buffer_full_range,
 7023                    true,
 7024                    window,
 7025                    cx,
 7026                ),
 7027            ));
 7028        }
 7029    }
 7030
 7031    pub fn refresh_edit_prediction(
 7032        &mut self,
 7033        debounce: bool,
 7034        user_requested: bool,
 7035        window: &mut Window,
 7036        cx: &mut Context<Self>,
 7037    ) -> Option<()> {
 7038        if DisableAiSettings::get_global(cx).disable_ai {
 7039            return None;
 7040        }
 7041
 7042        let provider = self.edit_prediction_provider()?;
 7043        let cursor = self.selections.newest_anchor().head();
 7044        let (buffer, cursor_buffer_position) =
 7045            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7046
 7047        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7048            self.discard_edit_prediction(false, cx);
 7049            return None;
 7050        }
 7051
 7052        if !user_requested
 7053            && (!self.should_show_edit_predictions()
 7054                || !self.is_focused(window)
 7055                || buffer.read(cx).is_empty())
 7056        {
 7057            self.discard_edit_prediction(false, cx);
 7058            return None;
 7059        }
 7060
 7061        self.update_visible_edit_prediction(window, cx);
 7062        provider.refresh(
 7063            self.project.clone(),
 7064            buffer,
 7065            cursor_buffer_position,
 7066            debounce,
 7067            cx,
 7068        );
 7069        Some(())
 7070    }
 7071
 7072    fn show_edit_predictions_in_menu(&self) -> bool {
 7073        match self.edit_prediction_settings {
 7074            EditPredictionSettings::Disabled => false,
 7075            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7076        }
 7077    }
 7078
 7079    pub fn edit_predictions_enabled(&self) -> bool {
 7080        match self.edit_prediction_settings {
 7081            EditPredictionSettings::Disabled => false,
 7082            EditPredictionSettings::Enabled { .. } => true,
 7083        }
 7084    }
 7085
 7086    fn edit_prediction_requires_modifier(&self) -> bool {
 7087        match self.edit_prediction_settings {
 7088            EditPredictionSettings::Disabled => false,
 7089            EditPredictionSettings::Enabled {
 7090                preview_requires_modifier,
 7091                ..
 7092            } => preview_requires_modifier,
 7093        }
 7094    }
 7095
 7096    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7097        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7098            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7099            self.discard_edit_prediction(false, cx);
 7100        } else {
 7101            let selection = self.selections.newest_anchor();
 7102            let cursor = selection.head();
 7103
 7104            if let Some((buffer, cursor_buffer_position)) =
 7105                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7106            {
 7107                self.edit_prediction_settings =
 7108                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7109            }
 7110        }
 7111    }
 7112
 7113    fn edit_prediction_settings_at_position(
 7114        &self,
 7115        buffer: &Entity<Buffer>,
 7116        buffer_position: language::Anchor,
 7117        cx: &App,
 7118    ) -> EditPredictionSettings {
 7119        if !self.mode.is_full()
 7120            || !self.show_edit_predictions_override.unwrap_or(true)
 7121            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7122        {
 7123            return EditPredictionSettings::Disabled;
 7124        }
 7125
 7126        let buffer = buffer.read(cx);
 7127
 7128        let file = buffer.file();
 7129
 7130        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7131            return EditPredictionSettings::Disabled;
 7132        };
 7133
 7134        let by_provider = matches!(
 7135            self.menu_edit_predictions_policy,
 7136            MenuEditPredictionsPolicy::ByProvider
 7137        );
 7138
 7139        let show_in_menu = by_provider
 7140            && self
 7141                .edit_prediction_provider
 7142                .as_ref()
 7143                .map_or(false, |provider| {
 7144                    provider.provider.show_completions_in_menu()
 7145                });
 7146
 7147        let preview_requires_modifier =
 7148            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7149
 7150        EditPredictionSettings::Enabled {
 7151            show_in_menu,
 7152            preview_requires_modifier,
 7153        }
 7154    }
 7155
 7156    fn should_show_edit_predictions(&self) -> bool {
 7157        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7158    }
 7159
 7160    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7161        matches!(
 7162            self.edit_prediction_preview,
 7163            EditPredictionPreview::Active { .. }
 7164        )
 7165    }
 7166
 7167    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7168        let cursor = self.selections.newest_anchor().head();
 7169        if let Some((buffer, cursor_position)) =
 7170            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7171        {
 7172            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7173        } else {
 7174            false
 7175        }
 7176    }
 7177
 7178    pub fn supports_minimap(&self, cx: &App) -> bool {
 7179        !self.minimap_visibility.disabled() && self.is_singleton(cx)
 7180    }
 7181
 7182    fn edit_predictions_enabled_in_buffer(
 7183        &self,
 7184        buffer: &Entity<Buffer>,
 7185        buffer_position: language::Anchor,
 7186        cx: &App,
 7187    ) -> bool {
 7188        maybe!({
 7189            if self.read_only(cx) {
 7190                return Some(false);
 7191            }
 7192            let provider = self.edit_prediction_provider()?;
 7193            if !provider.is_enabled(buffer, buffer_position, cx) {
 7194                return Some(false);
 7195            }
 7196            let buffer = buffer.read(cx);
 7197            let Some(file) = buffer.file() else {
 7198                return Some(true);
 7199            };
 7200            let settings = all_language_settings(Some(file), cx);
 7201            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7202        })
 7203        .unwrap_or(false)
 7204    }
 7205
 7206    fn cycle_edit_prediction(
 7207        &mut self,
 7208        direction: Direction,
 7209        window: &mut Window,
 7210        cx: &mut Context<Self>,
 7211    ) -> Option<()> {
 7212        let provider = self.edit_prediction_provider()?;
 7213        let cursor = self.selections.newest_anchor().head();
 7214        let (buffer, cursor_buffer_position) =
 7215            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7216        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7217            return None;
 7218        }
 7219
 7220        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7221        self.update_visible_edit_prediction(window, cx);
 7222
 7223        Some(())
 7224    }
 7225
 7226    pub fn show_edit_prediction(
 7227        &mut self,
 7228        _: &ShowEditPrediction,
 7229        window: &mut Window,
 7230        cx: &mut Context<Self>,
 7231    ) {
 7232        if !self.has_active_edit_prediction() {
 7233            self.refresh_edit_prediction(false, true, window, cx);
 7234            return;
 7235        }
 7236
 7237        self.update_visible_edit_prediction(window, cx);
 7238    }
 7239
 7240    pub fn display_cursor_names(
 7241        &mut self,
 7242        _: &DisplayCursorNames,
 7243        window: &mut Window,
 7244        cx: &mut Context<Self>,
 7245    ) {
 7246        self.show_cursor_names(window, cx);
 7247    }
 7248
 7249    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7250        self.show_cursor_names = true;
 7251        cx.notify();
 7252        cx.spawn_in(window, async move |this, cx| {
 7253            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7254            this.update(cx, |this, cx| {
 7255                this.show_cursor_names = false;
 7256                cx.notify()
 7257            })
 7258            .ok()
 7259        })
 7260        .detach();
 7261    }
 7262
 7263    pub fn next_edit_prediction(
 7264        &mut self,
 7265        _: &NextEditPrediction,
 7266        window: &mut Window,
 7267        cx: &mut Context<Self>,
 7268    ) {
 7269        if self.has_active_edit_prediction() {
 7270            self.cycle_edit_prediction(Direction::Next, window, cx);
 7271        } else {
 7272            let is_copilot_disabled = self
 7273                .refresh_edit_prediction(false, true, window, cx)
 7274                .is_none();
 7275            if is_copilot_disabled {
 7276                cx.propagate();
 7277            }
 7278        }
 7279    }
 7280
 7281    pub fn previous_edit_prediction(
 7282        &mut self,
 7283        _: &PreviousEditPrediction,
 7284        window: &mut Window,
 7285        cx: &mut Context<Self>,
 7286    ) {
 7287        if self.has_active_edit_prediction() {
 7288            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7289        } else {
 7290            let is_copilot_disabled = self
 7291                .refresh_edit_prediction(false, true, window, cx)
 7292                .is_none();
 7293            if is_copilot_disabled {
 7294                cx.propagate();
 7295            }
 7296        }
 7297    }
 7298
 7299    pub fn accept_edit_prediction(
 7300        &mut self,
 7301        _: &AcceptEditPrediction,
 7302        window: &mut Window,
 7303        cx: &mut Context<Self>,
 7304    ) {
 7305        if self.show_edit_predictions_in_menu() {
 7306            self.hide_context_menu(window, cx);
 7307        }
 7308
 7309        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7310            return;
 7311        };
 7312
 7313        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7314
 7315        match &active_edit_prediction.completion {
 7316            EditPrediction::Move { target, .. } => {
 7317                let target = *target;
 7318
 7319                if let Some(position_map) = &self.last_position_map {
 7320                    if position_map
 7321                        .visible_row_range
 7322                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7323                        || !self.edit_prediction_requires_modifier()
 7324                    {
 7325                        self.unfold_ranges(&[target..target], true, false, cx);
 7326                        // Note that this is also done in vim's handler of the Tab action.
 7327                        self.change_selections(
 7328                            SelectionEffects::scroll(Autoscroll::newest()),
 7329                            window,
 7330                            cx,
 7331                            |selections| {
 7332                                selections.select_anchor_ranges([target..target]);
 7333                            },
 7334                        );
 7335                        self.clear_row_highlights::<EditPredictionPreview>();
 7336
 7337                        self.edit_prediction_preview
 7338                            .set_previous_scroll_position(None);
 7339                    } else {
 7340                        self.edit_prediction_preview
 7341                            .set_previous_scroll_position(Some(
 7342                                position_map.snapshot.scroll_anchor,
 7343                            ));
 7344
 7345                        self.highlight_rows::<EditPredictionPreview>(
 7346                            target..target,
 7347                            cx.theme().colors().editor_highlighted_line_background,
 7348                            RowHighlightOptions {
 7349                                autoscroll: true,
 7350                                ..Default::default()
 7351                            },
 7352                            cx,
 7353                        );
 7354                        self.request_autoscroll(Autoscroll::fit(), cx);
 7355                    }
 7356                }
 7357            }
 7358            EditPrediction::Edit { edits, .. } => {
 7359                if let Some(provider) = self.edit_prediction_provider() {
 7360                    provider.accept(cx);
 7361                }
 7362
 7363                // Store the transaction ID and selections before applying the edit
 7364                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7365
 7366                let snapshot = self.buffer.read(cx).snapshot(cx);
 7367                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7368
 7369                self.buffer.update(cx, |buffer, cx| {
 7370                    buffer.edit(edits.iter().cloned(), None, cx)
 7371                });
 7372
 7373                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7374                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7375                });
 7376
 7377                let selections = self.selections.disjoint_anchors();
 7378                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7379                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7380                    if has_new_transaction {
 7381                        self.selection_history
 7382                            .insert_transaction(transaction_id_now, selections);
 7383                    }
 7384                }
 7385
 7386                self.update_visible_edit_prediction(window, cx);
 7387                if self.active_edit_prediction.is_none() {
 7388                    self.refresh_edit_prediction(true, true, window, cx);
 7389                }
 7390
 7391                cx.notify();
 7392            }
 7393        }
 7394
 7395        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7396    }
 7397
 7398    pub fn accept_partial_edit_prediction(
 7399        &mut self,
 7400        _: &AcceptPartialEditPrediction,
 7401        window: &mut Window,
 7402        cx: &mut Context<Self>,
 7403    ) {
 7404        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7405            return;
 7406        };
 7407        if self.selections.count() != 1 {
 7408            return;
 7409        }
 7410
 7411        self.report_edit_prediction_event(active_edit_prediction.completion_id.clone(), true, cx);
 7412
 7413        match &active_edit_prediction.completion {
 7414            EditPrediction::Move { target, .. } => {
 7415                let target = *target;
 7416                self.change_selections(
 7417                    SelectionEffects::scroll(Autoscroll::newest()),
 7418                    window,
 7419                    cx,
 7420                    |selections| {
 7421                        selections.select_anchor_ranges([target..target]);
 7422                    },
 7423                );
 7424            }
 7425            EditPrediction::Edit { edits, .. } => {
 7426                // Find an insertion that starts at the cursor position.
 7427                let snapshot = self.buffer.read(cx).snapshot(cx);
 7428                let cursor_offset = self.selections.newest::<usize>(cx).head();
 7429                let insertion = edits.iter().find_map(|(range, text)| {
 7430                    let range = range.to_offset(&snapshot);
 7431                    if range.is_empty() && range.start == cursor_offset {
 7432                        Some(text)
 7433                    } else {
 7434                        None
 7435                    }
 7436                });
 7437
 7438                if let Some(text) = insertion {
 7439                    let mut partial_completion = text
 7440                        .chars()
 7441                        .by_ref()
 7442                        .take_while(|c| c.is_alphabetic())
 7443                        .collect::<String>();
 7444                    if partial_completion.is_empty() {
 7445                        partial_completion = text
 7446                            .chars()
 7447                            .by_ref()
 7448                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7449                            .collect::<String>();
 7450                    }
 7451
 7452                    cx.emit(EditorEvent::InputHandled {
 7453                        utf16_range_to_replace: None,
 7454                        text: partial_completion.clone().into(),
 7455                    });
 7456
 7457                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7458
 7459                    self.refresh_edit_prediction(true, true, window, cx);
 7460                    cx.notify();
 7461                } else {
 7462                    self.accept_edit_prediction(&Default::default(), window, cx);
 7463                }
 7464            }
 7465        }
 7466    }
 7467
 7468    fn discard_edit_prediction(
 7469        &mut self,
 7470        should_report_edit_prediction_event: bool,
 7471        cx: &mut Context<Self>,
 7472    ) -> bool {
 7473        if should_report_edit_prediction_event {
 7474            let completion_id = self
 7475                .active_edit_prediction
 7476                .as_ref()
 7477                .and_then(|active_completion| active_completion.completion_id.clone());
 7478
 7479            self.report_edit_prediction_event(completion_id, false, cx);
 7480        }
 7481
 7482        if let Some(provider) = self.edit_prediction_provider() {
 7483            provider.discard(cx);
 7484        }
 7485
 7486        self.take_active_edit_prediction(cx)
 7487    }
 7488
 7489    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7490        let Some(provider) = self.edit_prediction_provider() else {
 7491            return;
 7492        };
 7493
 7494        let Some((_, buffer, _)) = self
 7495            .buffer
 7496            .read(cx)
 7497            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7498        else {
 7499            return;
 7500        };
 7501
 7502        let extension = buffer
 7503            .read(cx)
 7504            .file()
 7505            .and_then(|file| Some(file.path().extension()?.to_string_lossy().to_string()));
 7506
 7507        let event_type = match accepted {
 7508            true => "Edit Prediction Accepted",
 7509            false => "Edit Prediction Discarded",
 7510        };
 7511        telemetry::event!(
 7512            event_type,
 7513            provider = provider.name(),
 7514            prediction_id = id,
 7515            suggestion_accepted = accepted,
 7516            file_extension = extension,
 7517        );
 7518    }
 7519
 7520    pub fn has_active_edit_prediction(&self) -> bool {
 7521        self.active_edit_prediction.is_some()
 7522    }
 7523
 7524    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7525        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7526            return false;
 7527        };
 7528
 7529        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7530        self.clear_highlights::<EditPredictionHighlight>(cx);
 7531        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7532        true
 7533    }
 7534
 7535    /// Returns true when we're displaying the edit prediction popover below the cursor
 7536    /// like we are not previewing and the LSP autocomplete menu is visible
 7537    /// or we are in `when_holding_modifier` mode.
 7538    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7539        if self.edit_prediction_preview_is_active()
 7540            || !self.show_edit_predictions_in_menu()
 7541            || !self.edit_predictions_enabled()
 7542        {
 7543            return false;
 7544        }
 7545
 7546        if self.has_visible_completions_menu() {
 7547            return true;
 7548        }
 7549
 7550        has_completion && self.edit_prediction_requires_modifier()
 7551    }
 7552
 7553    fn handle_modifiers_changed(
 7554        &mut self,
 7555        modifiers: Modifiers,
 7556        position_map: &PositionMap,
 7557        window: &mut Window,
 7558        cx: &mut Context<Self>,
 7559    ) {
 7560        if self.show_edit_predictions_in_menu() {
 7561            self.update_edit_prediction_preview(&modifiers, window, cx);
 7562        }
 7563
 7564        self.update_selection_mode(&modifiers, position_map, window, cx);
 7565
 7566        let mouse_position = window.mouse_position();
 7567        if !position_map.text_hitbox.is_hovered(window) {
 7568            return;
 7569        }
 7570
 7571        self.update_hovered_link(
 7572            position_map.point_for_position(mouse_position),
 7573            &position_map.snapshot,
 7574            modifiers,
 7575            window,
 7576            cx,
 7577        )
 7578    }
 7579
 7580    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7581        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7582        if invert {
 7583            match multi_cursor_setting {
 7584                MultiCursorModifier::Alt => modifiers.alt,
 7585                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7586            }
 7587        } else {
 7588            match multi_cursor_setting {
 7589                MultiCursorModifier::Alt => modifiers.secondary(),
 7590                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7591            }
 7592        }
 7593    }
 7594
 7595    fn columnar_selection_mode(
 7596        modifiers: &Modifiers,
 7597        cx: &mut Context<Self>,
 7598    ) -> Option<ColumnarMode> {
 7599        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7600            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7601                Some(ColumnarMode::FromMouse)
 7602            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7603                Some(ColumnarMode::FromSelection)
 7604            } else {
 7605                None
 7606            }
 7607        } else {
 7608            None
 7609        }
 7610    }
 7611
 7612    fn update_selection_mode(
 7613        &mut self,
 7614        modifiers: &Modifiers,
 7615        position_map: &PositionMap,
 7616        window: &mut Window,
 7617        cx: &mut Context<Self>,
 7618    ) {
 7619        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7620            return;
 7621        };
 7622        if self.selections.pending.is_none() {
 7623            return;
 7624        }
 7625
 7626        let mouse_position = window.mouse_position();
 7627        let point_for_position = position_map.point_for_position(mouse_position);
 7628        let position = point_for_position.previous_valid;
 7629
 7630        self.select(
 7631            SelectPhase::BeginColumnar {
 7632                position,
 7633                reset: false,
 7634                mode,
 7635                goal_column: point_for_position.exact_unclipped.column(),
 7636            },
 7637            window,
 7638            cx,
 7639        );
 7640    }
 7641
 7642    fn update_edit_prediction_preview(
 7643        &mut self,
 7644        modifiers: &Modifiers,
 7645        window: &mut Window,
 7646        cx: &mut Context<Self>,
 7647    ) {
 7648        let mut modifiers_held = false;
 7649        if let Some(accept_keystroke) = self
 7650            .accept_edit_prediction_keybind(false, window, cx)
 7651            .keystroke()
 7652        {
 7653            modifiers_held = modifiers_held
 7654                || (&accept_keystroke.modifiers == modifiers
 7655                    && accept_keystroke.modifiers.modified());
 7656        };
 7657        if let Some(accept_partial_keystroke) = self
 7658            .accept_edit_prediction_keybind(true, window, cx)
 7659            .keystroke()
 7660        {
 7661            modifiers_held = modifiers_held
 7662                || (&accept_partial_keystroke.modifiers == modifiers
 7663                    && accept_partial_keystroke.modifiers.modified());
 7664        }
 7665
 7666        if modifiers_held {
 7667            if matches!(
 7668                self.edit_prediction_preview,
 7669                EditPredictionPreview::Inactive { .. }
 7670            ) {
 7671                self.edit_prediction_preview = EditPredictionPreview::Active {
 7672                    previous_scroll_position: None,
 7673                    since: Instant::now(),
 7674                };
 7675
 7676                self.update_visible_edit_prediction(window, cx);
 7677                cx.notify();
 7678            }
 7679        } else if let EditPredictionPreview::Active {
 7680            previous_scroll_position,
 7681            since,
 7682        } = self.edit_prediction_preview
 7683        {
 7684            if let (Some(previous_scroll_position), Some(position_map)) =
 7685                (previous_scroll_position, self.last_position_map.as_ref())
 7686            {
 7687                self.set_scroll_position(
 7688                    previous_scroll_position
 7689                        .scroll_position(&position_map.snapshot.display_snapshot),
 7690                    window,
 7691                    cx,
 7692                );
 7693            }
 7694
 7695            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7696                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7697            };
 7698            self.clear_row_highlights::<EditPredictionPreview>();
 7699            self.update_visible_edit_prediction(window, cx);
 7700            cx.notify();
 7701        }
 7702    }
 7703
 7704    fn update_visible_edit_prediction(
 7705        &mut self,
 7706        _window: &mut Window,
 7707        cx: &mut Context<Self>,
 7708    ) -> Option<()> {
 7709        if DisableAiSettings::get_global(cx).disable_ai {
 7710            return None;
 7711        }
 7712
 7713        let selection = self.selections.newest_anchor();
 7714        let cursor = selection.head();
 7715        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7716        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7717        let excerpt_id = cursor.excerpt_id;
 7718
 7719        let show_in_menu = self.show_edit_predictions_in_menu();
 7720        let completions_menu_has_precedence = !show_in_menu
 7721            && (self.context_menu.borrow().is_some()
 7722                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7723
 7724        if completions_menu_has_precedence
 7725            || !offset_selection.is_empty()
 7726            || self
 7727                .active_edit_prediction
 7728                .as_ref()
 7729                .map_or(false, |completion| {
 7730                    let invalidation_range = completion.invalidation_range.to_offset(&multibuffer);
 7731                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7732                    !invalidation_range.contains(&offset_selection.head())
 7733                })
 7734        {
 7735            self.discard_edit_prediction(false, cx);
 7736            return None;
 7737        }
 7738
 7739        self.take_active_edit_prediction(cx);
 7740        let Some(provider) = self.edit_prediction_provider() else {
 7741            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7742            return None;
 7743        };
 7744
 7745        let (buffer, cursor_buffer_position) =
 7746            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7747
 7748        self.edit_prediction_settings =
 7749            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7750
 7751        match self.edit_prediction_settings {
 7752            EditPredictionSettings::Disabled => {
 7753                self.discard_edit_prediction(false, cx);
 7754                return None;
 7755            }
 7756            _ => {}
 7757        };
 7758
 7759        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7760
 7761        if self.edit_prediction_indent_conflict {
 7762            let cursor_point = cursor.to_point(&multibuffer);
 7763
 7764            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7765
 7766            if let Some((_, indent)) = indents.iter().next()
 7767                && indent.len == cursor_point.column
 7768            {
 7769                self.edit_prediction_indent_conflict = false;
 7770            }
 7771        }
 7772
 7773        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7774        let edits = edit_prediction
 7775            .edits
 7776            .into_iter()
 7777            .flat_map(|(range, new_text)| {
 7778                let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
 7779                let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
 7780                Some((start..end, new_text))
 7781            })
 7782            .collect::<Vec<_>>();
 7783        if edits.is_empty() {
 7784            return None;
 7785        }
 7786
 7787        let first_edit_start = edits.first().unwrap().0.start;
 7788        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7789        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7790
 7791        let last_edit_end = edits.last().unwrap().0.end;
 7792        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7793        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7794
 7795        let cursor_row = cursor.to_point(&multibuffer).row;
 7796
 7797        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7798
 7799        let mut inlay_ids = Vec::new();
 7800        let invalidation_row_range;
 7801        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7802            Some(cursor_row..edit_end_row)
 7803        } else if cursor_row > edit_end_row {
 7804            Some(edit_start_row..cursor_row)
 7805        } else {
 7806            None
 7807        };
 7808        let supports_jump = self
 7809            .edit_prediction_provider
 7810            .as_ref()
 7811            .map(|provider| provider.provider.supports_jump_to_edit())
 7812            .unwrap_or(true);
 7813
 7814        let is_move = supports_jump
 7815            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7816        let completion = if is_move {
 7817            invalidation_row_range =
 7818                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7819            let target = first_edit_start;
 7820            EditPrediction::Move { target, snapshot }
 7821        } else {
 7822            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7823                && !self.edit_predictions_hidden_for_vim_mode;
 7824
 7825            if show_completions_in_buffer {
 7826                if edits
 7827                    .iter()
 7828                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7829                {
 7830                    let mut inlays = Vec::new();
 7831                    for (range, new_text) in &edits {
 7832                        let inlay = Inlay::edit_prediction(
 7833                            post_inc(&mut self.next_inlay_id),
 7834                            range.start,
 7835                            new_text.as_str(),
 7836                        );
 7837                        inlay_ids.push(inlay.id);
 7838                        inlays.push(inlay);
 7839                    }
 7840
 7841                    self.splice_inlays(&[], inlays, cx);
 7842                } else {
 7843                    let background_color = cx.theme().status().deleted_background;
 7844                    self.highlight_text::<EditPredictionHighlight>(
 7845                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7846                        HighlightStyle {
 7847                            background_color: Some(background_color),
 7848                            ..Default::default()
 7849                        },
 7850                        cx,
 7851                    );
 7852                }
 7853            }
 7854
 7855            invalidation_row_range = edit_start_row..edit_end_row;
 7856
 7857            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7858                if provider.show_tab_accept_marker() {
 7859                    EditDisplayMode::TabAccept
 7860                } else {
 7861                    EditDisplayMode::Inline
 7862                }
 7863            } else {
 7864                EditDisplayMode::DiffPopover
 7865            };
 7866
 7867            EditPrediction::Edit {
 7868                edits,
 7869                edit_preview: edit_prediction.edit_preview,
 7870                display_mode,
 7871                snapshot,
 7872            }
 7873        };
 7874
 7875        let invalidation_range = multibuffer
 7876            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7877            ..multibuffer.anchor_after(Point::new(
 7878                invalidation_row_range.end,
 7879                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7880            ));
 7881
 7882        self.stale_edit_prediction_in_menu = None;
 7883        self.active_edit_prediction = Some(EditPredictionState {
 7884            inlay_ids,
 7885            completion,
 7886            completion_id: edit_prediction.id,
 7887            invalidation_range,
 7888        });
 7889
 7890        cx.notify();
 7891
 7892        Some(())
 7893    }
 7894
 7895    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7896        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7897    }
 7898
 7899    fn clear_tasks(&mut self) {
 7900        self.tasks.clear()
 7901    }
 7902
 7903    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7904        if self.tasks.insert(key, value).is_some() {
 7905            // This case should hopefully be rare, but just in case...
 7906            log::error!(
 7907                "multiple different run targets found on a single line, only the last target will be rendered"
 7908            )
 7909        }
 7910    }
 7911
 7912    /// Get all display points of breakpoints that will be rendered within editor
 7913    ///
 7914    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7915    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7916    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7917    fn active_breakpoints(
 7918        &self,
 7919        range: Range<DisplayRow>,
 7920        window: &mut Window,
 7921        cx: &mut Context<Self>,
 7922    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7923        let mut breakpoint_display_points = HashMap::default();
 7924
 7925        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7926            return breakpoint_display_points;
 7927        };
 7928
 7929        let snapshot = self.snapshot(window, cx);
 7930
 7931        let multi_buffer_snapshot = &snapshot.display_snapshot.buffer_snapshot;
 7932        let Some(project) = self.project() else {
 7933            return breakpoint_display_points;
 7934        };
 7935
 7936        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7937            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7938
 7939        for (buffer_snapshot, range, excerpt_id) in
 7940            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7941        {
 7942            let Some(buffer) = project
 7943                .read(cx)
 7944                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7945            else {
 7946                continue;
 7947            };
 7948            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7949                &buffer,
 7950                Some(
 7951                    buffer_snapshot.anchor_before(range.start)
 7952                        ..buffer_snapshot.anchor_after(range.end),
 7953                ),
 7954                buffer_snapshot,
 7955                cx,
 7956            );
 7957            for (breakpoint, state) in breakpoints {
 7958                let multi_buffer_anchor =
 7959                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 7960                let position = multi_buffer_anchor
 7961                    .to_point(multi_buffer_snapshot)
 7962                    .to_display_point(&snapshot);
 7963
 7964                breakpoint_display_points.insert(
 7965                    position.row(),
 7966                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 7967                );
 7968            }
 7969        }
 7970
 7971        breakpoint_display_points
 7972    }
 7973
 7974    fn breakpoint_context_menu(
 7975        &self,
 7976        anchor: Anchor,
 7977        window: &mut Window,
 7978        cx: &mut Context<Self>,
 7979    ) -> Entity<ui::ContextMenu> {
 7980        let weak_editor = cx.weak_entity();
 7981        let focus_handle = self.focus_handle(cx);
 7982
 7983        let row = self
 7984            .buffer
 7985            .read(cx)
 7986            .snapshot(cx)
 7987            .summary_for_anchor::<Point>(&anchor)
 7988            .row;
 7989
 7990        let breakpoint = self
 7991            .breakpoint_at_row(row, window, cx)
 7992            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 7993
 7994        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 7995            "Edit Log Breakpoint"
 7996        } else {
 7997            "Set Log Breakpoint"
 7998        };
 7999
 8000        let condition_breakpoint_msg = if breakpoint
 8001            .as_ref()
 8002            .is_some_and(|bp| bp.1.condition.is_some())
 8003        {
 8004            "Edit Condition Breakpoint"
 8005        } else {
 8006            "Set Condition Breakpoint"
 8007        };
 8008
 8009        let hit_condition_breakpoint_msg = if breakpoint
 8010            .as_ref()
 8011            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8012        {
 8013            "Edit Hit Condition Breakpoint"
 8014        } else {
 8015            "Set Hit Condition Breakpoint"
 8016        };
 8017
 8018        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8019            "Unset Breakpoint"
 8020        } else {
 8021            "Set Breakpoint"
 8022        };
 8023
 8024        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8025
 8026        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8027            BreakpointState::Enabled => Some("Disable"),
 8028            BreakpointState::Disabled => Some("Enable"),
 8029        });
 8030
 8031        let (anchor, breakpoint) =
 8032            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8033
 8034        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8035            menu.on_blur_subscription(Subscription::new(|| {}))
 8036                .context(focus_handle)
 8037                .when(run_to_cursor, |this| {
 8038                    let weak_editor = weak_editor.clone();
 8039                    this.entry("Run to cursor", None, move |window, cx| {
 8040                        weak_editor
 8041                            .update(cx, |editor, cx| {
 8042                                editor.change_selections(
 8043                                    SelectionEffects::no_scroll(),
 8044                                    window,
 8045                                    cx,
 8046                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8047                                );
 8048                            })
 8049                            .ok();
 8050
 8051                        window.dispatch_action(Box::new(RunToCursor), cx);
 8052                    })
 8053                    .separator()
 8054                })
 8055                .when_some(toggle_state_msg, |this, msg| {
 8056                    this.entry(msg, None, {
 8057                        let weak_editor = weak_editor.clone();
 8058                        let breakpoint = breakpoint.clone();
 8059                        move |_window, cx| {
 8060                            weak_editor
 8061                                .update(cx, |this, cx| {
 8062                                    this.edit_breakpoint_at_anchor(
 8063                                        anchor,
 8064                                        breakpoint.as_ref().clone(),
 8065                                        BreakpointEditAction::InvertState,
 8066                                        cx,
 8067                                    );
 8068                                })
 8069                                .log_err();
 8070                        }
 8071                    })
 8072                })
 8073                .entry(set_breakpoint_msg, None, {
 8074                    let weak_editor = weak_editor.clone();
 8075                    let breakpoint = breakpoint.clone();
 8076                    move |_window, cx| {
 8077                        weak_editor
 8078                            .update(cx, |this, cx| {
 8079                                this.edit_breakpoint_at_anchor(
 8080                                    anchor,
 8081                                    breakpoint.as_ref().clone(),
 8082                                    BreakpointEditAction::Toggle,
 8083                                    cx,
 8084                                );
 8085                            })
 8086                            .log_err();
 8087                    }
 8088                })
 8089                .entry(log_breakpoint_msg, None, {
 8090                    let breakpoint = breakpoint.clone();
 8091                    let weak_editor = weak_editor.clone();
 8092                    move |window, cx| {
 8093                        weak_editor
 8094                            .update(cx, |this, cx| {
 8095                                this.add_edit_breakpoint_block(
 8096                                    anchor,
 8097                                    breakpoint.as_ref(),
 8098                                    BreakpointPromptEditAction::Log,
 8099                                    window,
 8100                                    cx,
 8101                                );
 8102                            })
 8103                            .log_err();
 8104                    }
 8105                })
 8106                .entry(condition_breakpoint_msg, None, {
 8107                    let breakpoint = breakpoint.clone();
 8108                    let weak_editor = weak_editor.clone();
 8109                    move |window, cx| {
 8110                        weak_editor
 8111                            .update(cx, |this, cx| {
 8112                                this.add_edit_breakpoint_block(
 8113                                    anchor,
 8114                                    breakpoint.as_ref(),
 8115                                    BreakpointPromptEditAction::Condition,
 8116                                    window,
 8117                                    cx,
 8118                                );
 8119                            })
 8120                            .log_err();
 8121                    }
 8122                })
 8123                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8124                    weak_editor
 8125                        .update(cx, |this, cx| {
 8126                            this.add_edit_breakpoint_block(
 8127                                anchor,
 8128                                breakpoint.as_ref(),
 8129                                BreakpointPromptEditAction::HitCondition,
 8130                                window,
 8131                                cx,
 8132                            );
 8133                        })
 8134                        .log_err();
 8135                })
 8136        })
 8137    }
 8138
 8139    fn render_breakpoint(
 8140        &self,
 8141        position: Anchor,
 8142        row: DisplayRow,
 8143        breakpoint: &Breakpoint,
 8144        state: Option<BreakpointSessionState>,
 8145        cx: &mut Context<Self>,
 8146    ) -> IconButton {
 8147        let is_rejected = state.is_some_and(|s| !s.verified);
 8148        // Is it a breakpoint that shows up when hovering over gutter?
 8149        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8150            (false, false),
 8151            |PhantomBreakpointIndicator {
 8152                 is_active,
 8153                 display_row,
 8154                 collides_with_existing_breakpoint,
 8155             }| {
 8156                (
 8157                    is_active && display_row == row,
 8158                    collides_with_existing_breakpoint,
 8159                )
 8160            },
 8161        );
 8162
 8163        let (color, icon) = {
 8164            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8165                (false, false) => ui::IconName::DebugBreakpoint,
 8166                (true, false) => ui::IconName::DebugLogBreakpoint,
 8167                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8168                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8169            };
 8170
 8171            let color = if is_phantom {
 8172                Color::Hint
 8173            } else if is_rejected {
 8174                Color::Disabled
 8175            } else {
 8176                Color::Debugger
 8177            };
 8178
 8179            (color, icon)
 8180        };
 8181
 8182        let breakpoint = Arc::from(breakpoint.clone());
 8183
 8184        let alt_as_text = gpui::Keystroke {
 8185            modifiers: Modifiers::secondary_key(),
 8186            ..Default::default()
 8187        };
 8188        let primary_action_text = if breakpoint.is_disabled() {
 8189            "Enable breakpoint"
 8190        } else if is_phantom && !collides_with_existing {
 8191            "Set breakpoint"
 8192        } else {
 8193            "Unset breakpoint"
 8194        };
 8195        let focus_handle = self.focus_handle.clone();
 8196
 8197        let meta = if is_rejected {
 8198            SharedString::from("No executable code is associated with this line.")
 8199        } else if collides_with_existing && !breakpoint.is_disabled() {
 8200            SharedString::from(format!(
 8201                "{alt_as_text}-click to disable,\nright-click for more options."
 8202            ))
 8203        } else {
 8204            SharedString::from("Right-click for more options.")
 8205        };
 8206        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8207            .icon_size(IconSize::XSmall)
 8208            .size(ui::ButtonSize::None)
 8209            .when(is_rejected, |this| {
 8210                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8211            })
 8212            .icon_color(color)
 8213            .style(ButtonStyle::Transparent)
 8214            .on_click(cx.listener({
 8215                let breakpoint = breakpoint.clone();
 8216
 8217                move |editor, event: &ClickEvent, window, cx| {
 8218                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8219                        BreakpointEditAction::InvertState
 8220                    } else {
 8221                        BreakpointEditAction::Toggle
 8222                    };
 8223
 8224                    window.focus(&editor.focus_handle(cx));
 8225                    editor.edit_breakpoint_at_anchor(
 8226                        position,
 8227                        breakpoint.as_ref().clone(),
 8228                        edit_action,
 8229                        cx,
 8230                    );
 8231                }
 8232            }))
 8233            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8234                editor.set_breakpoint_context_menu(
 8235                    row,
 8236                    Some(position),
 8237                    event.position(),
 8238                    window,
 8239                    cx,
 8240                );
 8241            }))
 8242            .tooltip(move |window, cx| {
 8243                Tooltip::with_meta_in(
 8244                    primary_action_text,
 8245                    Some(&ToggleBreakpoint),
 8246                    meta.clone(),
 8247                    &focus_handle,
 8248                    window,
 8249                    cx,
 8250                )
 8251            })
 8252    }
 8253
 8254    fn build_tasks_context(
 8255        project: &Entity<Project>,
 8256        buffer: &Entity<Buffer>,
 8257        buffer_row: u32,
 8258        tasks: &Arc<RunnableTasks>,
 8259        cx: &mut Context<Self>,
 8260    ) -> Task<Option<task::TaskContext>> {
 8261        let position = Point::new(buffer_row, tasks.column);
 8262        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8263        let location = Location {
 8264            buffer: buffer.clone(),
 8265            range: range_start..range_start,
 8266        };
 8267        // Fill in the environmental variables from the tree-sitter captures
 8268        let mut captured_task_variables = TaskVariables::default();
 8269        for (capture_name, value) in tasks.extra_variables.clone() {
 8270            captured_task_variables.insert(
 8271                task::VariableName::Custom(capture_name.into()),
 8272                value.clone(),
 8273            );
 8274        }
 8275        project.update(cx, |project, cx| {
 8276            project.task_store().update(cx, |task_store, cx| {
 8277                task_store.task_context_for_location(captured_task_variables, location, cx)
 8278            })
 8279        })
 8280    }
 8281
 8282    pub fn spawn_nearest_task(
 8283        &mut self,
 8284        action: &SpawnNearestTask,
 8285        window: &mut Window,
 8286        cx: &mut Context<Self>,
 8287    ) {
 8288        let Some((workspace, _)) = self.workspace.clone() else {
 8289            return;
 8290        };
 8291        let Some(project) = self.project.clone() else {
 8292            return;
 8293        };
 8294
 8295        // Try to find a closest, enclosing node using tree-sitter that has a task
 8296        let Some((buffer, buffer_row, tasks)) = self
 8297            .find_enclosing_node_task(cx)
 8298            // Or find the task that's closest in row-distance.
 8299            .or_else(|| self.find_closest_task(cx))
 8300        else {
 8301            return;
 8302        };
 8303
 8304        let reveal_strategy = action.reveal;
 8305        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8306        cx.spawn_in(window, async move |_, cx| {
 8307            let context = task_context.await?;
 8308            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8309
 8310            let resolved = &mut resolved_task.resolved;
 8311            resolved.reveal = reveal_strategy;
 8312
 8313            workspace
 8314                .update_in(cx, |workspace, window, cx| {
 8315                    workspace.schedule_resolved_task(
 8316                        task_source_kind,
 8317                        resolved_task,
 8318                        false,
 8319                        window,
 8320                        cx,
 8321                    );
 8322                })
 8323                .ok()
 8324        })
 8325        .detach();
 8326    }
 8327
 8328    fn find_closest_task(
 8329        &mut self,
 8330        cx: &mut Context<Self>,
 8331    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8332        let cursor_row = self.selections.newest_adjusted(cx).head().row;
 8333
 8334        let ((buffer_id, row), tasks) = self
 8335            .tasks
 8336            .iter()
 8337            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8338
 8339        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8340        let tasks = Arc::new(tasks.to_owned());
 8341        Some((buffer, *row, tasks))
 8342    }
 8343
 8344    fn find_enclosing_node_task(
 8345        &mut self,
 8346        cx: &mut Context<Self>,
 8347    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8348        let snapshot = self.buffer.read(cx).snapshot(cx);
 8349        let offset = self.selections.newest::<usize>(cx).head();
 8350        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8351        let buffer_id = excerpt.buffer().remote_id();
 8352
 8353        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8354        let mut cursor = layer.node().walk();
 8355
 8356        while cursor.goto_first_child_for_byte(offset).is_some() {
 8357            if cursor.node().end_byte() == offset {
 8358                cursor.goto_next_sibling();
 8359            }
 8360        }
 8361
 8362        // Ascend to the smallest ancestor that contains the range and has a task.
 8363        loop {
 8364            let node = cursor.node();
 8365            let node_range = node.byte_range();
 8366            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8367
 8368            // Check if this node contains our offset
 8369            if node_range.start <= offset && node_range.end >= offset {
 8370                // If it contains offset, check for task
 8371                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8372                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8373                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8374                }
 8375            }
 8376
 8377            if !cursor.goto_parent() {
 8378                break;
 8379            }
 8380        }
 8381        None
 8382    }
 8383
 8384    fn render_run_indicator(
 8385        &self,
 8386        _style: &EditorStyle,
 8387        is_active: bool,
 8388        row: DisplayRow,
 8389        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8390        cx: &mut Context<Self>,
 8391    ) -> IconButton {
 8392        let color = Color::Muted;
 8393        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8394
 8395        IconButton::new(
 8396            ("run_indicator", row.0 as usize),
 8397            ui::IconName::PlayOutlined,
 8398        )
 8399        .shape(ui::IconButtonShape::Square)
 8400        .icon_size(IconSize::XSmall)
 8401        .icon_color(color)
 8402        .toggle_state(is_active)
 8403        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8404            let quick_launch = match e {
 8405                ClickEvent::Keyboard(_) => true,
 8406                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8407            };
 8408
 8409            window.focus(&editor.focus_handle(cx));
 8410            editor.toggle_code_actions(
 8411                &ToggleCodeActions {
 8412                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8413                    quick_launch,
 8414                },
 8415                window,
 8416                cx,
 8417            );
 8418        }))
 8419        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8420            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8421        }))
 8422    }
 8423
 8424    pub fn context_menu_visible(&self) -> bool {
 8425        !self.edit_prediction_preview_is_active()
 8426            && self
 8427                .context_menu
 8428                .borrow()
 8429                .as_ref()
 8430                .map_or(false, |menu| menu.visible())
 8431    }
 8432
 8433    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8434        self.context_menu
 8435            .borrow()
 8436            .as_ref()
 8437            .map(|menu| menu.origin())
 8438    }
 8439
 8440    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8441        self.context_menu_options = Some(options);
 8442    }
 8443
 8444    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
 8445    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
 8446
 8447    fn render_edit_prediction_popover(
 8448        &mut self,
 8449        text_bounds: &Bounds<Pixels>,
 8450        content_origin: gpui::Point<Pixels>,
 8451        right_margin: Pixels,
 8452        editor_snapshot: &EditorSnapshot,
 8453        visible_row_range: Range<DisplayRow>,
 8454        scroll_top: f32,
 8455        scroll_bottom: f32,
 8456        line_layouts: &[LineWithInvisibles],
 8457        line_height: Pixels,
 8458        scroll_pixel_position: gpui::Point<Pixels>,
 8459        newest_selection_head: Option<DisplayPoint>,
 8460        editor_width: Pixels,
 8461        style: &EditorStyle,
 8462        window: &mut Window,
 8463        cx: &mut App,
 8464    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8465        if self.mode().is_minimap() {
 8466            return None;
 8467        }
 8468        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8469
 8470        if self.edit_prediction_visible_in_cursor_popover(true) {
 8471            return None;
 8472        }
 8473
 8474        match &active_edit_prediction.completion {
 8475            EditPrediction::Move { target, .. } => {
 8476                let target_display_point = target.to_display_point(editor_snapshot);
 8477
 8478                if self.edit_prediction_requires_modifier() {
 8479                    if !self.edit_prediction_preview_is_active() {
 8480                        return None;
 8481                    }
 8482
 8483                    self.render_edit_prediction_modifier_jump_popover(
 8484                        text_bounds,
 8485                        content_origin,
 8486                        visible_row_range,
 8487                        line_layouts,
 8488                        line_height,
 8489                        scroll_pixel_position,
 8490                        newest_selection_head,
 8491                        target_display_point,
 8492                        window,
 8493                        cx,
 8494                    )
 8495                } else {
 8496                    self.render_edit_prediction_eager_jump_popover(
 8497                        text_bounds,
 8498                        content_origin,
 8499                        editor_snapshot,
 8500                        visible_row_range,
 8501                        scroll_top,
 8502                        scroll_bottom,
 8503                        line_height,
 8504                        scroll_pixel_position,
 8505                        target_display_point,
 8506                        editor_width,
 8507                        window,
 8508                        cx,
 8509                    )
 8510                }
 8511            }
 8512            EditPrediction::Edit {
 8513                display_mode: EditDisplayMode::Inline,
 8514                ..
 8515            } => None,
 8516            EditPrediction::Edit {
 8517                display_mode: EditDisplayMode::TabAccept,
 8518                edits,
 8519                ..
 8520            } => {
 8521                let range = &edits.first()?.0;
 8522                let target_display_point = range.end.to_display_point(editor_snapshot);
 8523
 8524                self.render_edit_prediction_end_of_line_popover(
 8525                    "Accept",
 8526                    editor_snapshot,
 8527                    visible_row_range,
 8528                    target_display_point,
 8529                    line_height,
 8530                    scroll_pixel_position,
 8531                    content_origin,
 8532                    editor_width,
 8533                    window,
 8534                    cx,
 8535                )
 8536            }
 8537            EditPrediction::Edit {
 8538                edits,
 8539                edit_preview,
 8540                display_mode: EditDisplayMode::DiffPopover,
 8541                snapshot,
 8542            } => self.render_edit_prediction_diff_popover(
 8543                text_bounds,
 8544                content_origin,
 8545                right_margin,
 8546                editor_snapshot,
 8547                visible_row_range,
 8548                line_layouts,
 8549                line_height,
 8550                scroll_pixel_position,
 8551                newest_selection_head,
 8552                editor_width,
 8553                style,
 8554                edits,
 8555                edit_preview,
 8556                snapshot,
 8557                window,
 8558                cx,
 8559            ),
 8560        }
 8561    }
 8562
 8563    fn render_edit_prediction_modifier_jump_popover(
 8564        &mut self,
 8565        text_bounds: &Bounds<Pixels>,
 8566        content_origin: gpui::Point<Pixels>,
 8567        visible_row_range: Range<DisplayRow>,
 8568        line_layouts: &[LineWithInvisibles],
 8569        line_height: Pixels,
 8570        scroll_pixel_position: gpui::Point<Pixels>,
 8571        newest_selection_head: Option<DisplayPoint>,
 8572        target_display_point: DisplayPoint,
 8573        window: &mut Window,
 8574        cx: &mut App,
 8575    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8576        let scrolled_content_origin =
 8577            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
 8578
 8579        const SCROLL_PADDING_Y: Pixels = px(12.);
 8580
 8581        if target_display_point.row() < visible_row_range.start {
 8582            return self.render_edit_prediction_scroll_popover(
 8583                |_| SCROLL_PADDING_Y,
 8584                IconName::ArrowUp,
 8585                visible_row_range,
 8586                line_layouts,
 8587                newest_selection_head,
 8588                scrolled_content_origin,
 8589                window,
 8590                cx,
 8591            );
 8592        } else if target_display_point.row() >= visible_row_range.end {
 8593            return self.render_edit_prediction_scroll_popover(
 8594                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8595                IconName::ArrowDown,
 8596                visible_row_range,
 8597                line_layouts,
 8598                newest_selection_head,
 8599                scrolled_content_origin,
 8600                window,
 8601                cx,
 8602            );
 8603        }
 8604
 8605        const POLE_WIDTH: Pixels = px(2.);
 8606
 8607        let line_layout =
 8608            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8609        let target_column = target_display_point.column() as usize;
 8610
 8611        let target_x = line_layout.x_for_index(target_column);
 8612        let target_y =
 8613            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
 8614
 8615        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8616
 8617        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8618        border_color.l += 0.001;
 8619
 8620        let mut element = v_flex()
 8621            .items_end()
 8622            .when(flag_on_right, |el| el.items_start())
 8623            .child(if flag_on_right {
 8624                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8625                    .rounded_bl(px(0.))
 8626                    .rounded_tl(px(0.))
 8627                    .border_l_2()
 8628                    .border_color(border_color)
 8629            } else {
 8630                self.render_edit_prediction_line_popover("Jump", None, window, cx)?
 8631                    .rounded_br(px(0.))
 8632                    .rounded_tr(px(0.))
 8633                    .border_r_2()
 8634                    .border_color(border_color)
 8635            })
 8636            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8637            .into_any();
 8638
 8639        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8640
 8641        let mut origin = scrolled_content_origin + point(target_x, target_y)
 8642            - point(
 8643                if flag_on_right {
 8644                    POLE_WIDTH
 8645                } else {
 8646                    size.width - POLE_WIDTH
 8647                },
 8648                size.height - line_height,
 8649            );
 8650
 8651        origin.x = origin.x.max(content_origin.x);
 8652
 8653        element.prepaint_at(origin, window, cx);
 8654
 8655        Some((element, origin))
 8656    }
 8657
 8658    fn render_edit_prediction_scroll_popover(
 8659        &mut self,
 8660        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8661        scroll_icon: IconName,
 8662        visible_row_range: Range<DisplayRow>,
 8663        line_layouts: &[LineWithInvisibles],
 8664        newest_selection_head: Option<DisplayPoint>,
 8665        scrolled_content_origin: gpui::Point<Pixels>,
 8666        window: &mut Window,
 8667        cx: &mut App,
 8668    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8669        let mut element = self
 8670            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)?
 8671            .into_any();
 8672
 8673        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8674
 8675        let cursor = newest_selection_head?;
 8676        let cursor_row_layout =
 8677            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8678        let cursor_column = cursor.column() as usize;
 8679
 8680        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8681
 8682        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8683
 8684        element.prepaint_at(origin, window, cx);
 8685        Some((element, origin))
 8686    }
 8687
 8688    fn render_edit_prediction_eager_jump_popover(
 8689        &mut self,
 8690        text_bounds: &Bounds<Pixels>,
 8691        content_origin: gpui::Point<Pixels>,
 8692        editor_snapshot: &EditorSnapshot,
 8693        visible_row_range: Range<DisplayRow>,
 8694        scroll_top: f32,
 8695        scroll_bottom: f32,
 8696        line_height: Pixels,
 8697        scroll_pixel_position: gpui::Point<Pixels>,
 8698        target_display_point: DisplayPoint,
 8699        editor_width: Pixels,
 8700        window: &mut Window,
 8701        cx: &mut App,
 8702    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8703        if target_display_point.row().as_f32() < scroll_top {
 8704            let mut element = self
 8705                .render_edit_prediction_line_popover(
 8706                    "Jump to Edit",
 8707                    Some(IconName::ArrowUp),
 8708                    window,
 8709                    cx,
 8710                )?
 8711                .into_any();
 8712
 8713            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8714            let offset = point(
 8715                (text_bounds.size.width - size.width) / 2.,
 8716                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8717            );
 8718
 8719            let origin = text_bounds.origin + offset;
 8720            element.prepaint_at(origin, window, cx);
 8721            Some((element, origin))
 8722        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
 8723            let mut element = self
 8724                .render_edit_prediction_line_popover(
 8725                    "Jump to Edit",
 8726                    Some(IconName::ArrowDown),
 8727                    window,
 8728                    cx,
 8729                )?
 8730                .into_any();
 8731
 8732            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8733            let offset = point(
 8734                (text_bounds.size.width - size.width) / 2.,
 8735                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8736            );
 8737
 8738            let origin = text_bounds.origin + offset;
 8739            element.prepaint_at(origin, window, cx);
 8740            Some((element, origin))
 8741        } else {
 8742            self.render_edit_prediction_end_of_line_popover(
 8743                "Jump to Edit",
 8744                editor_snapshot,
 8745                visible_row_range,
 8746                target_display_point,
 8747                line_height,
 8748                scroll_pixel_position,
 8749                content_origin,
 8750                editor_width,
 8751                window,
 8752                cx,
 8753            )
 8754        }
 8755    }
 8756
 8757    fn render_edit_prediction_end_of_line_popover(
 8758        self: &mut Editor,
 8759        label: &'static str,
 8760        editor_snapshot: &EditorSnapshot,
 8761        visible_row_range: Range<DisplayRow>,
 8762        target_display_point: DisplayPoint,
 8763        line_height: Pixels,
 8764        scroll_pixel_position: gpui::Point<Pixels>,
 8765        content_origin: gpui::Point<Pixels>,
 8766        editor_width: Pixels,
 8767        window: &mut Window,
 8768        cx: &mut App,
 8769    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8770        let target_line_end = DisplayPoint::new(
 8771            target_display_point.row(),
 8772            editor_snapshot.line_len(target_display_point.row()),
 8773        );
 8774
 8775        let mut element = self
 8776            .render_edit_prediction_line_popover(label, None, window, cx)?
 8777            .into_any();
 8778
 8779        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8780
 8781        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8782
 8783        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
 8784        let mut origin = start_point
 8785            + line_origin
 8786            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8787        origin.x = origin.x.max(content_origin.x);
 8788
 8789        let max_x = content_origin.x + editor_width - size.width;
 8790
 8791        if origin.x > max_x {
 8792            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8793
 8794            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8795                origin.y += offset;
 8796                IconName::ArrowUp
 8797            } else {
 8798                origin.y -= offset;
 8799                IconName::ArrowDown
 8800            };
 8801
 8802            element = self
 8803                .render_edit_prediction_line_popover(label, Some(icon), window, cx)?
 8804                .into_any();
 8805
 8806            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8807
 8808            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8809        }
 8810
 8811        element.prepaint_at(origin, window, cx);
 8812        Some((element, origin))
 8813    }
 8814
 8815    fn render_edit_prediction_diff_popover(
 8816        self: &Editor,
 8817        text_bounds: &Bounds<Pixels>,
 8818        content_origin: gpui::Point<Pixels>,
 8819        right_margin: Pixels,
 8820        editor_snapshot: &EditorSnapshot,
 8821        visible_row_range: Range<DisplayRow>,
 8822        line_layouts: &[LineWithInvisibles],
 8823        line_height: Pixels,
 8824        scroll_pixel_position: gpui::Point<Pixels>,
 8825        newest_selection_head: Option<DisplayPoint>,
 8826        editor_width: Pixels,
 8827        style: &EditorStyle,
 8828        edits: &Vec<(Range<Anchor>, String)>,
 8829        edit_preview: &Option<language::EditPreview>,
 8830        snapshot: &language::BufferSnapshot,
 8831        window: &mut Window,
 8832        cx: &mut App,
 8833    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8834        let edit_start = edits
 8835            .first()
 8836            .unwrap()
 8837            .0
 8838            .start
 8839            .to_display_point(editor_snapshot);
 8840        let edit_end = edits
 8841            .last()
 8842            .unwrap()
 8843            .0
 8844            .end
 8845            .to_display_point(editor_snapshot);
 8846
 8847        let is_visible = visible_row_range.contains(&edit_start.row())
 8848            || visible_row_range.contains(&edit_end.row());
 8849        if !is_visible {
 8850            return None;
 8851        }
 8852
 8853        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8854            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8855        } else {
 8856            // Fallback for providers without edit_preview
 8857            crate::edit_prediction_fallback_text(edits, cx)
 8858        };
 8859
 8860        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8861        let line_count = highlighted_edits.text.lines().count();
 8862
 8863        const BORDER_WIDTH: Pixels = px(1.);
 8864
 8865        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8866        let has_keybind = keybind.is_some();
 8867
 8868        let mut element = h_flex()
 8869            .items_start()
 8870            .child(
 8871                h_flex()
 8872                    .bg(cx.theme().colors().editor_background)
 8873                    .border(BORDER_WIDTH)
 8874                    .shadow_xs()
 8875                    .border_color(cx.theme().colors().border)
 8876                    .rounded_l_lg()
 8877                    .when(line_count > 1, |el| el.rounded_br_lg())
 8878                    .pr_1()
 8879                    .child(styled_text),
 8880            )
 8881            .child(
 8882                h_flex()
 8883                    .h(line_height + BORDER_WIDTH * 2.)
 8884                    .px_1p5()
 8885                    .gap_1()
 8886                    // Workaround: For some reason, there's a gap if we don't do this
 8887                    .ml(-BORDER_WIDTH)
 8888                    .shadow(vec![gpui::BoxShadow {
 8889                        color: gpui::black().opacity(0.05),
 8890                        offset: point(px(1.), px(1.)),
 8891                        blur_radius: px(2.),
 8892                        spread_radius: px(0.),
 8893                    }])
 8894                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8895                    .border(BORDER_WIDTH)
 8896                    .border_color(cx.theme().colors().border)
 8897                    .rounded_r_lg()
 8898                    .id("edit_prediction_diff_popover_keybind")
 8899                    .when(!has_keybind, |el| {
 8900                        let status_colors = cx.theme().status();
 8901
 8902                        el.bg(status_colors.error_background)
 8903                            .border_color(status_colors.error.opacity(0.6))
 8904                            .child(Icon::new(IconName::Info).color(Color::Error))
 8905                            .cursor_default()
 8906                            .hoverable_tooltip(move |_window, cx| {
 8907                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8908                            })
 8909                    })
 8910                    .children(keybind),
 8911            )
 8912            .into_any();
 8913
 8914        let longest_row =
 8915            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8916        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8917            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8918        } else {
 8919            layout_line(
 8920                longest_row,
 8921                editor_snapshot,
 8922                style,
 8923                editor_width,
 8924                |_| false,
 8925                window,
 8926                cx,
 8927            )
 8928            .width
 8929        };
 8930
 8931        let viewport_bounds =
 8932            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 8933                right: -right_margin,
 8934                ..Default::default()
 8935            });
 8936
 8937        let x_after_longest =
 8938            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
 8939                - scroll_pixel_position.x;
 8940
 8941        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8942
 8943        // Fully visible if it can be displayed within the window (allow overlapping other
 8944        // panes). However, this is only allowed if the popover starts within text_bounds.
 8945        let can_position_to_the_right = x_after_longest < text_bounds.right()
 8946            && x_after_longest + element_bounds.width < viewport_bounds.right();
 8947
 8948        let mut origin = if can_position_to_the_right {
 8949            point(
 8950                x_after_longest,
 8951                text_bounds.origin.y + edit_start.row().as_f32() * line_height
 8952                    - scroll_pixel_position.y,
 8953            )
 8954        } else {
 8955            let cursor_row = newest_selection_head.map(|head| head.row());
 8956            let above_edit = edit_start
 8957                .row()
 8958                .0
 8959                .checked_sub(line_count as u32)
 8960                .map(DisplayRow);
 8961            let below_edit = Some(edit_end.row() + 1);
 8962            let above_cursor =
 8963                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 8964            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 8965
 8966            // Place the edit popover adjacent to the edit if there is a location
 8967            // available that is onscreen and does not obscure the cursor. Otherwise,
 8968            // place it adjacent to the cursor.
 8969            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 8970                .into_iter()
 8971                .flatten()
 8972                .find(|&start_row| {
 8973                    let end_row = start_row + line_count as u32;
 8974                    visible_row_range.contains(&start_row)
 8975                        && visible_row_range.contains(&end_row)
 8976                        && cursor_row.map_or(true, |cursor_row| {
 8977                            !((start_row..end_row).contains(&cursor_row))
 8978                        })
 8979                })?;
 8980
 8981            content_origin
 8982                + point(
 8983                    -scroll_pixel_position.x,
 8984                    row_target.as_f32() * line_height - scroll_pixel_position.y,
 8985                )
 8986        };
 8987
 8988        origin.x -= BORDER_WIDTH;
 8989
 8990        window.defer_draw(element, origin, 1);
 8991
 8992        // Do not return an element, since it will already be drawn due to defer_draw.
 8993        None
 8994    }
 8995
 8996    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 8997        px(30.)
 8998    }
 8999
 9000    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9001        if self.read_only(cx) {
 9002            cx.theme().players().read_only()
 9003        } else {
 9004            self.style.as_ref().unwrap().local_player
 9005        }
 9006    }
 9007
 9008    fn render_edit_prediction_accept_keybind(
 9009        &self,
 9010        window: &mut Window,
 9011        cx: &App,
 9012    ) -> Option<AnyElement> {
 9013        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9014        let accept_keystroke = accept_binding.keystroke()?;
 9015
 9016        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9017
 9018        let modifiers_color = if accept_keystroke.modifiers == window.modifiers() {
 9019            Color::Accent
 9020        } else {
 9021            Color::Muted
 9022        };
 9023
 9024        h_flex()
 9025            .px_0p5()
 9026            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9027            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9028            .text_size(TextSize::XSmall.rems(cx))
 9029            .child(h_flex().children(ui::render_modifiers(
 9030                &accept_keystroke.modifiers,
 9031                PlatformStyle::platform(),
 9032                Some(modifiers_color),
 9033                Some(IconSize::XSmall.rems().into()),
 9034                true,
 9035            )))
 9036            .when(is_platform_style_mac, |parent| {
 9037                parent.child(accept_keystroke.key.clone())
 9038            })
 9039            .when(!is_platform_style_mac, |parent| {
 9040                parent.child(
 9041                    Key::new(
 9042                        util::capitalize(&accept_keystroke.key),
 9043                        Some(Color::Default),
 9044                    )
 9045                    .size(Some(IconSize::XSmall.rems().into())),
 9046                )
 9047            })
 9048            .into_any()
 9049            .into()
 9050    }
 9051
 9052    fn render_edit_prediction_line_popover(
 9053        &self,
 9054        label: impl Into<SharedString>,
 9055        icon: Option<IconName>,
 9056        window: &mut Window,
 9057        cx: &App,
 9058    ) -> Option<Stateful<Div>> {
 9059        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9060
 9061        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9062        let has_keybind = keybind.is_some();
 9063
 9064        let result = h_flex()
 9065            .id("ep-line-popover")
 9066            .py_0p5()
 9067            .pl_1()
 9068            .pr(padding_right)
 9069            .gap_1()
 9070            .rounded_md()
 9071            .border_1()
 9072            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9073            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9074            .shadow_xs()
 9075            .when(!has_keybind, |el| {
 9076                let status_colors = cx.theme().status();
 9077
 9078                el.bg(status_colors.error_background)
 9079                    .border_color(status_colors.error.opacity(0.6))
 9080                    .pl_2()
 9081                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9082                    .cursor_default()
 9083                    .hoverable_tooltip(move |_window, cx| {
 9084                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9085                    })
 9086            })
 9087            .children(keybind)
 9088            .child(
 9089                Label::new(label)
 9090                    .size(LabelSize::Small)
 9091                    .when(!has_keybind, |el| {
 9092                        el.color(cx.theme().status().error.into()).strikethrough()
 9093                    }),
 9094            )
 9095            .when(!has_keybind, |el| {
 9096                el.child(
 9097                    h_flex().ml_1().child(
 9098                        Icon::new(IconName::Info)
 9099                            .size(IconSize::Small)
 9100                            .color(cx.theme().status().error.into()),
 9101                    ),
 9102                )
 9103            })
 9104            .when_some(icon, |element, icon| {
 9105                element.child(
 9106                    div()
 9107                        .mt(px(1.5))
 9108                        .child(Icon::new(icon).size(IconSize::Small)),
 9109                )
 9110            });
 9111
 9112        Some(result)
 9113    }
 9114
 9115    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9116        let accent_color = cx.theme().colors().text_accent;
 9117        let editor_bg_color = cx.theme().colors().editor_background;
 9118        editor_bg_color.blend(accent_color.opacity(0.1))
 9119    }
 9120
 9121    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9122        let accent_color = cx.theme().colors().text_accent;
 9123        let editor_bg_color = cx.theme().colors().editor_background;
 9124        editor_bg_color.blend(accent_color.opacity(0.6))
 9125    }
 9126    fn get_prediction_provider_icon_name(
 9127        provider: &Option<RegisteredEditPredictionProvider>,
 9128    ) -> IconName {
 9129        match provider {
 9130            Some(provider) => match provider.provider.name() {
 9131                "copilot" => IconName::Copilot,
 9132                "supermaven" => IconName::Supermaven,
 9133                _ => IconName::ZedPredict,
 9134            },
 9135            None => IconName::ZedPredict,
 9136        }
 9137    }
 9138
 9139    fn render_edit_prediction_cursor_popover(
 9140        &self,
 9141        min_width: Pixels,
 9142        max_width: Pixels,
 9143        cursor_point: Point,
 9144        style: &EditorStyle,
 9145        accept_keystroke: Option<&gpui::Keystroke>,
 9146        _window: &Window,
 9147        cx: &mut Context<Editor>,
 9148    ) -> Option<AnyElement> {
 9149        let provider = self.edit_prediction_provider.as_ref()?;
 9150        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9151
 9152        if provider.provider.needs_terms_acceptance(cx) {
 9153            return Some(
 9154                h_flex()
 9155                    .min_w(min_width)
 9156                    .flex_1()
 9157                    .px_2()
 9158                    .py_1()
 9159                    .gap_3()
 9160                    .elevation_2(cx)
 9161                    .hover(|style| style.bg(cx.theme().colors().element_hover))
 9162                    .id("accept-terms")
 9163                    .cursor_pointer()
 9164                    .on_mouse_down(MouseButton::Left, |_, window, _| window.prevent_default())
 9165                    .on_click(cx.listener(|this, _event, window, cx| {
 9166                        cx.stop_propagation();
 9167                        this.report_editor_event(ReportEditorEvent::ZetaTosClicked, None, cx);
 9168                        window.dispatch_action(
 9169                            zed_actions::OpenZedPredictOnboarding.boxed_clone(),
 9170                            cx,
 9171                        );
 9172                    }))
 9173                    .child(
 9174                        h_flex()
 9175                            .flex_1()
 9176                            .gap_2()
 9177                            .child(Icon::new(provider_icon))
 9178                            .child(Label::new("Accept Terms of Service"))
 9179                            .child(div().w_full())
 9180                            .child(
 9181                                Icon::new(IconName::ArrowUpRight)
 9182                                    .color(Color::Muted)
 9183                                    .size(IconSize::Small),
 9184                            )
 9185                            .into_any_element(),
 9186                    )
 9187                    .into_any(),
 9188            );
 9189        }
 9190
 9191        let is_refreshing = provider.provider.is_refreshing(cx);
 9192
 9193        fn pending_completion_container(icon: IconName) -> Div {
 9194            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9195        }
 9196
 9197        let completion = match &self.active_edit_prediction {
 9198            Some(prediction) => {
 9199                if !self.has_visible_completions_menu() {
 9200                    const RADIUS: Pixels = px(6.);
 9201                    const BORDER_WIDTH: Pixels = px(1.);
 9202
 9203                    return Some(
 9204                        h_flex()
 9205                            .elevation_2(cx)
 9206                            .border(BORDER_WIDTH)
 9207                            .border_color(cx.theme().colors().border)
 9208                            .when(accept_keystroke.is_none(), |el| {
 9209                                el.border_color(cx.theme().status().error)
 9210                            })
 9211                            .rounded(RADIUS)
 9212                            .rounded_tl(px(0.))
 9213                            .overflow_hidden()
 9214                            .child(div().px_1p5().child(match &prediction.completion {
 9215                                EditPrediction::Move { target, snapshot } => {
 9216                                    use text::ToPoint as _;
 9217                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9218                                    {
 9219                                        Icon::new(IconName::ZedPredictDown)
 9220                                    } else {
 9221                                        Icon::new(IconName::ZedPredictUp)
 9222                                    }
 9223                                }
 9224                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9225                            }))
 9226                            .child(
 9227                                h_flex()
 9228                                    .gap_1()
 9229                                    .py_1()
 9230                                    .px_2()
 9231                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9232                                    .border_l_1()
 9233                                    .border_color(cx.theme().colors().border)
 9234                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9235                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9236                                        el.child(
 9237                                            Label::new("Hold")
 9238                                                .size(LabelSize::Small)
 9239                                                .when(accept_keystroke.is_none(), |el| {
 9240                                                    el.strikethrough()
 9241                                                })
 9242                                                .line_height_style(LineHeightStyle::UiLabel),
 9243                                        )
 9244                                    })
 9245                                    .id("edit_prediction_cursor_popover_keybind")
 9246                                    .when(accept_keystroke.is_none(), |el| {
 9247                                        let status_colors = cx.theme().status();
 9248
 9249                                        el.bg(status_colors.error_background)
 9250                                            .border_color(status_colors.error.opacity(0.6))
 9251                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9252                                            .cursor_default()
 9253                                            .hoverable_tooltip(move |_window, cx| {
 9254                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9255                                                    .into()
 9256                                            })
 9257                                    })
 9258                                    .when_some(
 9259                                        accept_keystroke.as_ref(),
 9260                                        |el, accept_keystroke| {
 9261                                            el.child(h_flex().children(ui::render_modifiers(
 9262                                                &accept_keystroke.modifiers,
 9263                                                PlatformStyle::platform(),
 9264                                                Some(Color::Default),
 9265                                                Some(IconSize::XSmall.rems().into()),
 9266                                                false,
 9267                                            )))
 9268                                        },
 9269                                    ),
 9270                            )
 9271                            .into_any(),
 9272                    );
 9273                }
 9274
 9275                self.render_edit_prediction_cursor_popover_preview(
 9276                    prediction,
 9277                    cursor_point,
 9278                    style,
 9279                    cx,
 9280                )?
 9281            }
 9282
 9283            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9284                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9285                    stale_completion,
 9286                    cursor_point,
 9287                    style,
 9288                    cx,
 9289                )?,
 9290
 9291                None => pending_completion_container(provider_icon)
 9292                    .child(Label::new("...").size(LabelSize::Small)),
 9293            },
 9294
 9295            None => pending_completion_container(provider_icon)
 9296                .child(Label::new("...").size(LabelSize::Small)),
 9297        };
 9298
 9299        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9300            completion
 9301                .with_animation(
 9302                    "loading-completion",
 9303                    Animation::new(Duration::from_secs(2))
 9304                        .repeat()
 9305                        .with_easing(pulsating_between(0.4, 0.8)),
 9306                    |label, delta| label.opacity(delta),
 9307                )
 9308                .into_any_element()
 9309        } else {
 9310            completion.into_any_element()
 9311        };
 9312
 9313        let has_completion = self.active_edit_prediction.is_some();
 9314
 9315        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9316        Some(
 9317            h_flex()
 9318                .min_w(min_width)
 9319                .max_w(max_width)
 9320                .flex_1()
 9321                .elevation_2(cx)
 9322                .border_color(cx.theme().colors().border)
 9323                .child(
 9324                    div()
 9325                        .flex_1()
 9326                        .py_1()
 9327                        .px_2()
 9328                        .overflow_hidden()
 9329                        .child(completion),
 9330                )
 9331                .when_some(accept_keystroke, |el, accept_keystroke| {
 9332                    if !accept_keystroke.modifiers.modified() {
 9333                        return el;
 9334                    }
 9335
 9336                    el.child(
 9337                        h_flex()
 9338                            .h_full()
 9339                            .border_l_1()
 9340                            .rounded_r_lg()
 9341                            .border_color(cx.theme().colors().border)
 9342                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9343                            .gap_1()
 9344                            .py_1()
 9345                            .px_2()
 9346                            .child(
 9347                                h_flex()
 9348                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9349                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9350                                    .child(h_flex().children(ui::render_modifiers(
 9351                                        &accept_keystroke.modifiers,
 9352                                        PlatformStyle::platform(),
 9353                                        Some(if !has_completion {
 9354                                            Color::Muted
 9355                                        } else {
 9356                                            Color::Default
 9357                                        }),
 9358                                        None,
 9359                                        false,
 9360                                    ))),
 9361                            )
 9362                            .child(Label::new("Preview").into_any_element())
 9363                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9364                    )
 9365                })
 9366                .into_any(),
 9367        )
 9368    }
 9369
 9370    fn render_edit_prediction_cursor_popover_preview(
 9371        &self,
 9372        completion: &EditPredictionState,
 9373        cursor_point: Point,
 9374        style: &EditorStyle,
 9375        cx: &mut Context<Editor>,
 9376    ) -> Option<Div> {
 9377        use text::ToPoint as _;
 9378
 9379        fn render_relative_row_jump(
 9380            prefix: impl Into<String>,
 9381            current_row: u32,
 9382            target_row: u32,
 9383        ) -> Div {
 9384            let (row_diff, arrow) = if target_row < current_row {
 9385                (current_row - target_row, IconName::ArrowUp)
 9386            } else {
 9387                (target_row - current_row, IconName::ArrowDown)
 9388            };
 9389
 9390            h_flex()
 9391                .child(
 9392                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9393                        .color(Color::Muted)
 9394                        .size(LabelSize::Small),
 9395                )
 9396                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9397        }
 9398
 9399        let supports_jump = self
 9400            .edit_prediction_provider
 9401            .as_ref()
 9402            .map(|provider| provider.provider.supports_jump_to_edit())
 9403            .unwrap_or(true);
 9404
 9405        match &completion.completion {
 9406            EditPrediction::Move {
 9407                target, snapshot, ..
 9408            } => {
 9409                if !supports_jump {
 9410                    return None;
 9411                }
 9412
 9413                Some(
 9414                    h_flex()
 9415                        .px_2()
 9416                        .gap_2()
 9417                        .flex_1()
 9418                        .child(
 9419                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9420                                Icon::new(IconName::ZedPredictDown)
 9421                            } else {
 9422                                Icon::new(IconName::ZedPredictUp)
 9423                            },
 9424                        )
 9425                        .child(Label::new("Jump to Edit")),
 9426                )
 9427            }
 9428
 9429            EditPrediction::Edit {
 9430                edits,
 9431                edit_preview,
 9432                snapshot,
 9433                display_mode: _,
 9434            } => {
 9435                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9436
 9437                let (highlighted_edits, has_more_lines) =
 9438                    if let Some(edit_preview) = edit_preview.as_ref() {
 9439                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9440                            .first_line_preview()
 9441                    } else {
 9442                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9443                    };
 9444
 9445                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9446                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9447
 9448                let preview = h_flex()
 9449                    .gap_1()
 9450                    .min_w_16()
 9451                    .child(styled_text)
 9452                    .when(has_more_lines, |parent| parent.child(""));
 9453
 9454                let left = if supports_jump && first_edit_row != cursor_point.row {
 9455                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9456                        .into_any_element()
 9457                } else {
 9458                    let icon_name =
 9459                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9460                    Icon::new(icon_name).into_any_element()
 9461                };
 9462
 9463                Some(
 9464                    h_flex()
 9465                        .h_full()
 9466                        .flex_1()
 9467                        .gap_2()
 9468                        .pr_1()
 9469                        .overflow_x_hidden()
 9470                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9471                        .child(left)
 9472                        .child(preview),
 9473                )
 9474            }
 9475        }
 9476    }
 9477
 9478    pub fn render_context_menu(
 9479        &self,
 9480        style: &EditorStyle,
 9481        max_height_in_lines: u32,
 9482        window: &mut Window,
 9483        cx: &mut Context<Editor>,
 9484    ) -> Option<AnyElement> {
 9485        let menu = self.context_menu.borrow();
 9486        let menu = menu.as_ref()?;
 9487        if !menu.visible() {
 9488            return None;
 9489        };
 9490        Some(menu.render(style, max_height_in_lines, window, cx))
 9491    }
 9492
 9493    fn render_context_menu_aside(
 9494        &mut self,
 9495        max_size: Size<Pixels>,
 9496        window: &mut Window,
 9497        cx: &mut Context<Editor>,
 9498    ) -> Option<AnyElement> {
 9499        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9500            if menu.visible() {
 9501                menu.render_aside(max_size, window, cx)
 9502            } else {
 9503                None
 9504            }
 9505        })
 9506    }
 9507
 9508    fn hide_context_menu(
 9509        &mut self,
 9510        window: &mut Window,
 9511        cx: &mut Context<Self>,
 9512    ) -> Option<CodeContextMenu> {
 9513        cx.notify();
 9514        self.completion_tasks.clear();
 9515        let context_menu = self.context_menu.borrow_mut().take();
 9516        self.stale_edit_prediction_in_menu.take();
 9517        self.update_visible_edit_prediction(window, cx);
 9518        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9519            && let Some(completion_provider) = &self.completion_provider
 9520        {
 9521            completion_provider.selection_changed(None, window, cx);
 9522        }
 9523        context_menu
 9524    }
 9525
 9526    fn show_snippet_choices(
 9527        &mut self,
 9528        choices: &Vec<String>,
 9529        selection: Range<Anchor>,
 9530        cx: &mut Context<Self>,
 9531    ) {
 9532        let buffer_id = match (&selection.start.buffer_id, &selection.end.buffer_id) {
 9533            (Some(a), Some(b)) if a == b => a,
 9534            _ => {
 9535                log::error!("expected anchor range to have matching buffer IDs");
 9536                return;
 9537            }
 9538        };
 9539        let multi_buffer = self.buffer().read(cx);
 9540        let Some(buffer) = multi_buffer.buffer(*buffer_id) else {
 9541            return;
 9542        };
 9543
 9544        let id = post_inc(&mut self.next_completion_id);
 9545        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9546        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9547            CompletionsMenu::new_snippet_choices(
 9548                id,
 9549                true,
 9550                choices,
 9551                selection,
 9552                buffer,
 9553                snippet_sort_order,
 9554            ),
 9555        ));
 9556    }
 9557
 9558    pub fn insert_snippet(
 9559        &mut self,
 9560        insertion_ranges: &[Range<usize>],
 9561        snippet: Snippet,
 9562        window: &mut Window,
 9563        cx: &mut Context<Self>,
 9564    ) -> Result<()> {
 9565        struct Tabstop<T> {
 9566            is_end_tabstop: bool,
 9567            ranges: Vec<Range<T>>,
 9568            choices: Option<Vec<String>>,
 9569        }
 9570
 9571        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9572            let snippet_text: Arc<str> = snippet.text.clone().into();
 9573            let edits = insertion_ranges
 9574                .iter()
 9575                .cloned()
 9576                .map(|range| (range, snippet_text.clone()));
 9577            let autoindent_mode = AutoindentMode::Block {
 9578                original_indent_columns: Vec::new(),
 9579            };
 9580            buffer.edit(edits, Some(autoindent_mode), cx);
 9581
 9582            let snapshot = &*buffer.read(cx);
 9583            let snippet = &snippet;
 9584            snippet
 9585                .tabstops
 9586                .iter()
 9587                .map(|tabstop| {
 9588                    let is_end_tabstop = tabstop.ranges.first().map_or(false, |tabstop| {
 9589                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9590                    });
 9591                    let mut tabstop_ranges = tabstop
 9592                        .ranges
 9593                        .iter()
 9594                        .flat_map(|tabstop_range| {
 9595                            let mut delta = 0_isize;
 9596                            insertion_ranges.iter().map(move |insertion_range| {
 9597                                let insertion_start = insertion_range.start as isize + delta;
 9598                                delta +=
 9599                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9600
 9601                                let start = ((insertion_start + tabstop_range.start) as usize)
 9602                                    .min(snapshot.len());
 9603                                let end = ((insertion_start + tabstop_range.end) as usize)
 9604                                    .min(snapshot.len());
 9605                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9606                            })
 9607                        })
 9608                        .collect::<Vec<_>>();
 9609                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9610
 9611                    Tabstop {
 9612                        is_end_tabstop,
 9613                        ranges: tabstop_ranges,
 9614                        choices: tabstop.choices.clone(),
 9615                    }
 9616                })
 9617                .collect::<Vec<_>>()
 9618        });
 9619        if let Some(tabstop) = tabstops.first() {
 9620            self.change_selections(Default::default(), window, cx, |s| {
 9621                // Reverse order so that the first range is the newest created selection.
 9622                // Completions will use it and autoscroll will prioritize it.
 9623                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9624            });
 9625
 9626            if let Some(choices) = &tabstop.choices
 9627                && let Some(selection) = tabstop.ranges.first()
 9628            {
 9629                self.show_snippet_choices(choices, selection.clone(), cx)
 9630            }
 9631
 9632            // If we're already at the last tabstop and it's at the end of the snippet,
 9633            // we're done, we don't need to keep the state around.
 9634            if !tabstop.is_end_tabstop {
 9635                let choices = tabstops
 9636                    .iter()
 9637                    .map(|tabstop| tabstop.choices.clone())
 9638                    .collect();
 9639
 9640                let ranges = tabstops
 9641                    .into_iter()
 9642                    .map(|tabstop| tabstop.ranges)
 9643                    .collect::<Vec<_>>();
 9644
 9645                self.snippet_stack.push(SnippetState {
 9646                    active_index: 0,
 9647                    ranges,
 9648                    choices,
 9649                });
 9650            }
 9651
 9652            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9653            if self.autoclose_regions.is_empty() {
 9654                let snapshot = self.buffer.read(cx).snapshot(cx);
 9655                let mut all_selections = self.selections.all::<Point>(cx);
 9656                for selection in &mut all_selections {
 9657                    let selection_head = selection.head();
 9658                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9659                        continue;
 9660                    };
 9661
 9662                    let mut bracket_pair = None;
 9663                    let max_lookup_length = scope
 9664                        .brackets()
 9665                        .map(|(pair, _)| {
 9666                            pair.start
 9667                                .as_str()
 9668                                .chars()
 9669                                .count()
 9670                                .max(pair.end.as_str().chars().count())
 9671                        })
 9672                        .max();
 9673                    if let Some(max_lookup_length) = max_lookup_length {
 9674                        let next_text = snapshot
 9675                            .chars_at(selection_head)
 9676                            .take(max_lookup_length)
 9677                            .collect::<String>();
 9678                        let prev_text = snapshot
 9679                            .reversed_chars_at(selection_head)
 9680                            .take(max_lookup_length)
 9681                            .collect::<String>();
 9682
 9683                        for (pair, enabled) in scope.brackets() {
 9684                            if enabled
 9685                                && pair.close
 9686                                && prev_text.starts_with(pair.start.as_str())
 9687                                && next_text.starts_with(pair.end.as_str())
 9688                            {
 9689                                bracket_pair = Some(pair.clone());
 9690                                break;
 9691                            }
 9692                        }
 9693                    }
 9694
 9695                    if let Some(pair) = bracket_pair {
 9696                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9697                        let autoclose_enabled =
 9698                            self.use_autoclose && snapshot_settings.use_autoclose;
 9699                        if autoclose_enabled {
 9700                            let start = snapshot.anchor_after(selection_head);
 9701                            let end = snapshot.anchor_after(selection_head);
 9702                            self.autoclose_regions.push(AutocloseRegion {
 9703                                selection_id: selection.id,
 9704                                range: start..end,
 9705                                pair,
 9706                            });
 9707                        }
 9708                    }
 9709                }
 9710            }
 9711        }
 9712        Ok(())
 9713    }
 9714
 9715    pub fn move_to_next_snippet_tabstop(
 9716        &mut self,
 9717        window: &mut Window,
 9718        cx: &mut Context<Self>,
 9719    ) -> bool {
 9720        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9721    }
 9722
 9723    pub fn move_to_prev_snippet_tabstop(
 9724        &mut self,
 9725        window: &mut Window,
 9726        cx: &mut Context<Self>,
 9727    ) -> bool {
 9728        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9729    }
 9730
 9731    pub fn move_to_snippet_tabstop(
 9732        &mut self,
 9733        bias: Bias,
 9734        window: &mut Window,
 9735        cx: &mut Context<Self>,
 9736    ) -> bool {
 9737        if let Some(mut snippet) = self.snippet_stack.pop() {
 9738            match bias {
 9739                Bias::Left => {
 9740                    if snippet.active_index > 0 {
 9741                        snippet.active_index -= 1;
 9742                    } else {
 9743                        self.snippet_stack.push(snippet);
 9744                        return false;
 9745                    }
 9746                }
 9747                Bias::Right => {
 9748                    if snippet.active_index + 1 < snippet.ranges.len() {
 9749                        snippet.active_index += 1;
 9750                    } else {
 9751                        self.snippet_stack.push(snippet);
 9752                        return false;
 9753                    }
 9754                }
 9755            }
 9756            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9757                self.change_selections(Default::default(), window, cx, |s| {
 9758                    // Reverse order so that the first range is the newest created selection.
 9759                    // Completions will use it and autoscroll will prioritize it.
 9760                    s.select_ranges(current_ranges.iter().rev().cloned())
 9761                });
 9762
 9763                if let Some(choices) = &snippet.choices[snippet.active_index]
 9764                    && let Some(selection) = current_ranges.first()
 9765                {
 9766                    self.show_snippet_choices(choices, selection.clone(), cx);
 9767                }
 9768
 9769                // If snippet state is not at the last tabstop, push it back on the stack
 9770                if snippet.active_index + 1 < snippet.ranges.len() {
 9771                    self.snippet_stack.push(snippet);
 9772                }
 9773                return true;
 9774            }
 9775        }
 9776
 9777        false
 9778    }
 9779
 9780    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9781        self.transact(window, cx, |this, window, cx| {
 9782            this.select_all(&SelectAll, window, cx);
 9783            this.insert("", window, cx);
 9784        });
 9785    }
 9786
 9787    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9788        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9789        self.transact(window, cx, |this, window, cx| {
 9790            this.select_autoclose_pair(window, cx);
 9791            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9792            if !this.linked_edit_ranges.is_empty() {
 9793                let selections = this.selections.all::<MultiBufferPoint>(cx);
 9794                let snapshot = this.buffer.read(cx).snapshot(cx);
 9795
 9796                for selection in selections.iter() {
 9797                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9798                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9799                    if selection_start.buffer_id != selection_end.buffer_id {
 9800                        continue;
 9801                    }
 9802                    if let Some(ranges) =
 9803                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9804                    {
 9805                        for (buffer, entries) in ranges {
 9806                            linked_ranges.entry(buffer).or_default().extend(entries);
 9807                        }
 9808                    }
 9809                }
 9810            }
 9811
 9812            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
 9813            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9814            for selection in &mut selections {
 9815                if selection.is_empty() {
 9816                    let old_head = selection.head();
 9817                    let mut new_head =
 9818                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9819                            .to_point(&display_map);
 9820                    if let Some((buffer, line_buffer_range)) = display_map
 9821                        .buffer_snapshot
 9822                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9823                    {
 9824                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9825                        let indent_len = match indent_size.kind {
 9826                            IndentKind::Space => {
 9827                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9828                            }
 9829                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9830                        };
 9831                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9832                            let indent_len = indent_len.get();
 9833                            new_head = cmp::min(
 9834                                new_head,
 9835                                MultiBufferPoint::new(
 9836                                    old_head.row,
 9837                                    ((old_head.column - 1) / indent_len) * indent_len,
 9838                                ),
 9839                            );
 9840                        }
 9841                    }
 9842
 9843                    selection.set_head(new_head, SelectionGoal::None);
 9844                }
 9845            }
 9846
 9847            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9848            this.insert("", window, cx);
 9849            let empty_str: Arc<str> = Arc::from("");
 9850            for (buffer, edits) in linked_ranges {
 9851                let snapshot = buffer.read(cx).snapshot();
 9852                use text::ToPoint as TP;
 9853
 9854                let edits = edits
 9855                    .into_iter()
 9856                    .map(|range| {
 9857                        let end_point = TP::to_point(&range.end, &snapshot);
 9858                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9859
 9860                        if end_point == start_point {
 9861                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9862                                .saturating_sub(1);
 9863                            start_point =
 9864                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9865                        };
 9866
 9867                        (start_point..end_point, empty_str.clone())
 9868                    })
 9869                    .sorted_by_key(|(range, _)| range.start)
 9870                    .collect::<Vec<_>>();
 9871                buffer.update(cx, |this, cx| {
 9872                    this.edit(edits, None, cx);
 9873                })
 9874            }
 9875            this.refresh_edit_prediction(true, false, window, cx);
 9876            linked_editing_ranges::refresh_linked_ranges(this, window, cx);
 9877        });
 9878    }
 9879
 9880    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9881        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9882        self.transact(window, cx, |this, window, cx| {
 9883            this.change_selections(Default::default(), window, cx, |s| {
 9884                s.move_with(|map, selection| {
 9885                    if selection.is_empty() {
 9886                        let cursor = movement::right(map, selection.head());
 9887                        selection.end = cursor;
 9888                        selection.reversed = true;
 9889                        selection.goal = SelectionGoal::None;
 9890                    }
 9891                })
 9892            });
 9893            this.insert("", window, cx);
 9894            this.refresh_edit_prediction(true, false, window, cx);
 9895        });
 9896    }
 9897
 9898    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9899        if self.mode.is_single_line() {
 9900            cx.propagate();
 9901            return;
 9902        }
 9903
 9904        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9905        if self.move_to_prev_snippet_tabstop(window, cx) {
 9906            return;
 9907        }
 9908        self.outdent(&Outdent, window, cx);
 9909    }
 9910
 9911    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9912        if self.mode.is_single_line() {
 9913            cx.propagate();
 9914            return;
 9915        }
 9916
 9917        if self.move_to_next_snippet_tabstop(window, cx) {
 9918            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9919            return;
 9920        }
 9921        if self.read_only(cx) {
 9922            return;
 9923        }
 9924        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9925        let mut selections = self.selections.all_adjusted(cx);
 9926        let buffer = self.buffer.read(cx);
 9927        let snapshot = buffer.snapshot(cx);
 9928        let rows_iter = selections.iter().map(|s| s.head().row);
 9929        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
 9930
 9931        let has_some_cursor_in_whitespace = selections
 9932            .iter()
 9933            .filter(|selection| selection.is_empty())
 9934            .any(|selection| {
 9935                let cursor = selection.head();
 9936                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9937                cursor.column < current_indent.len
 9938            });
 9939
 9940        let mut edits = Vec::new();
 9941        let mut prev_edited_row = 0;
 9942        let mut row_delta = 0;
 9943        for selection in &mut selections {
 9944            if selection.start.row != prev_edited_row {
 9945                row_delta = 0;
 9946            }
 9947            prev_edited_row = selection.end.row;
 9948
 9949            // If the selection is non-empty, then increase the indentation of the selected lines.
 9950            if !selection.is_empty() {
 9951                row_delta =
 9952                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
 9953                continue;
 9954            }
 9955
 9956            let cursor = selection.head();
 9957            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
 9958            if let Some(suggested_indent) =
 9959                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
 9960            {
 9961                // Don't do anything if already at suggested indent
 9962                // and there is any other cursor which is not
 9963                if has_some_cursor_in_whitespace
 9964                    && cursor.column == current_indent.len
 9965                    && current_indent.len == suggested_indent.len
 9966                {
 9967                    continue;
 9968                }
 9969
 9970                // Adjust line and move cursor to suggested indent
 9971                // if cursor is not at suggested indent
 9972                if cursor.column < suggested_indent.len
 9973                    && cursor.column <= current_indent.len
 9974                    && current_indent.len <= suggested_indent.len
 9975                {
 9976                    selection.start = Point::new(cursor.row, suggested_indent.len);
 9977                    selection.end = selection.start;
 9978                    if row_delta == 0 {
 9979                        edits.extend(Buffer::edit_for_indent_size_adjustment(
 9980                            cursor.row,
 9981                            current_indent,
 9982                            suggested_indent,
 9983                        ));
 9984                        row_delta = suggested_indent.len - current_indent.len;
 9985                    }
 9986                    continue;
 9987                }
 9988
 9989                // If current indent is more than suggested indent
 9990                // only move cursor to current indent and skip indent
 9991                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
 9992                    selection.start = Point::new(cursor.row, current_indent.len);
 9993                    selection.end = selection.start;
 9994                    continue;
 9995                }
 9996            }
 9997
 9998            // Otherwise, insert a hard or soft tab.
 9999            let settings = buffer.language_settings_at(cursor, cx);
10000            let tab_size = if settings.hard_tabs {
10001                IndentSize::tab()
10002            } else {
10003                let tab_size = settings.tab_size.get();
10004                let indent_remainder = snapshot
10005                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10006                    .flat_map(str::chars)
10007                    .fold(row_delta % tab_size, |counter: u32, c| {
10008                        if c == '\t' {
10009                            0
10010                        } else {
10011                            (counter + 1) % tab_size
10012                        }
10013                    });
10014
10015                let chars_to_next_tab_stop = tab_size - indent_remainder;
10016                IndentSize::spaces(chars_to_next_tab_stop)
10017            };
10018            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10019            selection.end = selection.start;
10020            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10021            row_delta += tab_size.len;
10022        }
10023
10024        self.transact(window, cx, |this, window, cx| {
10025            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10026            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10027            this.refresh_edit_prediction(true, false, window, cx);
10028        });
10029    }
10030
10031    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10032        if self.read_only(cx) {
10033            return;
10034        }
10035        if self.mode.is_single_line() {
10036            cx.propagate();
10037            return;
10038        }
10039
10040        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10041        let mut selections = self.selections.all::<Point>(cx);
10042        let mut prev_edited_row = 0;
10043        let mut row_delta = 0;
10044        let mut edits = Vec::new();
10045        let buffer = self.buffer.read(cx);
10046        let snapshot = buffer.snapshot(cx);
10047        for selection in &mut selections {
10048            if selection.start.row != prev_edited_row {
10049                row_delta = 0;
10050            }
10051            prev_edited_row = selection.end.row;
10052
10053            row_delta =
10054                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10055        }
10056
10057        self.transact(window, cx, |this, window, cx| {
10058            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10059            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10060        });
10061    }
10062
10063    fn indent_selection(
10064        buffer: &MultiBuffer,
10065        snapshot: &MultiBufferSnapshot,
10066        selection: &mut Selection<Point>,
10067        edits: &mut Vec<(Range<Point>, String)>,
10068        delta_for_start_row: u32,
10069        cx: &App,
10070    ) -> u32 {
10071        let settings = buffer.language_settings_at(selection.start, cx);
10072        let tab_size = settings.tab_size.get();
10073        let indent_kind = if settings.hard_tabs {
10074            IndentKind::Tab
10075        } else {
10076            IndentKind::Space
10077        };
10078        let mut start_row = selection.start.row;
10079        let mut end_row = selection.end.row + 1;
10080
10081        // If a selection ends at the beginning of a line, don't indent
10082        // that last line.
10083        if selection.end.column == 0 && selection.end.row > selection.start.row {
10084            end_row -= 1;
10085        }
10086
10087        // Avoid re-indenting a row that has already been indented by a
10088        // previous selection, but still update this selection's column
10089        // to reflect that indentation.
10090        if delta_for_start_row > 0 {
10091            start_row += 1;
10092            selection.start.column += delta_for_start_row;
10093            if selection.end.row == selection.start.row {
10094                selection.end.column += delta_for_start_row;
10095            }
10096        }
10097
10098        let mut delta_for_end_row = 0;
10099        let has_multiple_rows = start_row + 1 != end_row;
10100        for row in start_row..end_row {
10101            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10102            let indent_delta = match (current_indent.kind, indent_kind) {
10103                (IndentKind::Space, IndentKind::Space) => {
10104                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10105                    IndentSize::spaces(columns_to_next_tab_stop)
10106                }
10107                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10108                (_, IndentKind::Tab) => IndentSize::tab(),
10109            };
10110
10111            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10112                0
10113            } else {
10114                selection.start.column
10115            };
10116            let row_start = Point::new(row, start);
10117            edits.push((
10118                row_start..row_start,
10119                indent_delta.chars().collect::<String>(),
10120            ));
10121
10122            // Update this selection's endpoints to reflect the indentation.
10123            if row == selection.start.row {
10124                selection.start.column += indent_delta.len;
10125            }
10126            if row == selection.end.row {
10127                selection.end.column += indent_delta.len;
10128                delta_for_end_row = indent_delta.len;
10129            }
10130        }
10131
10132        if selection.start.row == selection.end.row {
10133            delta_for_start_row + delta_for_end_row
10134        } else {
10135            delta_for_end_row
10136        }
10137    }
10138
10139    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10140        if self.read_only(cx) {
10141            return;
10142        }
10143        if self.mode.is_single_line() {
10144            cx.propagate();
10145            return;
10146        }
10147
10148        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10149        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10150        let selections = self.selections.all::<Point>(cx);
10151        let mut deletion_ranges = Vec::new();
10152        let mut last_outdent = None;
10153        {
10154            let buffer = self.buffer.read(cx);
10155            let snapshot = buffer.snapshot(cx);
10156            for selection in &selections {
10157                let settings = buffer.language_settings_at(selection.start, cx);
10158                let tab_size = settings.tab_size.get();
10159                let mut rows = selection.spanned_rows(false, &display_map);
10160
10161                // Avoid re-outdenting a row that has already been outdented by a
10162                // previous selection.
10163                if let Some(last_row) = last_outdent
10164                    && last_row == rows.start
10165                {
10166                    rows.start = rows.start.next_row();
10167                }
10168                let has_multiple_rows = rows.len() > 1;
10169                for row in rows.iter_rows() {
10170                    let indent_size = snapshot.indent_size_for_line(row);
10171                    if indent_size.len > 0 {
10172                        let deletion_len = match indent_size.kind {
10173                            IndentKind::Space => {
10174                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10175                                if columns_to_prev_tab_stop == 0 {
10176                                    tab_size
10177                                } else {
10178                                    columns_to_prev_tab_stop
10179                                }
10180                            }
10181                            IndentKind::Tab => 1,
10182                        };
10183                        let start = if has_multiple_rows
10184                            || deletion_len > selection.start.column
10185                            || indent_size.len < selection.start.column
10186                        {
10187                            0
10188                        } else {
10189                            selection.start.column - deletion_len
10190                        };
10191                        deletion_ranges.push(
10192                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10193                        );
10194                        last_outdent = Some(row);
10195                    }
10196                }
10197            }
10198        }
10199
10200        self.transact(window, cx, |this, window, cx| {
10201            this.buffer.update(cx, |buffer, cx| {
10202                let empty_str: Arc<str> = Arc::default();
10203                buffer.edit(
10204                    deletion_ranges
10205                        .into_iter()
10206                        .map(|range| (range, empty_str.clone())),
10207                    None,
10208                    cx,
10209                );
10210            });
10211            let selections = this.selections.all::<usize>(cx);
10212            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10213        });
10214    }
10215
10216    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10217        if self.read_only(cx) {
10218            return;
10219        }
10220        if self.mode.is_single_line() {
10221            cx.propagate();
10222            return;
10223        }
10224
10225        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10226        let selections = self
10227            .selections
10228            .all::<usize>(cx)
10229            .into_iter()
10230            .map(|s| s.range());
10231
10232        self.transact(window, cx, |this, window, cx| {
10233            this.buffer.update(cx, |buffer, cx| {
10234                buffer.autoindent_ranges(selections, cx);
10235            });
10236            let selections = this.selections.all::<usize>(cx);
10237            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10238        });
10239    }
10240
10241    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10242        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10243        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10244        let selections = self.selections.all::<Point>(cx);
10245
10246        let mut new_cursors = Vec::new();
10247        let mut edit_ranges = Vec::new();
10248        let mut selections = selections.iter().peekable();
10249        while let Some(selection) = selections.next() {
10250            let mut rows = selection.spanned_rows(false, &display_map);
10251            let goal_display_column = selection.head().to_display_point(&display_map).column();
10252
10253            // Accumulate contiguous regions of rows that we want to delete.
10254            while let Some(next_selection) = selections.peek() {
10255                let next_rows = next_selection.spanned_rows(false, &display_map);
10256                if next_rows.start <= rows.end {
10257                    rows.end = next_rows.end;
10258                    selections.next().unwrap();
10259                } else {
10260                    break;
10261                }
10262            }
10263
10264            let buffer = &display_map.buffer_snapshot;
10265            let mut edit_start = Point::new(rows.start.0, 0).to_offset(buffer);
10266            let edit_end;
10267            let cursor_buffer_row;
10268            if buffer.max_point().row >= rows.end.0 {
10269                // If there's a line after the range, delete the \n from the end of the row range
10270                // and position the cursor on the next line.
10271                edit_end = Point::new(rows.end.0, 0).to_offset(buffer);
10272                cursor_buffer_row = rows.end;
10273            } else {
10274                // If there isn't a line after the range, delete the \n from the line before the
10275                // start of the row range and position the cursor there.
10276                edit_start = edit_start.saturating_sub(1);
10277                edit_end = buffer.len();
10278                cursor_buffer_row = rows.start.previous_row();
10279            }
10280
10281            let mut cursor = Point::new(cursor_buffer_row.0, 0).to_display_point(&display_map);
10282            *cursor.column_mut() =
10283                cmp::min(goal_display_column, display_map.line_len(cursor.row()));
10284
10285            new_cursors.push((
10286                selection.id,
10287                buffer.anchor_after(cursor.to_point(&display_map)),
10288            ));
10289            edit_ranges.push(edit_start..edit_end);
10290        }
10291
10292        self.transact(window, cx, |this, window, cx| {
10293            let buffer = this.buffer.update(cx, |buffer, cx| {
10294                let empty_str: Arc<str> = Arc::default();
10295                buffer.edit(
10296                    edit_ranges
10297                        .into_iter()
10298                        .map(|range| (range, empty_str.clone())),
10299                    None,
10300                    cx,
10301                );
10302                buffer.snapshot(cx)
10303            });
10304            let new_selections = new_cursors
10305                .into_iter()
10306                .map(|(id, cursor)| {
10307                    let cursor = cursor.to_point(&buffer);
10308                    Selection {
10309                        id,
10310                        start: cursor,
10311                        end: cursor,
10312                        reversed: false,
10313                        goal: SelectionGoal::None,
10314                    }
10315                })
10316                .collect();
10317
10318            this.change_selections(Default::default(), window, cx, |s| {
10319                s.select(new_selections);
10320            });
10321        });
10322    }
10323
10324    pub fn join_lines_impl(
10325        &mut self,
10326        insert_whitespace: bool,
10327        window: &mut Window,
10328        cx: &mut Context<Self>,
10329    ) {
10330        if self.read_only(cx) {
10331            return;
10332        }
10333        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10334        for selection in self.selections.all::<Point>(cx) {
10335            let start = MultiBufferRow(selection.start.row);
10336            // Treat single line selections as if they include the next line. Otherwise this action
10337            // would do nothing for single line selections individual cursors.
10338            let end = if selection.start.row == selection.end.row {
10339                MultiBufferRow(selection.start.row + 1)
10340            } else {
10341                MultiBufferRow(selection.end.row)
10342            };
10343
10344            if let Some(last_row_range) = row_ranges.last_mut()
10345                && start <= last_row_range.end
10346            {
10347                last_row_range.end = end;
10348                continue;
10349            }
10350            row_ranges.push(start..end);
10351        }
10352
10353        let snapshot = self.buffer.read(cx).snapshot(cx);
10354        let mut cursor_positions = Vec::new();
10355        for row_range in &row_ranges {
10356            let anchor = snapshot.anchor_before(Point::new(
10357                row_range.end.previous_row().0,
10358                snapshot.line_len(row_range.end.previous_row()),
10359            ));
10360            cursor_positions.push(anchor..anchor);
10361        }
10362
10363        self.transact(window, cx, |this, window, cx| {
10364            for row_range in row_ranges.into_iter().rev() {
10365                for row in row_range.iter_rows().rev() {
10366                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10367                    let next_line_row = row.next_row();
10368                    let indent = snapshot.indent_size_for_line(next_line_row);
10369                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10370
10371                    let replace =
10372                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10373                            " "
10374                        } else {
10375                            ""
10376                        };
10377
10378                    this.buffer.update(cx, |buffer, cx| {
10379                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10380                    });
10381                }
10382            }
10383
10384            this.change_selections(Default::default(), window, cx, |s| {
10385                s.select_anchor_ranges(cursor_positions)
10386            });
10387        });
10388    }
10389
10390    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10391        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10392        self.join_lines_impl(true, window, cx);
10393    }
10394
10395    pub fn sort_lines_case_sensitive(
10396        &mut self,
10397        _: &SortLinesCaseSensitive,
10398        window: &mut Window,
10399        cx: &mut Context<Self>,
10400    ) {
10401        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10402    }
10403
10404    pub fn sort_lines_by_length(
10405        &mut self,
10406        _: &SortLinesByLength,
10407        window: &mut Window,
10408        cx: &mut Context<Self>,
10409    ) {
10410        self.manipulate_immutable_lines(window, cx, |lines| {
10411            lines.sort_by_key(|&line| line.chars().count())
10412        })
10413    }
10414
10415    pub fn sort_lines_case_insensitive(
10416        &mut self,
10417        _: &SortLinesCaseInsensitive,
10418        window: &mut Window,
10419        cx: &mut Context<Self>,
10420    ) {
10421        self.manipulate_immutable_lines(window, cx, |lines| {
10422            lines.sort_by_key(|line| line.to_lowercase())
10423        })
10424    }
10425
10426    pub fn unique_lines_case_insensitive(
10427        &mut self,
10428        _: &UniqueLinesCaseInsensitive,
10429        window: &mut Window,
10430        cx: &mut Context<Self>,
10431    ) {
10432        self.manipulate_immutable_lines(window, cx, |lines| {
10433            let mut seen = HashSet::default();
10434            lines.retain(|line| seen.insert(line.to_lowercase()));
10435        })
10436    }
10437
10438    pub fn unique_lines_case_sensitive(
10439        &mut self,
10440        _: &UniqueLinesCaseSensitive,
10441        window: &mut Window,
10442        cx: &mut Context<Self>,
10443    ) {
10444        self.manipulate_immutable_lines(window, cx, |lines| {
10445            let mut seen = HashSet::default();
10446            lines.retain(|line| seen.insert(*line));
10447        })
10448    }
10449
10450    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10451        let Some(project) = self.project.clone() else {
10452            return;
10453        };
10454        self.reload(project, window, cx)
10455            .detach_and_notify_err(window, cx);
10456    }
10457
10458    pub fn restore_file(
10459        &mut self,
10460        _: &::git::RestoreFile,
10461        window: &mut Window,
10462        cx: &mut Context<Self>,
10463    ) {
10464        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10465        let mut buffer_ids = HashSet::default();
10466        let snapshot = self.buffer().read(cx).snapshot(cx);
10467        for selection in self.selections.all::<usize>(cx) {
10468            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10469        }
10470
10471        let buffer = self.buffer().read(cx);
10472        let ranges = buffer_ids
10473            .into_iter()
10474            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10475            .collect::<Vec<_>>();
10476
10477        self.restore_hunks_in_ranges(ranges, window, cx);
10478    }
10479
10480    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10481        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10482        let selections = self
10483            .selections
10484            .all(cx)
10485            .into_iter()
10486            .map(|s| s.range())
10487            .collect();
10488        self.restore_hunks_in_ranges(selections, window, cx);
10489    }
10490
10491    pub fn restore_hunks_in_ranges(
10492        &mut self,
10493        ranges: Vec<Range<Point>>,
10494        window: &mut Window,
10495        cx: &mut Context<Editor>,
10496    ) {
10497        let mut revert_changes = HashMap::default();
10498        let chunk_by = self
10499            .snapshot(window, cx)
10500            .hunks_for_ranges(ranges)
10501            .into_iter()
10502            .chunk_by(|hunk| hunk.buffer_id);
10503        for (buffer_id, hunks) in &chunk_by {
10504            let hunks = hunks.collect::<Vec<_>>();
10505            for hunk in &hunks {
10506                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10507            }
10508            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10509        }
10510        drop(chunk_by);
10511        if !revert_changes.is_empty() {
10512            self.transact(window, cx, |editor, window, cx| {
10513                editor.restore(revert_changes, window, cx);
10514            });
10515        }
10516    }
10517
10518    pub fn open_active_item_in_terminal(
10519        &mut self,
10520        _: &OpenInTerminal,
10521        window: &mut Window,
10522        cx: &mut Context<Self>,
10523    ) {
10524        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10525            let project_path = buffer.read(cx).project_path(cx)?;
10526            let project = self.project()?.read(cx);
10527            let entry = project.entry_for_path(&project_path, cx)?;
10528            let parent = match &entry.canonical_path {
10529                Some(canonical_path) => canonical_path.to_path_buf(),
10530                None => project.absolute_path(&project_path, cx)?,
10531            }
10532            .parent()?
10533            .to_path_buf();
10534            Some(parent)
10535        }) {
10536            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10537        }
10538    }
10539
10540    fn set_breakpoint_context_menu(
10541        &mut self,
10542        display_row: DisplayRow,
10543        position: Option<Anchor>,
10544        clicked_point: gpui::Point<Pixels>,
10545        window: &mut Window,
10546        cx: &mut Context<Self>,
10547    ) {
10548        let source = self
10549            .buffer
10550            .read(cx)
10551            .snapshot(cx)
10552            .anchor_before(Point::new(display_row.0, 0u32));
10553
10554        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10555
10556        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10557            self,
10558            source,
10559            clicked_point,
10560            context_menu,
10561            window,
10562            cx,
10563        );
10564    }
10565
10566    fn add_edit_breakpoint_block(
10567        &mut self,
10568        anchor: Anchor,
10569        breakpoint: &Breakpoint,
10570        edit_action: BreakpointPromptEditAction,
10571        window: &mut Window,
10572        cx: &mut Context<Self>,
10573    ) {
10574        let weak_editor = cx.weak_entity();
10575        let bp_prompt = cx.new(|cx| {
10576            BreakpointPromptEditor::new(
10577                weak_editor,
10578                anchor,
10579                breakpoint.clone(),
10580                edit_action,
10581                window,
10582                cx,
10583            )
10584        });
10585
10586        let height = bp_prompt.update(cx, |this, cx| {
10587            this.prompt
10588                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10589        });
10590        let cloned_prompt = bp_prompt.clone();
10591        let blocks = vec![BlockProperties {
10592            style: BlockStyle::Sticky,
10593            placement: BlockPlacement::Above(anchor),
10594            height: Some(height),
10595            render: Arc::new(move |cx| {
10596                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10597                cloned_prompt.clone().into_any_element()
10598            }),
10599            priority: 0,
10600        }];
10601
10602        let focus_handle = bp_prompt.focus_handle(cx);
10603        window.focus(&focus_handle);
10604
10605        let block_ids = self.insert_blocks(blocks, None, cx);
10606        bp_prompt.update(cx, |prompt, _| {
10607            prompt.add_block_ids(block_ids);
10608        });
10609    }
10610
10611    pub(crate) fn breakpoint_at_row(
10612        &self,
10613        row: u32,
10614        window: &mut Window,
10615        cx: &mut Context<Self>,
10616    ) -> Option<(Anchor, Breakpoint)> {
10617        let snapshot = self.snapshot(window, cx);
10618        let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
10619
10620        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10621    }
10622
10623    pub(crate) fn breakpoint_at_anchor(
10624        &self,
10625        breakpoint_position: Anchor,
10626        snapshot: &EditorSnapshot,
10627        cx: &mut Context<Self>,
10628    ) -> Option<(Anchor, Breakpoint)> {
10629        let project = self.project.clone()?;
10630
10631        let buffer_id = breakpoint_position.buffer_id.or_else(|| {
10632            snapshot
10633                .buffer_snapshot
10634                .buffer_id_for_excerpt(breakpoint_position.excerpt_id)
10635        })?;
10636
10637        let enclosing_excerpt = breakpoint_position.excerpt_id;
10638        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
10639        let buffer_snapshot = buffer.read(cx).snapshot();
10640
10641        let row = buffer_snapshot
10642            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10643            .row;
10644
10645        let line_len = snapshot.buffer_snapshot.line_len(MultiBufferRow(row));
10646        let anchor_end = snapshot
10647            .buffer_snapshot
10648            .anchor_after(Point::new(row, line_len));
10649
10650        let bp = self
10651            .breakpoint_store
10652            .as_ref()?
10653            .read_with(cx, |breakpoint_store, cx| {
10654                breakpoint_store
10655                    .breakpoints(
10656                        &buffer,
10657                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10658                        &buffer_snapshot,
10659                        cx,
10660                    )
10661                    .next()
10662                    .and_then(|(bp, _)| {
10663                        let breakpoint_row = buffer_snapshot
10664                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10665                            .row;
10666
10667                        if breakpoint_row == row {
10668                            snapshot
10669                                .buffer_snapshot
10670                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10671                                .map(|position| (position, bp.bp.clone()))
10672                        } else {
10673                            None
10674                        }
10675                    })
10676            });
10677        bp
10678    }
10679
10680    pub fn edit_log_breakpoint(
10681        &mut self,
10682        _: &EditLogBreakpoint,
10683        window: &mut Window,
10684        cx: &mut Context<Self>,
10685    ) {
10686        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10687            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10688                message: None,
10689                state: BreakpointState::Enabled,
10690                condition: None,
10691                hit_condition: None,
10692            });
10693
10694            self.add_edit_breakpoint_block(
10695                anchor,
10696                &breakpoint,
10697                BreakpointPromptEditAction::Log,
10698                window,
10699                cx,
10700            );
10701        }
10702    }
10703
10704    fn breakpoints_at_cursors(
10705        &self,
10706        window: &mut Window,
10707        cx: &mut Context<Self>,
10708    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10709        let snapshot = self.snapshot(window, cx);
10710        let cursors = self
10711            .selections
10712            .disjoint_anchors()
10713            .into_iter()
10714            .map(|selection| {
10715                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
10716
10717                let breakpoint_position = self
10718                    .breakpoint_at_row(cursor_position.row, window, cx)
10719                    .map(|bp| bp.0)
10720                    .unwrap_or_else(|| {
10721                        snapshot
10722                            .display_snapshot
10723                            .buffer_snapshot
10724                            .anchor_after(Point::new(cursor_position.row, 0))
10725                    });
10726
10727                let breakpoint = self
10728                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10729                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10730
10731                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10732            })
10733            // 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.
10734            .collect::<HashMap<Anchor, _>>();
10735
10736        cursors.into_iter().collect()
10737    }
10738
10739    pub fn enable_breakpoint(
10740        &mut self,
10741        _: &crate::actions::EnableBreakpoint,
10742        window: &mut Window,
10743        cx: &mut Context<Self>,
10744    ) {
10745        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10746            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10747                continue;
10748            };
10749            self.edit_breakpoint_at_anchor(
10750                anchor,
10751                breakpoint,
10752                BreakpointEditAction::InvertState,
10753                cx,
10754            );
10755        }
10756    }
10757
10758    pub fn disable_breakpoint(
10759        &mut self,
10760        _: &crate::actions::DisableBreakpoint,
10761        window: &mut Window,
10762        cx: &mut Context<Self>,
10763    ) {
10764        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10765            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10766                continue;
10767            };
10768            self.edit_breakpoint_at_anchor(
10769                anchor,
10770                breakpoint,
10771                BreakpointEditAction::InvertState,
10772                cx,
10773            );
10774        }
10775    }
10776
10777    pub fn toggle_breakpoint(
10778        &mut self,
10779        _: &crate::actions::ToggleBreakpoint,
10780        window: &mut Window,
10781        cx: &mut Context<Self>,
10782    ) {
10783        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10784            if let Some(breakpoint) = breakpoint {
10785                self.edit_breakpoint_at_anchor(
10786                    anchor,
10787                    breakpoint,
10788                    BreakpointEditAction::Toggle,
10789                    cx,
10790                );
10791            } else {
10792                self.edit_breakpoint_at_anchor(
10793                    anchor,
10794                    Breakpoint::new_standard(),
10795                    BreakpointEditAction::Toggle,
10796                    cx,
10797                );
10798            }
10799        }
10800    }
10801
10802    pub fn edit_breakpoint_at_anchor(
10803        &mut self,
10804        breakpoint_position: Anchor,
10805        breakpoint: Breakpoint,
10806        edit_action: BreakpointEditAction,
10807        cx: &mut Context<Self>,
10808    ) {
10809        let Some(breakpoint_store) = &self.breakpoint_store else {
10810            return;
10811        };
10812
10813        let Some(buffer_id) = breakpoint_position.buffer_id.or_else(|| {
10814            if breakpoint_position == Anchor::min() {
10815                self.buffer()
10816                    .read(cx)
10817                    .excerpt_buffer_ids()
10818                    .into_iter()
10819                    .next()
10820            } else {
10821                None
10822            }
10823        }) else {
10824            return;
10825        };
10826
10827        let Some(buffer) = self.buffer().read(cx).buffer(buffer_id) else {
10828            return;
10829        };
10830
10831        breakpoint_store.update(cx, |breakpoint_store, cx| {
10832            breakpoint_store.toggle_breakpoint(
10833                buffer,
10834                BreakpointWithPosition {
10835                    position: breakpoint_position.text_anchor,
10836                    bp: breakpoint,
10837                },
10838                edit_action,
10839                cx,
10840            );
10841        });
10842
10843        cx.notify();
10844    }
10845
10846    #[cfg(any(test, feature = "test-support"))]
10847    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
10848        self.breakpoint_store.clone()
10849    }
10850
10851    pub fn prepare_restore_change(
10852        &self,
10853        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
10854        hunk: &MultiBufferDiffHunk,
10855        cx: &mut App,
10856    ) -> Option<()> {
10857        if hunk.is_created_file() {
10858            return None;
10859        }
10860        let buffer = self.buffer.read(cx);
10861        let diff = buffer.diff_for(hunk.buffer_id)?;
10862        let buffer = buffer.buffer(hunk.buffer_id)?;
10863        let buffer = buffer.read(cx);
10864        let original_text = diff
10865            .read(cx)
10866            .base_text()
10867            .as_rope()
10868            .slice(hunk.diff_base_byte_range.clone());
10869        let buffer_snapshot = buffer.snapshot();
10870        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
10871        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
10872            probe
10873                .0
10874                .start
10875                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
10876                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
10877        }) {
10878            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
10879            Some(())
10880        } else {
10881            None
10882        }
10883    }
10884
10885    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
10886        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
10887    }
10888
10889    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
10890        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut thread_rng()))
10891    }
10892
10893    fn manipulate_lines<M>(
10894        &mut self,
10895        window: &mut Window,
10896        cx: &mut Context<Self>,
10897        mut manipulate: M,
10898    ) where
10899        M: FnMut(&str) -> LineManipulationResult,
10900    {
10901        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10902
10903        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10904        let buffer = self.buffer.read(cx).snapshot(cx);
10905
10906        let mut edits = Vec::new();
10907
10908        let selections = self.selections.all::<Point>(cx);
10909        let mut selections = selections.iter().peekable();
10910        let mut contiguous_row_selections = Vec::new();
10911        let mut new_selections = Vec::new();
10912        let mut added_lines = 0;
10913        let mut removed_lines = 0;
10914
10915        while let Some(selection) = selections.next() {
10916            let (start_row, end_row) = consume_contiguous_rows(
10917                &mut contiguous_row_selections,
10918                selection,
10919                &display_map,
10920                &mut selections,
10921            );
10922
10923            let start_point = Point::new(start_row.0, 0);
10924            let end_point = Point::new(
10925                end_row.previous_row().0,
10926                buffer.line_len(end_row.previous_row()),
10927            );
10928            let text = buffer
10929                .text_for_range(start_point..end_point)
10930                .collect::<String>();
10931
10932            let LineManipulationResult {
10933                new_text,
10934                line_count_before,
10935                line_count_after,
10936            } = manipulate(&text);
10937
10938            edits.push((start_point..end_point, new_text));
10939
10940            // Selections must change based on added and removed line count
10941            let start_row =
10942                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
10943            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
10944            new_selections.push(Selection {
10945                id: selection.id,
10946                start: start_row,
10947                end: end_row,
10948                goal: SelectionGoal::None,
10949                reversed: selection.reversed,
10950            });
10951
10952            if line_count_after > line_count_before {
10953                added_lines += line_count_after - line_count_before;
10954            } else if line_count_before > line_count_after {
10955                removed_lines += line_count_before - line_count_after;
10956            }
10957        }
10958
10959        self.transact(window, cx, |this, window, cx| {
10960            let buffer = this.buffer.update(cx, |buffer, cx| {
10961                buffer.edit(edits, None, cx);
10962                buffer.snapshot(cx)
10963            });
10964
10965            // Recalculate offsets on newly edited buffer
10966            let new_selections = new_selections
10967                .iter()
10968                .map(|s| {
10969                    let start_point = Point::new(s.start.0, 0);
10970                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
10971                    Selection {
10972                        id: s.id,
10973                        start: buffer.point_to_offset(start_point),
10974                        end: buffer.point_to_offset(end_point),
10975                        goal: s.goal,
10976                        reversed: s.reversed,
10977                    }
10978                })
10979                .collect();
10980
10981            this.change_selections(Default::default(), window, cx, |s| {
10982                s.select(new_selections);
10983            });
10984
10985            this.request_autoscroll(Autoscroll::fit(), cx);
10986        });
10987    }
10988
10989    fn manipulate_immutable_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<&str>),
10996    {
10997        self.manipulate_lines(window, cx, |text| {
10998            let mut lines: Vec<&str> = text.split('\n').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    fn manipulate_mutable_lines<Fn>(
11012        &mut self,
11013        window: &mut Window,
11014        cx: &mut Context<Self>,
11015        mut callback: Fn,
11016    ) where
11017        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11018    {
11019        self.manipulate_lines(window, cx, |text| {
11020            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11021            let line_count_before = lines.len();
11022
11023            callback(&mut lines);
11024
11025            LineManipulationResult {
11026                new_text: lines.join("\n"),
11027                line_count_before,
11028                line_count_after: lines.len(),
11029            }
11030        });
11031    }
11032
11033    pub fn convert_indentation_to_spaces(
11034        &mut self,
11035        _: &ConvertIndentationToSpaces,
11036        window: &mut Window,
11037        cx: &mut Context<Self>,
11038    ) {
11039        let settings = self.buffer.read(cx).language_settings(cx);
11040        let tab_size = settings.tab_size.get() as usize;
11041
11042        self.manipulate_mutable_lines(window, cx, |lines| {
11043            // Allocates a reasonably sized scratch buffer once for the whole loop
11044            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11045            // Avoids recomputing spaces that could be inserted many times
11046            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11047                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11048                .collect();
11049
11050            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11051                let mut chars = line.as_ref().chars();
11052                let mut col = 0;
11053                let mut changed = false;
11054
11055                while let Some(ch) = chars.next() {
11056                    match ch {
11057                        ' ' => {
11058                            reindented_line.push(' ');
11059                            col += 1;
11060                        }
11061                        '\t' => {
11062                            // \t are converted to spaces depending on the current column
11063                            let spaces_len = tab_size - (col % tab_size);
11064                            reindented_line.extend(&space_cache[spaces_len - 1]);
11065                            col += spaces_len;
11066                            changed = true;
11067                        }
11068                        _ => {
11069                            // If we dont append before break, the character is consumed
11070                            reindented_line.push(ch);
11071                            break;
11072                        }
11073                    }
11074                }
11075
11076                if !changed {
11077                    reindented_line.clear();
11078                    continue;
11079                }
11080                // Append the rest of the line and replace old reference with new one
11081                reindented_line.extend(chars);
11082                *line = Cow::Owned(reindented_line.clone());
11083                reindented_line.clear();
11084            }
11085        });
11086    }
11087
11088    pub fn convert_indentation_to_tabs(
11089        &mut self,
11090        _: &ConvertIndentationToTabs,
11091        window: &mut Window,
11092        cx: &mut Context<Self>,
11093    ) {
11094        let settings = self.buffer.read(cx).language_settings(cx);
11095        let tab_size = settings.tab_size.get() as usize;
11096
11097        self.manipulate_mutable_lines(window, cx, |lines| {
11098            // Allocates a reasonably sized buffer once for the whole loop
11099            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11100            // Avoids recomputing spaces that could be inserted many times
11101            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11102                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11103                .collect();
11104
11105            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11106                let mut chars = line.chars();
11107                let mut spaces_count = 0;
11108                let mut first_non_indent_char = None;
11109                let mut changed = false;
11110
11111                while let Some(ch) = chars.next() {
11112                    match ch {
11113                        ' ' => {
11114                            // Keep track of spaces. Append \t when we reach tab_size
11115                            spaces_count += 1;
11116                            changed = true;
11117                            if spaces_count == tab_size {
11118                                reindented_line.push('\t');
11119                                spaces_count = 0;
11120                            }
11121                        }
11122                        '\t' => {
11123                            reindented_line.push('\t');
11124                            spaces_count = 0;
11125                        }
11126                        _ => {
11127                            // Dont append it yet, we might have remaining spaces
11128                            first_non_indent_char = Some(ch);
11129                            break;
11130                        }
11131                    }
11132                }
11133
11134                if !changed {
11135                    reindented_line.clear();
11136                    continue;
11137                }
11138                // Remaining spaces that didn't make a full tab stop
11139                if spaces_count > 0 {
11140                    reindented_line.extend(&space_cache[spaces_count - 1]);
11141                }
11142                // If we consume an extra character that was not indentation, add it back
11143                if let Some(extra_char) = first_non_indent_char {
11144                    reindented_line.push(extra_char);
11145                }
11146                // Append the rest of the line and replace old reference with new one
11147                reindented_line.extend(chars);
11148                *line = Cow::Owned(reindented_line.clone());
11149                reindented_line.clear();
11150            }
11151        });
11152    }
11153
11154    pub fn convert_to_upper_case(
11155        &mut self,
11156        _: &ConvertToUpperCase,
11157        window: &mut Window,
11158        cx: &mut Context<Self>,
11159    ) {
11160        self.manipulate_text(window, cx, |text| text.to_uppercase())
11161    }
11162
11163    pub fn convert_to_lower_case(
11164        &mut self,
11165        _: &ConvertToLowerCase,
11166        window: &mut Window,
11167        cx: &mut Context<Self>,
11168    ) {
11169        self.manipulate_text(window, cx, |text| text.to_lowercase())
11170    }
11171
11172    pub fn convert_to_title_case(
11173        &mut self,
11174        _: &ConvertToTitleCase,
11175        window: &mut Window,
11176        cx: &mut Context<Self>,
11177    ) {
11178        self.manipulate_text(window, cx, |text| {
11179            text.split('\n')
11180                .map(|line| line.to_case(Case::Title))
11181                .join("\n")
11182        })
11183    }
11184
11185    pub fn convert_to_snake_case(
11186        &mut self,
11187        _: &ConvertToSnakeCase,
11188        window: &mut Window,
11189        cx: &mut Context<Self>,
11190    ) {
11191        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11192    }
11193
11194    pub fn convert_to_kebab_case(
11195        &mut self,
11196        _: &ConvertToKebabCase,
11197        window: &mut Window,
11198        cx: &mut Context<Self>,
11199    ) {
11200        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11201    }
11202
11203    pub fn convert_to_upper_camel_case(
11204        &mut self,
11205        _: &ConvertToUpperCamelCase,
11206        window: &mut Window,
11207        cx: &mut Context<Self>,
11208    ) {
11209        self.manipulate_text(window, cx, |text| {
11210            text.split('\n')
11211                .map(|line| line.to_case(Case::UpperCamel))
11212                .join("\n")
11213        })
11214    }
11215
11216    pub fn convert_to_lower_camel_case(
11217        &mut self,
11218        _: &ConvertToLowerCamelCase,
11219        window: &mut Window,
11220        cx: &mut Context<Self>,
11221    ) {
11222        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11223    }
11224
11225    pub fn convert_to_opposite_case(
11226        &mut self,
11227        _: &ConvertToOppositeCase,
11228        window: &mut Window,
11229        cx: &mut Context<Self>,
11230    ) {
11231        self.manipulate_text(window, cx, |text| {
11232            text.chars()
11233                .fold(String::with_capacity(text.len()), |mut t, c| {
11234                    if c.is_uppercase() {
11235                        t.extend(c.to_lowercase());
11236                    } else {
11237                        t.extend(c.to_uppercase());
11238                    }
11239                    t
11240                })
11241        })
11242    }
11243
11244    pub fn convert_to_sentence_case(
11245        &mut self,
11246        _: &ConvertToSentenceCase,
11247        window: &mut Window,
11248        cx: &mut Context<Self>,
11249    ) {
11250        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11251    }
11252
11253    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11254        self.manipulate_text(window, cx, |text| {
11255            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11256            if has_upper_case_characters {
11257                text.to_lowercase()
11258            } else {
11259                text.to_uppercase()
11260            }
11261        })
11262    }
11263
11264    pub fn convert_to_rot13(
11265        &mut self,
11266        _: &ConvertToRot13,
11267        window: &mut Window,
11268        cx: &mut Context<Self>,
11269    ) {
11270        self.manipulate_text(window, cx, |text| {
11271            text.chars()
11272                .map(|c| match c {
11273                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11274                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11275                    _ => c,
11276                })
11277                .collect()
11278        })
11279    }
11280
11281    pub fn convert_to_rot47(
11282        &mut self,
11283        _: &ConvertToRot47,
11284        window: &mut Window,
11285        cx: &mut Context<Self>,
11286    ) {
11287        self.manipulate_text(window, cx, |text| {
11288            text.chars()
11289                .map(|c| {
11290                    let code_point = c as u32;
11291                    if code_point >= 33 && code_point <= 126 {
11292                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11293                    }
11294                    c
11295                })
11296                .collect()
11297        })
11298    }
11299
11300    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11301    where
11302        Fn: FnMut(&str) -> String,
11303    {
11304        let buffer = self.buffer.read(cx).snapshot(cx);
11305
11306        let mut new_selections = Vec::new();
11307        let mut edits = Vec::new();
11308        let mut selection_adjustment = 0i32;
11309
11310        for selection in self.selections.all::<usize>(cx) {
11311            let selection_is_empty = selection.is_empty();
11312
11313            let (start, end) = if selection_is_empty {
11314                let (word_range, _) = buffer.surrounding_word(selection.start, false);
11315                (word_range.start, word_range.end)
11316            } else {
11317                (selection.start, selection.end)
11318            };
11319
11320            let text = buffer.text_for_range(start..end).collect::<String>();
11321            let old_length = text.len() as i32;
11322            let text = callback(&text);
11323
11324            new_selections.push(Selection {
11325                start: (start as i32 - selection_adjustment) as usize,
11326                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11327                goal: SelectionGoal::None,
11328                ..selection
11329            });
11330
11331            selection_adjustment += old_length - text.len() as i32;
11332
11333            edits.push((start..end, text));
11334        }
11335
11336        self.transact(window, cx, |this, window, cx| {
11337            this.buffer.update(cx, |buffer, cx| {
11338                buffer.edit(edits, None, cx);
11339            });
11340
11341            this.change_selections(Default::default(), window, cx, |s| {
11342                s.select(new_selections);
11343            });
11344
11345            this.request_autoscroll(Autoscroll::fit(), cx);
11346        });
11347    }
11348
11349    pub fn move_selection_on_drop(
11350        &mut self,
11351        selection: &Selection<Anchor>,
11352        target: DisplayPoint,
11353        is_cut: bool,
11354        window: &mut Window,
11355        cx: &mut Context<Self>,
11356    ) {
11357        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11358        let buffer = &display_map.buffer_snapshot;
11359        let mut edits = Vec::new();
11360        let insert_point = display_map
11361            .clip_point(target, Bias::Left)
11362            .to_point(&display_map);
11363        let text = buffer
11364            .text_for_range(selection.start..selection.end)
11365            .collect::<String>();
11366        if is_cut {
11367            edits.push(((selection.start..selection.end), String::new()));
11368        }
11369        let insert_anchor = buffer.anchor_before(insert_point);
11370        edits.push(((insert_anchor..insert_anchor), text));
11371        let last_edit_start = insert_anchor.bias_left(buffer);
11372        let last_edit_end = insert_anchor.bias_right(buffer);
11373        self.transact(window, cx, |this, window, cx| {
11374            this.buffer.update(cx, |buffer, cx| {
11375                buffer.edit(edits, None, cx);
11376            });
11377            this.change_selections(Default::default(), window, cx, |s| {
11378                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11379            });
11380        });
11381    }
11382
11383    pub fn clear_selection_drag_state(&mut self) {
11384        self.selection_drag_state = SelectionDragState::None;
11385    }
11386
11387    pub fn duplicate(
11388        &mut self,
11389        upwards: bool,
11390        whole_lines: bool,
11391        window: &mut Window,
11392        cx: &mut Context<Self>,
11393    ) {
11394        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11395
11396        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11397        let buffer = &display_map.buffer_snapshot;
11398        let selections = self.selections.all::<Point>(cx);
11399
11400        let mut edits = Vec::new();
11401        let mut selections_iter = selections.iter().peekable();
11402        while let Some(selection) = selections_iter.next() {
11403            let mut rows = selection.spanned_rows(false, &display_map);
11404            // duplicate line-wise
11405            if whole_lines || selection.start == selection.end {
11406                // Avoid duplicating the same lines twice.
11407                while let Some(next_selection) = selections_iter.peek() {
11408                    let next_rows = next_selection.spanned_rows(false, &display_map);
11409                    if next_rows.start < rows.end {
11410                        rows.end = next_rows.end;
11411                        selections_iter.next().unwrap();
11412                    } else {
11413                        break;
11414                    }
11415                }
11416
11417                // Copy the text from the selected row region and splice it either at the start
11418                // or end of the region.
11419                let start = Point::new(rows.start.0, 0);
11420                let end = Point::new(
11421                    rows.end.previous_row().0,
11422                    buffer.line_len(rows.end.previous_row()),
11423                );
11424                let text = buffer
11425                    .text_for_range(start..end)
11426                    .chain(Some("\n"))
11427                    .collect::<String>();
11428                let insert_location = if upwards {
11429                    Point::new(rows.end.0, 0)
11430                } else {
11431                    start
11432                };
11433                edits.push((insert_location..insert_location, text));
11434            } else {
11435                // duplicate character-wise
11436                let start = selection.start;
11437                let end = selection.end;
11438                let text = buffer.text_for_range(start..end).collect::<String>();
11439                edits.push((selection.end..selection.end, text));
11440            }
11441        }
11442
11443        self.transact(window, cx, |this, _, cx| {
11444            this.buffer.update(cx, |buffer, cx| {
11445                buffer.edit(edits, None, cx);
11446            });
11447
11448            this.request_autoscroll(Autoscroll::fit(), cx);
11449        });
11450    }
11451
11452    pub fn duplicate_line_up(
11453        &mut self,
11454        _: &DuplicateLineUp,
11455        window: &mut Window,
11456        cx: &mut Context<Self>,
11457    ) {
11458        self.duplicate(true, true, window, cx);
11459    }
11460
11461    pub fn duplicate_line_down(
11462        &mut self,
11463        _: &DuplicateLineDown,
11464        window: &mut Window,
11465        cx: &mut Context<Self>,
11466    ) {
11467        self.duplicate(false, true, window, cx);
11468    }
11469
11470    pub fn duplicate_selection(
11471        &mut self,
11472        _: &DuplicateSelection,
11473        window: &mut Window,
11474        cx: &mut Context<Self>,
11475    ) {
11476        self.duplicate(false, false, window, cx);
11477    }
11478
11479    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11480        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11481        if self.mode.is_single_line() {
11482            cx.propagate();
11483            return;
11484        }
11485
11486        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11487        let buffer = self.buffer.read(cx).snapshot(cx);
11488
11489        let mut edits = Vec::new();
11490        let mut unfold_ranges = Vec::new();
11491        let mut refold_creases = Vec::new();
11492
11493        let selections = self.selections.all::<Point>(cx);
11494        let mut selections = selections.iter().peekable();
11495        let mut contiguous_row_selections = Vec::new();
11496        let mut new_selections = Vec::new();
11497
11498        while let Some(selection) = selections.next() {
11499            // Find all the selections that span a contiguous row range
11500            let (start_row, end_row) = consume_contiguous_rows(
11501                &mut contiguous_row_selections,
11502                selection,
11503                &display_map,
11504                &mut selections,
11505            );
11506
11507            // Move the text spanned by the row range to be before the line preceding the row range
11508            if start_row.0 > 0 {
11509                let range_to_move = Point::new(
11510                    start_row.previous_row().0,
11511                    buffer.line_len(start_row.previous_row()),
11512                )
11513                    ..Point::new(
11514                        end_row.previous_row().0,
11515                        buffer.line_len(end_row.previous_row()),
11516                    );
11517                let insertion_point = display_map
11518                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11519                    .0;
11520
11521                // Don't move lines across excerpts
11522                if buffer
11523                    .excerpt_containing(insertion_point..range_to_move.end)
11524                    .is_some()
11525                {
11526                    let text = buffer
11527                        .text_for_range(range_to_move.clone())
11528                        .flat_map(|s| s.chars())
11529                        .skip(1)
11530                        .chain(['\n'])
11531                        .collect::<String>();
11532
11533                    edits.push((
11534                        buffer.anchor_after(range_to_move.start)
11535                            ..buffer.anchor_before(range_to_move.end),
11536                        String::new(),
11537                    ));
11538                    let insertion_anchor = buffer.anchor_after(insertion_point);
11539                    edits.push((insertion_anchor..insertion_anchor, text));
11540
11541                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11542
11543                    // Move selections up
11544                    new_selections.extend(contiguous_row_selections.drain(..).map(
11545                        |mut selection| {
11546                            selection.start.row -= row_delta;
11547                            selection.end.row -= row_delta;
11548                            selection
11549                        },
11550                    ));
11551
11552                    // Move folds up
11553                    unfold_ranges.push(range_to_move.clone());
11554                    for fold in display_map.folds_in_range(
11555                        buffer.anchor_before(range_to_move.start)
11556                            ..buffer.anchor_after(range_to_move.end),
11557                    ) {
11558                        let mut start = fold.range.start.to_point(&buffer);
11559                        let mut end = fold.range.end.to_point(&buffer);
11560                        start.row -= row_delta;
11561                        end.row -= row_delta;
11562                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11563                    }
11564                }
11565            }
11566
11567            // If we didn't move line(s), preserve the existing selections
11568            new_selections.append(&mut contiguous_row_selections);
11569        }
11570
11571        self.transact(window, cx, |this, window, cx| {
11572            this.unfold_ranges(&unfold_ranges, true, true, cx);
11573            this.buffer.update(cx, |buffer, cx| {
11574                for (range, text) in edits {
11575                    buffer.edit([(range, text)], None, cx);
11576                }
11577            });
11578            this.fold_creases(refold_creases, true, window, cx);
11579            this.change_selections(Default::default(), window, cx, |s| {
11580                s.select(new_selections);
11581            })
11582        });
11583    }
11584
11585    pub fn move_line_down(
11586        &mut self,
11587        _: &MoveLineDown,
11588        window: &mut Window,
11589        cx: &mut Context<Self>,
11590    ) {
11591        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11592        if self.mode.is_single_line() {
11593            cx.propagate();
11594            return;
11595        }
11596
11597        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11598        let buffer = self.buffer.read(cx).snapshot(cx);
11599
11600        let mut edits = Vec::new();
11601        let mut unfold_ranges = Vec::new();
11602        let mut refold_creases = Vec::new();
11603
11604        let selections = self.selections.all::<Point>(cx);
11605        let mut selections = selections.iter().peekable();
11606        let mut contiguous_row_selections = Vec::new();
11607        let mut new_selections = Vec::new();
11608
11609        while let Some(selection) = selections.next() {
11610            // Find all the selections that span a contiguous row range
11611            let (start_row, end_row) = consume_contiguous_rows(
11612                &mut contiguous_row_selections,
11613                selection,
11614                &display_map,
11615                &mut selections,
11616            );
11617
11618            // Move the text spanned by the row range to be after the last line of the row range
11619            if end_row.0 <= buffer.max_point().row {
11620                let range_to_move =
11621                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11622                let insertion_point = display_map
11623                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11624                    .0;
11625
11626                // Don't move lines across excerpt boundaries
11627                if buffer
11628                    .excerpt_containing(range_to_move.start..insertion_point)
11629                    .is_some()
11630                {
11631                    let mut text = String::from("\n");
11632                    text.extend(buffer.text_for_range(range_to_move.clone()));
11633                    text.pop(); // Drop trailing newline
11634                    edits.push((
11635                        buffer.anchor_after(range_to_move.start)
11636                            ..buffer.anchor_before(range_to_move.end),
11637                        String::new(),
11638                    ));
11639                    let insertion_anchor = buffer.anchor_after(insertion_point);
11640                    edits.push((insertion_anchor..insertion_anchor, text));
11641
11642                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11643
11644                    // Move selections down
11645                    new_selections.extend(contiguous_row_selections.drain(..).map(
11646                        |mut selection| {
11647                            selection.start.row += row_delta;
11648                            selection.end.row += row_delta;
11649                            selection
11650                        },
11651                    ));
11652
11653                    // Move folds down
11654                    unfold_ranges.push(range_to_move.clone());
11655                    for fold in display_map.folds_in_range(
11656                        buffer.anchor_before(range_to_move.start)
11657                            ..buffer.anchor_after(range_to_move.end),
11658                    ) {
11659                        let mut start = fold.range.start.to_point(&buffer);
11660                        let mut end = fold.range.end.to_point(&buffer);
11661                        start.row += row_delta;
11662                        end.row += row_delta;
11663                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11664                    }
11665                }
11666            }
11667
11668            // If we didn't move line(s), preserve the existing selections
11669            new_selections.append(&mut contiguous_row_selections);
11670        }
11671
11672        self.transact(window, cx, |this, window, cx| {
11673            this.unfold_ranges(&unfold_ranges, true, true, cx);
11674            this.buffer.update(cx, |buffer, cx| {
11675                for (range, text) in edits {
11676                    buffer.edit([(range, text)], None, cx);
11677                }
11678            });
11679            this.fold_creases(refold_creases, true, window, cx);
11680            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11681        });
11682    }
11683
11684    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11685        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11686        let text_layout_details = &self.text_layout_details(window);
11687        self.transact(window, cx, |this, window, cx| {
11688            let edits = this.change_selections(Default::default(), window, cx, |s| {
11689                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11690                s.move_with(|display_map, selection| {
11691                    if !selection.is_empty() {
11692                        return;
11693                    }
11694
11695                    let mut head = selection.head();
11696                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11697                    if head.column() == display_map.line_len(head.row()) {
11698                        transpose_offset = display_map
11699                            .buffer_snapshot
11700                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11701                    }
11702
11703                    if transpose_offset == 0 {
11704                        return;
11705                    }
11706
11707                    *head.column_mut() += 1;
11708                    head = display_map.clip_point(head, Bias::Right);
11709                    let goal = SelectionGoal::HorizontalPosition(
11710                        display_map
11711                            .x_for_display_point(head, text_layout_details)
11712                            .into(),
11713                    );
11714                    selection.collapse_to(head, goal);
11715
11716                    let transpose_start = display_map
11717                        .buffer_snapshot
11718                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11719                    if edits.last().map_or(true, |e| e.0.end <= transpose_start) {
11720                        let transpose_end = display_map
11721                            .buffer_snapshot
11722                            .clip_offset(transpose_offset + 1, Bias::Right);
11723                        if let Some(ch) =
11724                            display_map.buffer_snapshot.chars_at(transpose_start).next()
11725                        {
11726                            edits.push((transpose_start..transpose_offset, String::new()));
11727                            edits.push((transpose_end..transpose_end, ch.to_string()));
11728                        }
11729                    }
11730                });
11731                edits
11732            });
11733            this.buffer
11734                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11735            let selections = this.selections.all::<usize>(cx);
11736            this.change_selections(Default::default(), window, cx, |s| {
11737                s.select(selections);
11738            });
11739        });
11740    }
11741
11742    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11743        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11744        if self.mode.is_single_line() {
11745            cx.propagate();
11746            return;
11747        }
11748
11749        self.rewrap_impl(RewrapOptions::default(), cx)
11750    }
11751
11752    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11753        let buffer = self.buffer.read(cx).snapshot(cx);
11754        let selections = self.selections.all::<Point>(cx);
11755
11756        // Split selections to respect paragraph, indent, and comment prefix boundaries.
11757        let wrap_ranges = selections.into_iter().flat_map(|selection| {
11758            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
11759                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
11760                .peekable();
11761
11762            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
11763                row
11764            } else {
11765                return Vec::new();
11766            };
11767
11768            let language_settings = buffer.language_settings_at(selection.head(), cx);
11769            let language_scope = buffer.language_scope_at(selection.head());
11770
11771            let indent_and_prefix_for_row =
11772                |row: u32| -> (IndentSize, Option<String>, Option<String>) {
11773                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
11774                    let (comment_prefix, rewrap_prefix) =
11775                        if let Some(language_scope) = &language_scope {
11776                            let indent_end = Point::new(row, indent.len);
11777                            let comment_prefix = language_scope
11778                                .line_comment_prefixes()
11779                                .iter()
11780                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
11781                                .map(|prefix| prefix.to_string());
11782                            let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11783                            let line_text_after_indent = buffer
11784                                .text_for_range(indent_end..line_end)
11785                                .collect::<String>();
11786                            let rewrap_prefix = language_scope
11787                                .rewrap_prefixes()
11788                                .iter()
11789                                .find_map(|prefix_regex| {
11790                                    prefix_regex.find(&line_text_after_indent).map(|mat| {
11791                                        if mat.start() == 0 {
11792                                            Some(mat.as_str().to_string())
11793                                        } else {
11794                                            None
11795                                        }
11796                                    })
11797                                })
11798                                .flatten();
11799                            (comment_prefix, rewrap_prefix)
11800                        } else {
11801                            (None, None)
11802                        };
11803                    (indent, comment_prefix, rewrap_prefix)
11804                };
11805
11806            let mut ranges = Vec::new();
11807            let from_empty_selection = selection.is_empty();
11808
11809            let mut current_range_start = first_row;
11810            let mut prev_row = first_row;
11811            let (
11812                mut current_range_indent,
11813                mut current_range_comment_prefix,
11814                mut current_range_rewrap_prefix,
11815            ) = indent_and_prefix_for_row(first_row);
11816
11817            for row in non_blank_rows_iter.skip(1) {
11818                let has_paragraph_break = row > prev_row + 1;
11819
11820                let (row_indent, row_comment_prefix, row_rewrap_prefix) =
11821                    indent_and_prefix_for_row(row);
11822
11823                let has_indent_change = row_indent != current_range_indent;
11824                let has_comment_change = row_comment_prefix != current_range_comment_prefix;
11825
11826                let has_boundary_change = has_comment_change
11827                    || row_rewrap_prefix.is_some()
11828                    || (has_indent_change && current_range_comment_prefix.is_some());
11829
11830                if has_paragraph_break || has_boundary_change {
11831                    ranges.push((
11832                        language_settings.clone(),
11833                        Point::new(current_range_start, 0)
11834                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11835                        current_range_indent,
11836                        current_range_comment_prefix.clone(),
11837                        current_range_rewrap_prefix.clone(),
11838                        from_empty_selection,
11839                    ));
11840                    current_range_start = row;
11841                    current_range_indent = row_indent;
11842                    current_range_comment_prefix = row_comment_prefix;
11843                    current_range_rewrap_prefix = row_rewrap_prefix;
11844                }
11845                prev_row = row;
11846            }
11847
11848            ranges.push((
11849                language_settings.clone(),
11850                Point::new(current_range_start, 0)
11851                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
11852                current_range_indent,
11853                current_range_comment_prefix,
11854                current_range_rewrap_prefix,
11855                from_empty_selection,
11856            ));
11857
11858            ranges
11859        });
11860
11861        let mut edits = Vec::new();
11862        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
11863
11864        for (
11865            language_settings,
11866            wrap_range,
11867            indent_size,
11868            comment_prefix,
11869            rewrap_prefix,
11870            from_empty_selection,
11871        ) in wrap_ranges
11872        {
11873            let mut start_row = wrap_range.start.row;
11874            let mut end_row = wrap_range.end.row;
11875
11876            // Skip selections that overlap with a range that has already been rewrapped.
11877            let selection_range = start_row..end_row;
11878            if rewrapped_row_ranges
11879                .iter()
11880                .any(|range| range.overlaps(&selection_range))
11881            {
11882                continue;
11883            }
11884
11885            let tab_size = language_settings.tab_size;
11886
11887            let indent_prefix = indent_size.chars().collect::<String>();
11888            let mut line_prefix = indent_prefix.clone();
11889            let mut inside_comment = false;
11890            if let Some(prefix) = &comment_prefix {
11891                line_prefix.push_str(prefix);
11892                inside_comment = true;
11893            }
11894            if let Some(prefix) = &rewrap_prefix {
11895                line_prefix.push_str(prefix);
11896            }
11897
11898            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
11899                RewrapBehavior::InComments => inside_comment,
11900                RewrapBehavior::InSelections => !wrap_range.is_empty(),
11901                RewrapBehavior::Anywhere => true,
11902            };
11903
11904            let should_rewrap = options.override_language_settings
11905                || allow_rewrap_based_on_language
11906                || self.hard_wrap.is_some();
11907            if !should_rewrap {
11908                continue;
11909            }
11910
11911            if from_empty_selection {
11912                'expand_upwards: while start_row > 0 {
11913                    let prev_row = start_row - 1;
11914                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
11915                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
11916                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
11917                    {
11918                        start_row = prev_row;
11919                    } else {
11920                        break 'expand_upwards;
11921                    }
11922                }
11923
11924                'expand_downwards: while end_row < buffer.max_point().row {
11925                    let next_row = end_row + 1;
11926                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
11927                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
11928                        && !buffer.is_line_blank(MultiBufferRow(next_row))
11929                    {
11930                        end_row = next_row;
11931                    } else {
11932                        break 'expand_downwards;
11933                    }
11934                }
11935            }
11936
11937            let start = Point::new(start_row, 0);
11938            let start_offset = start.to_offset(&buffer);
11939            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
11940            let selection_text = buffer.text_for_range(start..end).collect::<String>();
11941            let Some(lines_without_prefixes) = selection_text
11942                .lines()
11943                .enumerate()
11944                .map(|(ix, line)| {
11945                    let line_trimmed = line.trim_start();
11946                    if rewrap_prefix.is_some() && ix > 0 {
11947                        Ok(line_trimmed)
11948                    } else {
11949                        line_trimmed
11950                            .strip_prefix(&line_prefix.trim_start())
11951                            .with_context(|| {
11952                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
11953                            })
11954                    }
11955                })
11956                .collect::<Result<Vec<_>, _>>()
11957                .log_err()
11958            else {
11959                continue;
11960            };
11961
11962            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
11963                buffer
11964                    .language_settings_at(Point::new(start_row, 0), cx)
11965                    .preferred_line_length as usize
11966            });
11967
11968            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
11969                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
11970            } else {
11971                line_prefix.clone()
11972            };
11973
11974            let wrapped_text = wrap_with_prefix(
11975                line_prefix,
11976                subsequent_lines_prefix,
11977                lines_without_prefixes.join("\n"),
11978                wrap_column,
11979                tab_size,
11980                options.preserve_existing_whitespace,
11981            );
11982
11983            // TODO: should always use char-based diff while still supporting cursor behavior that
11984            // matches vim.
11985            let mut diff_options = DiffOptions::default();
11986            if options.override_language_settings {
11987                diff_options.max_word_diff_len = 0;
11988                diff_options.max_word_diff_line_count = 0;
11989            } else {
11990                diff_options.max_word_diff_len = usize::MAX;
11991                diff_options.max_word_diff_line_count = usize::MAX;
11992            }
11993
11994            for (old_range, new_text) in
11995                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
11996            {
11997                let edit_start = buffer.anchor_after(start_offset + old_range.start);
11998                let edit_end = buffer.anchor_after(start_offset + old_range.end);
11999                edits.push((edit_start..edit_end, new_text));
12000            }
12001
12002            rewrapped_row_ranges.push(start_row..=end_row);
12003        }
12004
12005        self.buffer
12006            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12007    }
12008
12009    pub fn cut_common(&mut self, window: &mut Window, cx: &mut Context<Self>) -> ClipboardItem {
12010        let mut text = String::new();
12011        let buffer = self.buffer.read(cx).snapshot(cx);
12012        let mut selections = self.selections.all::<Point>(cx);
12013        let mut clipboard_selections = Vec::with_capacity(selections.len());
12014        {
12015            let max_point = buffer.max_point();
12016            let mut is_first = true;
12017            for selection in &mut selections {
12018                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12019                if is_entire_line {
12020                    selection.start = Point::new(selection.start.row, 0);
12021                    if !selection.is_empty() && selection.end.column == 0 {
12022                        selection.end = cmp::min(max_point, selection.end);
12023                    } else {
12024                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12025                    }
12026                    selection.goal = SelectionGoal::None;
12027                }
12028                if is_first {
12029                    is_first = false;
12030                } else {
12031                    text += "\n";
12032                }
12033                let mut len = 0;
12034                for chunk in buffer.text_for_range(selection.start..selection.end) {
12035                    text.push_str(chunk);
12036                    len += chunk.len();
12037                }
12038                clipboard_selections.push(ClipboardSelection {
12039                    len,
12040                    is_entire_line,
12041                    first_line_indent: buffer
12042                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12043                        .len,
12044                });
12045            }
12046        }
12047
12048        self.transact(window, cx, |this, window, cx| {
12049            this.change_selections(Default::default(), window, cx, |s| {
12050                s.select(selections);
12051            });
12052            this.insert("", window, cx);
12053        });
12054        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12055    }
12056
12057    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12058        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12059        let item = self.cut_common(window, cx);
12060        cx.write_to_clipboard(item);
12061    }
12062
12063    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12064        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12065        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12066            s.move_with(|snapshot, sel| {
12067                if sel.is_empty() {
12068                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()))
12069                }
12070            });
12071        });
12072        let item = self.cut_common(window, cx);
12073        cx.set_global(KillRing(item))
12074    }
12075
12076    pub fn kill_ring_yank(
12077        &mut self,
12078        _: &KillRingYank,
12079        window: &mut Window,
12080        cx: &mut Context<Self>,
12081    ) {
12082        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12083        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12084            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12085                (kill_ring.text().to_string(), kill_ring.metadata_json())
12086            } else {
12087                return;
12088            }
12089        } else {
12090            return;
12091        };
12092        self.do_paste(&text, metadata, false, window, cx);
12093    }
12094
12095    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12096        self.do_copy(true, cx);
12097    }
12098
12099    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12100        self.do_copy(false, cx);
12101    }
12102
12103    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12104        let selections = self.selections.all::<Point>(cx);
12105        let buffer = self.buffer.read(cx).read(cx);
12106        let mut text = String::new();
12107
12108        let mut clipboard_selections = Vec::with_capacity(selections.len());
12109        {
12110            let max_point = buffer.max_point();
12111            let mut is_first = true;
12112            for selection in &selections {
12113                let mut start = selection.start;
12114                let mut end = selection.end;
12115                let is_entire_line = selection.is_empty() || self.selections.line_mode;
12116                if is_entire_line {
12117                    start = Point::new(start.row, 0);
12118                    end = cmp::min(max_point, Point::new(end.row + 1, 0));
12119                }
12120
12121                let mut trimmed_selections = Vec::new();
12122                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12123                    let row = MultiBufferRow(start.row);
12124                    let first_indent = buffer.indent_size_for_line(row);
12125                    if first_indent.len == 0 || start.column > first_indent.len {
12126                        trimmed_selections.push(start..end);
12127                    } else {
12128                        trimmed_selections.push(
12129                            Point::new(row.0, first_indent.len)
12130                                ..Point::new(row.0, buffer.line_len(row)),
12131                        );
12132                        for row in start.row + 1..=end.row {
12133                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12134                            if row == end.row {
12135                                line_len = end.column;
12136                            }
12137                            if line_len == 0 {
12138                                trimmed_selections
12139                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12140                                continue;
12141                            }
12142                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12143                            if row_indent_size.len >= first_indent.len {
12144                                trimmed_selections.push(
12145                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12146                                );
12147                            } else {
12148                                trimmed_selections.clear();
12149                                trimmed_selections.push(start..end);
12150                                break;
12151                            }
12152                        }
12153                    }
12154                } else {
12155                    trimmed_selections.push(start..end);
12156                }
12157
12158                for trimmed_range in trimmed_selections {
12159                    if is_first {
12160                        is_first = false;
12161                    } else {
12162                        text += "\n";
12163                    }
12164                    let mut len = 0;
12165                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12166                        text.push_str(chunk);
12167                        len += chunk.len();
12168                    }
12169                    clipboard_selections.push(ClipboardSelection {
12170                        len,
12171                        is_entire_line,
12172                        first_line_indent: buffer
12173                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12174                            .len,
12175                    });
12176                }
12177            }
12178        }
12179
12180        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12181            text,
12182            clipboard_selections,
12183        ));
12184    }
12185
12186    pub fn do_paste(
12187        &mut self,
12188        text: &String,
12189        clipboard_selections: Option<Vec<ClipboardSelection>>,
12190        handle_entire_lines: bool,
12191        window: &mut Window,
12192        cx: &mut Context<Self>,
12193    ) {
12194        if self.read_only(cx) {
12195            return;
12196        }
12197
12198        let clipboard_text = Cow::Borrowed(text);
12199
12200        self.transact(window, cx, |this, window, cx| {
12201            let had_active_edit_prediction = this.has_active_edit_prediction();
12202
12203            if let Some(mut clipboard_selections) = clipboard_selections {
12204                let old_selections = this.selections.all::<usize>(cx);
12205                let all_selections_were_entire_line =
12206                    clipboard_selections.iter().all(|s| s.is_entire_line);
12207                let first_selection_indent_column =
12208                    clipboard_selections.first().map(|s| s.first_line_indent);
12209                if clipboard_selections.len() != old_selections.len() {
12210                    clipboard_selections.drain(..);
12211                }
12212                let cursor_offset = this.selections.last::<usize>(cx).head();
12213                let mut auto_indent_on_paste = true;
12214
12215                this.buffer.update(cx, |buffer, cx| {
12216                    let snapshot = buffer.read(cx);
12217                    auto_indent_on_paste = snapshot
12218                        .language_settings_at(cursor_offset, cx)
12219                        .auto_indent_on_paste;
12220
12221                    let mut start_offset = 0;
12222                    let mut edits = Vec::new();
12223                    let mut original_indent_columns = Vec::new();
12224                    for (ix, selection) in old_selections.iter().enumerate() {
12225                        let to_insert;
12226                        let entire_line;
12227                        let original_indent_column;
12228                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12229                            let end_offset = start_offset + clipboard_selection.len;
12230                            to_insert = &clipboard_text[start_offset..end_offset];
12231                            entire_line = clipboard_selection.is_entire_line;
12232                            start_offset = end_offset + 1;
12233                            original_indent_column = Some(clipboard_selection.first_line_indent);
12234                        } else {
12235                            to_insert = clipboard_text.as_str();
12236                            entire_line = all_selections_were_entire_line;
12237                            original_indent_column = first_selection_indent_column
12238                        }
12239
12240                        // If the corresponding selection was empty when this slice of the
12241                        // clipboard text was written, then the entire line containing the
12242                        // selection was copied. If this selection is also currently empty,
12243                        // then paste the line before the current line of the buffer.
12244                        let range = if selection.is_empty() && handle_entire_lines && entire_line {
12245                            let column = selection.start.to_point(&snapshot).column as usize;
12246                            let line_start = selection.start - column;
12247                            line_start..line_start
12248                        } else {
12249                            selection.range()
12250                        };
12251
12252                        edits.push((range, to_insert));
12253                        original_indent_columns.push(original_indent_column);
12254                    }
12255                    drop(snapshot);
12256
12257                    buffer.edit(
12258                        edits,
12259                        if auto_indent_on_paste {
12260                            Some(AutoindentMode::Block {
12261                                original_indent_columns,
12262                            })
12263                        } else {
12264                            None
12265                        },
12266                        cx,
12267                    );
12268                });
12269
12270                let selections = this.selections.all::<usize>(cx);
12271                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12272            } else {
12273                this.insert(&clipboard_text, window, cx);
12274            }
12275
12276            let trigger_in_words =
12277                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12278
12279            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12280        });
12281    }
12282
12283    pub fn diff_clipboard_with_selection(
12284        &mut self,
12285        _: &DiffClipboardWithSelection,
12286        window: &mut Window,
12287        cx: &mut Context<Self>,
12288    ) {
12289        let selections = self.selections.all::<usize>(cx);
12290
12291        if selections.is_empty() {
12292            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12293            return;
12294        };
12295
12296        let clipboard_text = match cx.read_from_clipboard() {
12297            Some(item) => match item.entries().first() {
12298                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12299                _ => None,
12300            },
12301            None => None,
12302        };
12303
12304        let Some(clipboard_text) = clipboard_text else {
12305            log::warn!("Clipboard doesn't contain text.");
12306            return;
12307        };
12308
12309        window.dispatch_action(
12310            Box::new(DiffClipboardWithSelectionData {
12311                clipboard_text,
12312                editor: cx.entity(),
12313            }),
12314            cx,
12315        );
12316    }
12317
12318    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12319        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12320        if let Some(item) = cx.read_from_clipboard() {
12321            let entries = item.entries();
12322
12323            match entries.first() {
12324                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12325                // of all the pasted entries.
12326                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12327                    .do_paste(
12328                        clipboard_string.text(),
12329                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12330                        true,
12331                        window,
12332                        cx,
12333                    ),
12334                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12335            }
12336        }
12337    }
12338
12339    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12340        if self.read_only(cx) {
12341            return;
12342        }
12343
12344        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12345
12346        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12347            if let Some((selections, _)) =
12348                self.selection_history.transaction(transaction_id).cloned()
12349            {
12350                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12351                    s.select_anchors(selections.to_vec());
12352                });
12353            } else {
12354                log::error!(
12355                    "No entry in selection_history found for undo. \
12356                     This may correspond to a bug where undo does not update the selection. \
12357                     If this is occurring, please add details to \
12358                     https://github.com/zed-industries/zed/issues/22692"
12359                );
12360            }
12361            self.request_autoscroll(Autoscroll::fit(), cx);
12362            self.unmark_text(window, cx);
12363            self.refresh_edit_prediction(true, false, window, cx);
12364            cx.emit(EditorEvent::Edited { transaction_id });
12365            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12366        }
12367    }
12368
12369    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12370        if self.read_only(cx) {
12371            return;
12372        }
12373
12374        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12375
12376        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12377            if let Some((_, Some(selections))) =
12378                self.selection_history.transaction(transaction_id).cloned()
12379            {
12380                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12381                    s.select_anchors(selections.to_vec());
12382                });
12383            } else {
12384                log::error!(
12385                    "No entry in selection_history found for redo. \
12386                     This may correspond to a bug where undo does not update the selection. \
12387                     If this is occurring, please add details to \
12388                     https://github.com/zed-industries/zed/issues/22692"
12389                );
12390            }
12391            self.request_autoscroll(Autoscroll::fit(), cx);
12392            self.unmark_text(window, cx);
12393            self.refresh_edit_prediction(true, false, window, cx);
12394            cx.emit(EditorEvent::Edited { transaction_id });
12395        }
12396    }
12397
12398    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12399        self.buffer
12400            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12401    }
12402
12403    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12404        self.buffer
12405            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12406    }
12407
12408    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12409        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12410        self.change_selections(Default::default(), window, cx, |s| {
12411            s.move_with(|map, selection| {
12412                let cursor = if selection.is_empty() {
12413                    movement::left(map, selection.start)
12414                } else {
12415                    selection.start
12416                };
12417                selection.collapse_to(cursor, SelectionGoal::None);
12418            });
12419        })
12420    }
12421
12422    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12423        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12424        self.change_selections(Default::default(), window, cx, |s| {
12425            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12426        })
12427    }
12428
12429    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12430        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12431        self.change_selections(Default::default(), window, cx, |s| {
12432            s.move_with(|map, selection| {
12433                let cursor = if selection.is_empty() {
12434                    movement::right(map, selection.end)
12435                } else {
12436                    selection.end
12437                };
12438                selection.collapse_to(cursor, SelectionGoal::None)
12439            });
12440        })
12441    }
12442
12443    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12444        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12445        self.change_selections(Default::default(), window, cx, |s| {
12446            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12447        })
12448    }
12449
12450    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12451        if self.take_rename(true, window, cx).is_some() {
12452            return;
12453        }
12454
12455        if self.mode.is_single_line() {
12456            cx.propagate();
12457            return;
12458        }
12459
12460        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12461
12462        let text_layout_details = &self.text_layout_details(window);
12463        let selection_count = self.selections.count();
12464        let first_selection = self.selections.first_anchor();
12465
12466        self.change_selections(Default::default(), window, cx, |s| {
12467            s.move_with(|map, selection| {
12468                if !selection.is_empty() {
12469                    selection.goal = SelectionGoal::None;
12470                }
12471                let (cursor, goal) = movement::up(
12472                    map,
12473                    selection.start,
12474                    selection.goal,
12475                    false,
12476                    text_layout_details,
12477                );
12478                selection.collapse_to(cursor, goal);
12479            });
12480        });
12481
12482        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12483        {
12484            cx.propagate();
12485        }
12486    }
12487
12488    pub fn move_up_by_lines(
12489        &mut self,
12490        action: &MoveUpByLines,
12491        window: &mut Window,
12492        cx: &mut Context<Self>,
12493    ) {
12494        if self.take_rename(true, window, cx).is_some() {
12495            return;
12496        }
12497
12498        if self.mode.is_single_line() {
12499            cx.propagate();
12500            return;
12501        }
12502
12503        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12504
12505        let text_layout_details = &self.text_layout_details(window);
12506
12507        self.change_selections(Default::default(), window, cx, |s| {
12508            s.move_with(|map, selection| {
12509                if !selection.is_empty() {
12510                    selection.goal = SelectionGoal::None;
12511                }
12512                let (cursor, goal) = movement::up_by_rows(
12513                    map,
12514                    selection.start,
12515                    action.lines,
12516                    selection.goal,
12517                    false,
12518                    text_layout_details,
12519                );
12520                selection.collapse_to(cursor, goal);
12521            });
12522        })
12523    }
12524
12525    pub fn move_down_by_lines(
12526        &mut self,
12527        action: &MoveDownByLines,
12528        window: &mut Window,
12529        cx: &mut Context<Self>,
12530    ) {
12531        if self.take_rename(true, window, cx).is_some() {
12532            return;
12533        }
12534
12535        if self.mode.is_single_line() {
12536            cx.propagate();
12537            return;
12538        }
12539
12540        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12541
12542        let text_layout_details = &self.text_layout_details(window);
12543
12544        self.change_selections(Default::default(), window, cx, |s| {
12545            s.move_with(|map, selection| {
12546                if !selection.is_empty() {
12547                    selection.goal = SelectionGoal::None;
12548                }
12549                let (cursor, goal) = movement::down_by_rows(
12550                    map,
12551                    selection.start,
12552                    action.lines,
12553                    selection.goal,
12554                    false,
12555                    text_layout_details,
12556                );
12557                selection.collapse_to(cursor, goal);
12558            });
12559        })
12560    }
12561
12562    pub fn select_down_by_lines(
12563        &mut self,
12564        action: &SelectDownByLines,
12565        window: &mut Window,
12566        cx: &mut Context<Self>,
12567    ) {
12568        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12569        let text_layout_details = &self.text_layout_details(window);
12570        self.change_selections(Default::default(), window, cx, |s| {
12571            s.move_heads_with(|map, head, goal| {
12572                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
12573            })
12574        })
12575    }
12576
12577    pub fn select_up_by_lines(
12578        &mut self,
12579        action: &SelectUpByLines,
12580        window: &mut Window,
12581        cx: &mut Context<Self>,
12582    ) {
12583        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12584        let text_layout_details = &self.text_layout_details(window);
12585        self.change_selections(Default::default(), window, cx, |s| {
12586            s.move_heads_with(|map, head, goal| {
12587                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
12588            })
12589        })
12590    }
12591
12592    pub fn select_page_up(
12593        &mut self,
12594        _: &SelectPageUp,
12595        window: &mut Window,
12596        cx: &mut Context<Self>,
12597    ) {
12598        let Some(row_count) = self.visible_row_count() else {
12599            return;
12600        };
12601
12602        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12603
12604        let text_layout_details = &self.text_layout_details(window);
12605
12606        self.change_selections(Default::default(), window, cx, |s| {
12607            s.move_heads_with(|map, head, goal| {
12608                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
12609            })
12610        })
12611    }
12612
12613    pub fn move_page_up(
12614        &mut self,
12615        action: &MovePageUp,
12616        window: &mut Window,
12617        cx: &mut Context<Self>,
12618    ) {
12619        if self.take_rename(true, window, cx).is_some() {
12620            return;
12621        }
12622
12623        if self
12624            .context_menu
12625            .borrow_mut()
12626            .as_mut()
12627            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
12628            .unwrap_or(false)
12629        {
12630            return;
12631        }
12632
12633        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12634            cx.propagate();
12635            return;
12636        }
12637
12638        let Some(row_count) = self.visible_row_count() else {
12639            return;
12640        };
12641
12642        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12643
12644        let effects = if action.center_cursor {
12645            SelectionEffects::scroll(Autoscroll::center())
12646        } else {
12647            SelectionEffects::default()
12648        };
12649
12650        let text_layout_details = &self.text_layout_details(window);
12651
12652        self.change_selections(effects, window, cx, |s| {
12653            s.move_with(|map, selection| {
12654                if !selection.is_empty() {
12655                    selection.goal = SelectionGoal::None;
12656                }
12657                let (cursor, goal) = movement::up_by_rows(
12658                    map,
12659                    selection.end,
12660                    row_count,
12661                    selection.goal,
12662                    false,
12663                    text_layout_details,
12664                );
12665                selection.collapse_to(cursor, goal);
12666            });
12667        });
12668    }
12669
12670    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
12671        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12672        let text_layout_details = &self.text_layout_details(window);
12673        self.change_selections(Default::default(), window, cx, |s| {
12674            s.move_heads_with(|map, head, goal| {
12675                movement::up(map, head, goal, false, text_layout_details)
12676            })
12677        })
12678    }
12679
12680    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
12681        self.take_rename(true, window, cx);
12682
12683        if self.mode.is_single_line() {
12684            cx.propagate();
12685            return;
12686        }
12687
12688        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12689
12690        let text_layout_details = &self.text_layout_details(window);
12691        let selection_count = self.selections.count();
12692        let first_selection = self.selections.first_anchor();
12693
12694        self.change_selections(Default::default(), window, cx, |s| {
12695            s.move_with(|map, selection| {
12696                if !selection.is_empty() {
12697                    selection.goal = SelectionGoal::None;
12698                }
12699                let (cursor, goal) = movement::down(
12700                    map,
12701                    selection.end,
12702                    selection.goal,
12703                    false,
12704                    text_layout_details,
12705                );
12706                selection.collapse_to(cursor, goal);
12707            });
12708        });
12709
12710        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12711        {
12712            cx.propagate();
12713        }
12714    }
12715
12716    pub fn select_page_down(
12717        &mut self,
12718        _: &SelectPageDown,
12719        window: &mut Window,
12720        cx: &mut Context<Self>,
12721    ) {
12722        let Some(row_count) = self.visible_row_count() else {
12723            return;
12724        };
12725
12726        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12727
12728        let text_layout_details = &self.text_layout_details(window);
12729
12730        self.change_selections(Default::default(), window, cx, |s| {
12731            s.move_heads_with(|map, head, goal| {
12732                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
12733            })
12734        })
12735    }
12736
12737    pub fn move_page_down(
12738        &mut self,
12739        action: &MovePageDown,
12740        window: &mut Window,
12741        cx: &mut Context<Self>,
12742    ) {
12743        if self.take_rename(true, window, cx).is_some() {
12744            return;
12745        }
12746
12747        if self
12748            .context_menu
12749            .borrow_mut()
12750            .as_mut()
12751            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
12752            .unwrap_or(false)
12753        {
12754            return;
12755        }
12756
12757        if matches!(self.mode, EditorMode::SingleLine { .. }) {
12758            cx.propagate();
12759            return;
12760        }
12761
12762        let Some(row_count) = self.visible_row_count() else {
12763            return;
12764        };
12765
12766        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12767
12768        let effects = if action.center_cursor {
12769            SelectionEffects::scroll(Autoscroll::center())
12770        } else {
12771            SelectionEffects::default()
12772        };
12773
12774        let text_layout_details = &self.text_layout_details(window);
12775        self.change_selections(effects, window, cx, |s| {
12776            s.move_with(|map, selection| {
12777                if !selection.is_empty() {
12778                    selection.goal = SelectionGoal::None;
12779                }
12780                let (cursor, goal) = movement::down_by_rows(
12781                    map,
12782                    selection.end,
12783                    row_count,
12784                    selection.goal,
12785                    false,
12786                    text_layout_details,
12787                );
12788                selection.collapse_to(cursor, goal);
12789            });
12790        });
12791    }
12792
12793    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
12794        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12795        let text_layout_details = &self.text_layout_details(window);
12796        self.change_selections(Default::default(), window, cx, |s| {
12797            s.move_heads_with(|map, head, goal| {
12798                movement::down(map, head, goal, false, text_layout_details)
12799            })
12800        });
12801    }
12802
12803    pub fn context_menu_first(
12804        &mut self,
12805        _: &ContextMenuFirst,
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_first(self.completion_provider.as_deref(), window, cx);
12811        }
12812    }
12813
12814    pub fn context_menu_prev(
12815        &mut self,
12816        _: &ContextMenuPrevious,
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_prev(self.completion_provider.as_deref(), window, cx);
12822        }
12823    }
12824
12825    pub fn context_menu_next(
12826        &mut self,
12827        _: &ContextMenuNext,
12828        window: &mut Window,
12829        cx: &mut Context<Self>,
12830    ) {
12831        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12832            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
12833        }
12834    }
12835
12836    pub fn context_menu_last(
12837        &mut self,
12838        _: &ContextMenuLast,
12839        window: &mut Window,
12840        cx: &mut Context<Self>,
12841    ) {
12842        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
12843            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
12844        }
12845    }
12846
12847    pub fn signature_help_prev(
12848        &mut self,
12849        _: &SignatureHelpPrevious,
12850        _: &mut Window,
12851        cx: &mut Context<Self>,
12852    ) {
12853        if let Some(popover) = self.signature_help_state.popover_mut() {
12854            if popover.current_signature == 0 {
12855                popover.current_signature = popover.signatures.len() - 1;
12856            } else {
12857                popover.current_signature -= 1;
12858            }
12859            cx.notify();
12860        }
12861    }
12862
12863    pub fn signature_help_next(
12864        &mut self,
12865        _: &SignatureHelpNext,
12866        _: &mut Window,
12867        cx: &mut Context<Self>,
12868    ) {
12869        if let Some(popover) = self.signature_help_state.popover_mut() {
12870            if popover.current_signature + 1 == popover.signatures.len() {
12871                popover.current_signature = 0;
12872            } else {
12873                popover.current_signature += 1;
12874            }
12875            cx.notify();
12876        }
12877    }
12878
12879    pub fn move_to_previous_word_start(
12880        &mut self,
12881        _: &MoveToPreviousWordStart,
12882        window: &mut Window,
12883        cx: &mut Context<Self>,
12884    ) {
12885        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12886        self.change_selections(Default::default(), window, cx, |s| {
12887            s.move_cursors_with(|map, head, _| {
12888                (
12889                    movement::previous_word_start(map, head),
12890                    SelectionGoal::None,
12891                )
12892            });
12893        })
12894    }
12895
12896    pub fn move_to_previous_subword_start(
12897        &mut self,
12898        _: &MoveToPreviousSubwordStart,
12899        window: &mut Window,
12900        cx: &mut Context<Self>,
12901    ) {
12902        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12903        self.change_selections(Default::default(), window, cx, |s| {
12904            s.move_cursors_with(|map, head, _| {
12905                (
12906                    movement::previous_subword_start(map, head),
12907                    SelectionGoal::None,
12908                )
12909            });
12910        })
12911    }
12912
12913    pub fn select_to_previous_word_start(
12914        &mut self,
12915        _: &SelectToPreviousWordStart,
12916        window: &mut Window,
12917        cx: &mut Context<Self>,
12918    ) {
12919        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12920        self.change_selections(Default::default(), window, cx, |s| {
12921            s.move_heads_with(|map, head, _| {
12922                (
12923                    movement::previous_word_start(map, head),
12924                    SelectionGoal::None,
12925                )
12926            });
12927        })
12928    }
12929
12930    pub fn select_to_previous_subword_start(
12931        &mut self,
12932        _: &SelectToPreviousSubwordStart,
12933        window: &mut Window,
12934        cx: &mut Context<Self>,
12935    ) {
12936        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12937        self.change_selections(Default::default(), window, cx, |s| {
12938            s.move_heads_with(|map, head, _| {
12939                (
12940                    movement::previous_subword_start(map, head),
12941                    SelectionGoal::None,
12942                )
12943            });
12944        })
12945    }
12946
12947    pub fn delete_to_previous_word_start(
12948        &mut self,
12949        action: &DeleteToPreviousWordStart,
12950        window: &mut Window,
12951        cx: &mut Context<Self>,
12952    ) {
12953        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12954        self.transact(window, cx, |this, window, cx| {
12955            this.select_autoclose_pair(window, cx);
12956            this.change_selections(Default::default(), window, cx, |s| {
12957                s.move_with(|map, selection| {
12958                    if selection.is_empty() {
12959                        let cursor = if action.ignore_newlines {
12960                            movement::previous_word_start(map, selection.head())
12961                        } else {
12962                            movement::previous_word_start_or_newline(map, selection.head())
12963                        };
12964                        selection.set_head(cursor, SelectionGoal::None);
12965                    }
12966                });
12967            });
12968            this.insert("", window, cx);
12969        });
12970    }
12971
12972    pub fn delete_to_previous_subword_start(
12973        &mut self,
12974        _: &DeleteToPreviousSubwordStart,
12975        window: &mut Window,
12976        cx: &mut Context<Self>,
12977    ) {
12978        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12979        self.transact(window, cx, |this, window, cx| {
12980            this.select_autoclose_pair(window, cx);
12981            this.change_selections(Default::default(), window, cx, |s| {
12982                s.move_with(|map, selection| {
12983                    if selection.is_empty() {
12984                        let cursor = movement::previous_subword_start(map, selection.head());
12985                        selection.set_head(cursor, SelectionGoal::None);
12986                    }
12987                });
12988            });
12989            this.insert("", window, cx);
12990        });
12991    }
12992
12993    pub fn move_to_next_word_end(
12994        &mut self,
12995        _: &MoveToNextWordEnd,
12996        window: &mut Window,
12997        cx: &mut Context<Self>,
12998    ) {
12999        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13000        self.change_selections(Default::default(), window, cx, |s| {
13001            s.move_cursors_with(|map, head, _| {
13002                (movement::next_word_end(map, head), SelectionGoal::None)
13003            });
13004        })
13005    }
13006
13007    pub fn move_to_next_subword_end(
13008        &mut self,
13009        _: &MoveToNextSubwordEnd,
13010        window: &mut Window,
13011        cx: &mut Context<Self>,
13012    ) {
13013        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13014        self.change_selections(Default::default(), window, cx, |s| {
13015            s.move_cursors_with(|map, head, _| {
13016                (movement::next_subword_end(map, head), SelectionGoal::None)
13017            });
13018        })
13019    }
13020
13021    pub fn select_to_next_word_end(
13022        &mut self,
13023        _: &SelectToNextWordEnd,
13024        window: &mut Window,
13025        cx: &mut Context<Self>,
13026    ) {
13027        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13028        self.change_selections(Default::default(), window, cx, |s| {
13029            s.move_heads_with(|map, head, _| {
13030                (movement::next_word_end(map, head), SelectionGoal::None)
13031            });
13032        })
13033    }
13034
13035    pub fn select_to_next_subword_end(
13036        &mut self,
13037        _: &SelectToNextSubwordEnd,
13038        window: &mut Window,
13039        cx: &mut Context<Self>,
13040    ) {
13041        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13042        self.change_selections(Default::default(), window, cx, |s| {
13043            s.move_heads_with(|map, head, _| {
13044                (movement::next_subword_end(map, head), SelectionGoal::None)
13045            });
13046        })
13047    }
13048
13049    pub fn delete_to_next_word_end(
13050        &mut self,
13051        action: &DeleteToNextWordEnd,
13052        window: &mut Window,
13053        cx: &mut Context<Self>,
13054    ) {
13055        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13056        self.transact(window, cx, |this, window, cx| {
13057            this.change_selections(Default::default(), window, cx, |s| {
13058                s.move_with(|map, selection| {
13059                    if selection.is_empty() {
13060                        let cursor = if action.ignore_newlines {
13061                            movement::next_word_end(map, selection.head())
13062                        } else {
13063                            movement::next_word_end_or_newline(map, selection.head())
13064                        };
13065                        selection.set_head(cursor, SelectionGoal::None);
13066                    }
13067                });
13068            });
13069            this.insert("", window, cx);
13070        });
13071    }
13072
13073    pub fn delete_to_next_subword_end(
13074        &mut self,
13075        _: &DeleteToNextSubwordEnd,
13076        window: &mut Window,
13077        cx: &mut Context<Self>,
13078    ) {
13079        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13080        self.transact(window, cx, |this, window, cx| {
13081            this.change_selections(Default::default(), window, cx, |s| {
13082                s.move_with(|map, selection| {
13083                    if selection.is_empty() {
13084                        let cursor = movement::next_subword_end(map, selection.head());
13085                        selection.set_head(cursor, SelectionGoal::None);
13086                    }
13087                });
13088            });
13089            this.insert("", window, cx);
13090        });
13091    }
13092
13093    pub fn move_to_beginning_of_line(
13094        &mut self,
13095        action: &MoveToBeginningOfLine,
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_cursors_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 select_to_beginning_of_line(
13116        &mut self,
13117        action: &SelectToBeginningOfLine,
13118        window: &mut Window,
13119        cx: &mut Context<Self>,
13120    ) {
13121        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13122        self.change_selections(Default::default(), window, cx, |s| {
13123            s.move_heads_with(|map, head, _| {
13124                (
13125                    movement::indented_line_beginning(
13126                        map,
13127                        head,
13128                        action.stop_at_soft_wraps,
13129                        action.stop_at_indent,
13130                    ),
13131                    SelectionGoal::None,
13132                )
13133            });
13134        });
13135    }
13136
13137    pub fn delete_to_beginning_of_line(
13138        &mut self,
13139        action: &DeleteToBeginningOfLine,
13140        window: &mut Window,
13141        cx: &mut Context<Self>,
13142    ) {
13143        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13144        self.transact(window, cx, |this, window, cx| {
13145            this.change_selections(Default::default(), window, cx, |s| {
13146                s.move_with(|_, selection| {
13147                    selection.reversed = true;
13148                });
13149            });
13150
13151            this.select_to_beginning_of_line(
13152                &SelectToBeginningOfLine {
13153                    stop_at_soft_wraps: false,
13154                    stop_at_indent: action.stop_at_indent,
13155                },
13156                window,
13157                cx,
13158            );
13159            this.backspace(&Backspace, window, cx);
13160        });
13161    }
13162
13163    pub fn move_to_end_of_line(
13164        &mut self,
13165        action: &MoveToEndOfLine,
13166        window: &mut Window,
13167        cx: &mut Context<Self>,
13168    ) {
13169        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13170        self.change_selections(Default::default(), window, cx, |s| {
13171            s.move_cursors_with(|map, head, _| {
13172                (
13173                    movement::line_end(map, head, action.stop_at_soft_wraps),
13174                    SelectionGoal::None,
13175                )
13176            });
13177        })
13178    }
13179
13180    pub fn select_to_end_of_line(
13181        &mut self,
13182        action: &SelectToEndOfLine,
13183        window: &mut Window,
13184        cx: &mut Context<Self>,
13185    ) {
13186        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13187        self.change_selections(Default::default(), window, cx, |s| {
13188            s.move_heads_with(|map, head, _| {
13189                (
13190                    movement::line_end(map, head, action.stop_at_soft_wraps),
13191                    SelectionGoal::None,
13192                )
13193            });
13194        })
13195    }
13196
13197    pub fn delete_to_end_of_line(
13198        &mut self,
13199        _: &DeleteToEndOfLine,
13200        window: &mut Window,
13201        cx: &mut Context<Self>,
13202    ) {
13203        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13204        self.transact(window, cx, |this, window, cx| {
13205            this.select_to_end_of_line(
13206                &SelectToEndOfLine {
13207                    stop_at_soft_wraps: false,
13208                },
13209                window,
13210                cx,
13211            );
13212            this.delete(&Delete, window, cx);
13213        });
13214    }
13215
13216    pub fn cut_to_end_of_line(
13217        &mut self,
13218        _: &CutToEndOfLine,
13219        window: &mut Window,
13220        cx: &mut Context<Self>,
13221    ) {
13222        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13223        self.transact(window, cx, |this, window, cx| {
13224            this.select_to_end_of_line(
13225                &SelectToEndOfLine {
13226                    stop_at_soft_wraps: false,
13227                },
13228                window,
13229                cx,
13230            );
13231            this.cut(&Cut, window, cx);
13232        });
13233    }
13234
13235    pub fn move_to_start_of_paragraph(
13236        &mut self,
13237        _: &MoveToStartOfParagraph,
13238        window: &mut Window,
13239        cx: &mut Context<Self>,
13240    ) {
13241        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13242            cx.propagate();
13243            return;
13244        }
13245        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13246        self.change_selections(Default::default(), window, cx, |s| {
13247            s.move_with(|map, selection| {
13248                selection.collapse_to(
13249                    movement::start_of_paragraph(map, selection.head(), 1),
13250                    SelectionGoal::None,
13251                )
13252            });
13253        })
13254    }
13255
13256    pub fn move_to_end_of_paragraph(
13257        &mut self,
13258        _: &MoveToEndOfParagraph,
13259        window: &mut Window,
13260        cx: &mut Context<Self>,
13261    ) {
13262        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13263            cx.propagate();
13264            return;
13265        }
13266        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13267        self.change_selections(Default::default(), window, cx, |s| {
13268            s.move_with(|map, selection| {
13269                selection.collapse_to(
13270                    movement::end_of_paragraph(map, selection.head(), 1),
13271                    SelectionGoal::None,
13272                )
13273            });
13274        })
13275    }
13276
13277    pub fn select_to_start_of_paragraph(
13278        &mut self,
13279        _: &SelectToStartOfParagraph,
13280        window: &mut Window,
13281        cx: &mut Context<Self>,
13282    ) {
13283        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13284            cx.propagate();
13285            return;
13286        }
13287        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13288        self.change_selections(Default::default(), window, cx, |s| {
13289            s.move_heads_with(|map, head, _| {
13290                (
13291                    movement::start_of_paragraph(map, head, 1),
13292                    SelectionGoal::None,
13293                )
13294            });
13295        })
13296    }
13297
13298    pub fn select_to_end_of_paragraph(
13299        &mut self,
13300        _: &SelectToEndOfParagraph,
13301        window: &mut Window,
13302        cx: &mut Context<Self>,
13303    ) {
13304        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13305            cx.propagate();
13306            return;
13307        }
13308        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13309        self.change_selections(Default::default(), window, cx, |s| {
13310            s.move_heads_with(|map, head, _| {
13311                (
13312                    movement::end_of_paragraph(map, head, 1),
13313                    SelectionGoal::None,
13314                )
13315            });
13316        })
13317    }
13318
13319    pub fn move_to_start_of_excerpt(
13320        &mut self,
13321        _: &MoveToStartOfExcerpt,
13322        window: &mut Window,
13323        cx: &mut Context<Self>,
13324    ) {
13325        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13326            cx.propagate();
13327            return;
13328        }
13329        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13330        self.change_selections(Default::default(), window, cx, |s| {
13331            s.move_with(|map, selection| {
13332                selection.collapse_to(
13333                    movement::start_of_excerpt(
13334                        map,
13335                        selection.head(),
13336                        workspace::searchable::Direction::Prev,
13337                    ),
13338                    SelectionGoal::None,
13339                )
13340            });
13341        })
13342    }
13343
13344    pub fn move_to_start_of_next_excerpt(
13345        &mut self,
13346        _: &MoveToStartOfNextExcerpt,
13347        window: &mut Window,
13348        cx: &mut Context<Self>,
13349    ) {
13350        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13351            cx.propagate();
13352            return;
13353        }
13354
13355        self.change_selections(Default::default(), window, cx, |s| {
13356            s.move_with(|map, selection| {
13357                selection.collapse_to(
13358                    movement::start_of_excerpt(
13359                        map,
13360                        selection.head(),
13361                        workspace::searchable::Direction::Next,
13362                    ),
13363                    SelectionGoal::None,
13364                )
13365            });
13366        })
13367    }
13368
13369    pub fn move_to_end_of_excerpt(
13370        &mut self,
13371        _: &MoveToEndOfExcerpt,
13372        window: &mut Window,
13373        cx: &mut Context<Self>,
13374    ) {
13375        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13376            cx.propagate();
13377            return;
13378        }
13379        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13380        self.change_selections(Default::default(), window, cx, |s| {
13381            s.move_with(|map, selection| {
13382                selection.collapse_to(
13383                    movement::end_of_excerpt(
13384                        map,
13385                        selection.head(),
13386                        workspace::searchable::Direction::Next,
13387                    ),
13388                    SelectionGoal::None,
13389                )
13390            });
13391        })
13392    }
13393
13394    pub fn move_to_end_of_previous_excerpt(
13395        &mut self,
13396        _: &MoveToEndOfPreviousExcerpt,
13397        window: &mut Window,
13398        cx: &mut Context<Self>,
13399    ) {
13400        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13401            cx.propagate();
13402            return;
13403        }
13404        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13405        self.change_selections(Default::default(), window, cx, |s| {
13406            s.move_with(|map, selection| {
13407                selection.collapse_to(
13408                    movement::end_of_excerpt(
13409                        map,
13410                        selection.head(),
13411                        workspace::searchable::Direction::Prev,
13412                    ),
13413                    SelectionGoal::None,
13414                )
13415            });
13416        })
13417    }
13418
13419    pub fn select_to_start_of_excerpt(
13420        &mut self,
13421        _: &SelectToStartOfExcerpt,
13422        window: &mut Window,
13423        cx: &mut Context<Self>,
13424    ) {
13425        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13426            cx.propagate();
13427            return;
13428        }
13429        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13430        self.change_selections(Default::default(), window, cx, |s| {
13431            s.move_heads_with(|map, head, _| {
13432                (
13433                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13434                    SelectionGoal::None,
13435                )
13436            });
13437        })
13438    }
13439
13440    pub fn select_to_start_of_next_excerpt(
13441        &mut self,
13442        _: &SelectToStartOfNextExcerpt,
13443        window: &mut Window,
13444        cx: &mut Context<Self>,
13445    ) {
13446        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13447            cx.propagate();
13448            return;
13449        }
13450        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13451        self.change_selections(Default::default(), window, cx, |s| {
13452            s.move_heads_with(|map, head, _| {
13453                (
13454                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13455                    SelectionGoal::None,
13456                )
13457            });
13458        })
13459    }
13460
13461    pub fn select_to_end_of_excerpt(
13462        &mut self,
13463        _: &SelectToEndOfExcerpt,
13464        window: &mut Window,
13465        cx: &mut Context<Self>,
13466    ) {
13467        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13468            cx.propagate();
13469            return;
13470        }
13471        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13472        self.change_selections(Default::default(), window, cx, |s| {
13473            s.move_heads_with(|map, head, _| {
13474                (
13475                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13476                    SelectionGoal::None,
13477                )
13478            });
13479        })
13480    }
13481
13482    pub fn select_to_end_of_previous_excerpt(
13483        &mut self,
13484        _: &SelectToEndOfPreviousExcerpt,
13485        window: &mut Window,
13486        cx: &mut Context<Self>,
13487    ) {
13488        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13489            cx.propagate();
13490            return;
13491        }
13492        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13493        self.change_selections(Default::default(), window, cx, |s| {
13494            s.move_heads_with(|map, head, _| {
13495                (
13496                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13497                    SelectionGoal::None,
13498                )
13499            });
13500        })
13501    }
13502
13503    pub fn move_to_beginning(
13504        &mut self,
13505        _: &MoveToBeginning,
13506        window: &mut Window,
13507        cx: &mut Context<Self>,
13508    ) {
13509        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13510            cx.propagate();
13511            return;
13512        }
13513        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13514        self.change_selections(Default::default(), window, cx, |s| {
13515            s.select_ranges(vec![0..0]);
13516        });
13517    }
13518
13519    pub fn select_to_beginning(
13520        &mut self,
13521        _: &SelectToBeginning,
13522        window: &mut Window,
13523        cx: &mut Context<Self>,
13524    ) {
13525        let mut selection = self.selections.last::<Point>(cx);
13526        selection.set_head(Point::zero(), SelectionGoal::None);
13527        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13528        self.change_selections(Default::default(), window, cx, |s| {
13529            s.select(vec![selection]);
13530        });
13531    }
13532
13533    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13534        if matches!(self.mode, EditorMode::SingleLine { .. }) {
13535            cx.propagate();
13536            return;
13537        }
13538        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13539        let cursor = self.buffer.read(cx).read(cx).len();
13540        self.change_selections(Default::default(), window, cx, |s| {
13541            s.select_ranges(vec![cursor..cursor])
13542        });
13543    }
13544
13545    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
13546        self.nav_history = nav_history;
13547    }
13548
13549    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
13550        self.nav_history.as_ref()
13551    }
13552
13553    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
13554        self.push_to_nav_history(
13555            self.selections.newest_anchor().head(),
13556            None,
13557            false,
13558            true,
13559            cx,
13560        );
13561    }
13562
13563    fn push_to_nav_history(
13564        &mut self,
13565        cursor_anchor: Anchor,
13566        new_position: Option<Point>,
13567        is_deactivate: bool,
13568        always: bool,
13569        cx: &mut Context<Self>,
13570    ) {
13571        if let Some(nav_history) = self.nav_history.as_mut() {
13572            let buffer = self.buffer.read(cx).read(cx);
13573            let cursor_position = cursor_anchor.to_point(&buffer);
13574            let scroll_state = self.scroll_manager.anchor();
13575            let scroll_top_row = scroll_state.top_row(&buffer);
13576            drop(buffer);
13577
13578            if let Some(new_position) = new_position {
13579                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
13580                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
13581                    return;
13582                }
13583            }
13584
13585            nav_history.push(
13586                Some(NavigationData {
13587                    cursor_anchor,
13588                    cursor_position,
13589                    scroll_anchor: scroll_state,
13590                    scroll_top_row,
13591                }),
13592                cx,
13593            );
13594            cx.emit(EditorEvent::PushedToNavHistory {
13595                anchor: cursor_anchor,
13596                is_deactivate,
13597            })
13598        }
13599    }
13600
13601    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
13602        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13603        let buffer = self.buffer.read(cx).snapshot(cx);
13604        let mut selection = self.selections.first::<usize>(cx);
13605        selection.set_head(buffer.len(), SelectionGoal::None);
13606        self.change_selections(Default::default(), window, cx, |s| {
13607            s.select(vec![selection]);
13608        });
13609    }
13610
13611    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
13612        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13613        let end = self.buffer.read(cx).read(cx).len();
13614        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13615            s.select_ranges(vec![0..end]);
13616        });
13617    }
13618
13619    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
13620        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13621        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13622        let mut selections = self.selections.all::<Point>(cx);
13623        let max_point = display_map.buffer_snapshot.max_point();
13624        for selection in &mut selections {
13625            let rows = selection.spanned_rows(true, &display_map);
13626            selection.start = Point::new(rows.start.0, 0);
13627            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
13628            selection.reversed = false;
13629        }
13630        self.change_selections(Default::default(), window, cx, |s| {
13631            s.select(selections);
13632        });
13633    }
13634
13635    pub fn split_selection_into_lines(
13636        &mut self,
13637        action: &SplitSelectionIntoLines,
13638        window: &mut Window,
13639        cx: &mut Context<Self>,
13640    ) {
13641        let selections = self
13642            .selections
13643            .all::<Point>(cx)
13644            .into_iter()
13645            .map(|selection| selection.start..selection.end)
13646            .collect::<Vec<_>>();
13647        self.unfold_ranges(&selections, true, true, cx);
13648
13649        let mut new_selection_ranges = Vec::new();
13650        {
13651            let buffer = self.buffer.read(cx).read(cx);
13652            for selection in selections {
13653                for row in selection.start.row..selection.end.row {
13654                    let line_start = Point::new(row, 0);
13655                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13656
13657                    if action.keep_selections {
13658                        // Keep the selection range for each line
13659                        let selection_start = if row == selection.start.row {
13660                            selection.start
13661                        } else {
13662                            line_start
13663                        };
13664                        new_selection_ranges.push(selection_start..line_end);
13665                    } else {
13666                        // Collapse to cursor at end of line
13667                        new_selection_ranges.push(line_end..line_end);
13668                    }
13669                }
13670
13671                let is_multiline_selection = selection.start.row != selection.end.row;
13672                // Don't insert last one if it's a multi-line selection ending at the start of a line,
13673                // so this action feels more ergonomic when paired with other selection operations
13674                let should_skip_last = is_multiline_selection && selection.end.column == 0;
13675                if !should_skip_last {
13676                    if action.keep_selections {
13677                        if is_multiline_selection {
13678                            let line_start = Point::new(selection.end.row, 0);
13679                            new_selection_ranges.push(line_start..selection.end);
13680                        } else {
13681                            new_selection_ranges.push(selection.start..selection.end);
13682                        }
13683                    } else {
13684                        new_selection_ranges.push(selection.end..selection.end);
13685                    }
13686                }
13687            }
13688        }
13689        self.change_selections(Default::default(), window, cx, |s| {
13690            s.select_ranges(new_selection_ranges);
13691        });
13692    }
13693
13694    pub fn add_selection_above(
13695        &mut self,
13696        _: &AddSelectionAbove,
13697        window: &mut Window,
13698        cx: &mut Context<Self>,
13699    ) {
13700        self.add_selection(true, window, cx);
13701    }
13702
13703    pub fn add_selection_below(
13704        &mut self,
13705        _: &AddSelectionBelow,
13706        window: &mut Window,
13707        cx: &mut Context<Self>,
13708    ) {
13709        self.add_selection(false, window, cx);
13710    }
13711
13712    fn add_selection(&mut self, above: bool, window: &mut Window, cx: &mut Context<Self>) {
13713        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13714
13715        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13716        let all_selections = self.selections.all::<Point>(cx);
13717        let text_layout_details = self.text_layout_details(window);
13718
13719        let (mut columnar_selections, new_selections_to_columnarize) = {
13720            if let Some(state) = self.add_selections_state.as_ref() {
13721                let columnar_selection_ids: HashSet<_> = state
13722                    .groups
13723                    .iter()
13724                    .flat_map(|group| group.stack.iter())
13725                    .copied()
13726                    .collect();
13727
13728                all_selections
13729                    .into_iter()
13730                    .partition(|s| columnar_selection_ids.contains(&s.id))
13731            } else {
13732                (Vec::new(), all_selections)
13733            }
13734        };
13735
13736        let mut state = self
13737            .add_selections_state
13738            .take()
13739            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
13740
13741        for selection in new_selections_to_columnarize {
13742            let range = selection.display_range(&display_map).sorted();
13743            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
13744            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
13745            let positions = start_x.min(end_x)..start_x.max(end_x);
13746            let mut stack = Vec::new();
13747            for row in range.start.row().0..=range.end.row().0 {
13748                if let Some(selection) = self.selections.build_columnar_selection(
13749                    &display_map,
13750                    DisplayRow(row),
13751                    &positions,
13752                    selection.reversed,
13753                    &text_layout_details,
13754                ) {
13755                    stack.push(selection.id);
13756                    columnar_selections.push(selection);
13757                }
13758            }
13759            if !stack.is_empty() {
13760                if above {
13761                    stack.reverse();
13762                }
13763                state.groups.push(AddSelectionsGroup { above, stack });
13764            }
13765        }
13766
13767        let mut final_selections = Vec::new();
13768        let end_row = if above {
13769            DisplayRow(0)
13770        } else {
13771            display_map.max_point().row()
13772        };
13773
13774        let mut last_added_item_per_group = HashMap::default();
13775        for group in state.groups.iter_mut() {
13776            if let Some(last_id) = group.stack.last() {
13777                last_added_item_per_group.insert(*last_id, group);
13778            }
13779        }
13780
13781        for selection in columnar_selections {
13782            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
13783                if above == group.above {
13784                    let range = selection.display_range(&display_map).sorted();
13785                    debug_assert_eq!(range.start.row(), range.end.row());
13786                    let mut row = range.start.row();
13787                    let positions =
13788                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
13789                            px(start)..px(end)
13790                        } else {
13791                            let start_x =
13792                                display_map.x_for_display_point(range.start, &text_layout_details);
13793                            let end_x =
13794                                display_map.x_for_display_point(range.end, &text_layout_details);
13795                            start_x.min(end_x)..start_x.max(end_x)
13796                        };
13797
13798                    let mut maybe_new_selection = None;
13799                    while row != end_row {
13800                        if above {
13801                            row.0 -= 1;
13802                        } else {
13803                            row.0 += 1;
13804                        }
13805                        if let Some(new_selection) = self.selections.build_columnar_selection(
13806                            &display_map,
13807                            row,
13808                            &positions,
13809                            selection.reversed,
13810                            &text_layout_details,
13811                        ) {
13812                            maybe_new_selection = Some(new_selection);
13813                            break;
13814                        }
13815                    }
13816
13817                    if let Some(new_selection) = maybe_new_selection {
13818                        group.stack.push(new_selection.id);
13819                        if above {
13820                            final_selections.push(new_selection);
13821                            final_selections.push(selection);
13822                        } else {
13823                            final_selections.push(selection);
13824                            final_selections.push(new_selection);
13825                        }
13826                    } else {
13827                        final_selections.push(selection);
13828                    }
13829                } else {
13830                    group.stack.pop();
13831                }
13832            } else {
13833                final_selections.push(selection);
13834            }
13835        }
13836
13837        self.change_selections(Default::default(), window, cx, |s| {
13838            s.select(final_selections);
13839        });
13840
13841        let final_selection_ids: HashSet<_> = self
13842            .selections
13843            .all::<Point>(cx)
13844            .iter()
13845            .map(|s| s.id)
13846            .collect();
13847        state.groups.retain_mut(|group| {
13848            // selections might get merged above so we remove invalid items from stacks
13849            group.stack.retain(|id| final_selection_ids.contains(id));
13850
13851            // single selection in stack can be treated as initial state
13852            group.stack.len() > 1
13853        });
13854
13855        if !state.groups.is_empty() {
13856            self.add_selections_state = Some(state);
13857        }
13858    }
13859
13860    fn select_match_ranges(
13861        &mut self,
13862        range: Range<usize>,
13863        reversed: bool,
13864        replace_newest: bool,
13865        auto_scroll: Option<Autoscroll>,
13866        window: &mut Window,
13867        cx: &mut Context<Editor>,
13868    ) {
13869        self.unfold_ranges(
13870            std::slice::from_ref(&range),
13871            false,
13872            auto_scroll.is_some(),
13873            cx,
13874        );
13875        let effects = if let Some(scroll) = auto_scroll {
13876            SelectionEffects::scroll(scroll)
13877        } else {
13878            SelectionEffects::no_scroll()
13879        };
13880        self.change_selections(effects, window, cx, |s| {
13881            if replace_newest {
13882                s.delete(s.newest_anchor().id);
13883            }
13884            if reversed {
13885                s.insert_range(range.end..range.start);
13886            } else {
13887                s.insert_range(range);
13888            }
13889        });
13890    }
13891
13892    pub fn select_next_match_internal(
13893        &mut self,
13894        display_map: &DisplaySnapshot,
13895        replace_newest: bool,
13896        autoscroll: Option<Autoscroll>,
13897        window: &mut Window,
13898        cx: &mut Context<Self>,
13899    ) -> Result<()> {
13900        let buffer = &display_map.buffer_snapshot;
13901        let mut selections = self.selections.all::<usize>(cx);
13902        if let Some(mut select_next_state) = self.select_next_state.take() {
13903            let query = &select_next_state.query;
13904            if !select_next_state.done {
13905                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
13906                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
13907                let mut next_selected_range = None;
13908
13909                let bytes_after_last_selection =
13910                    buffer.bytes_in_range(last_selection.end..buffer.len());
13911                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
13912                let query_matches = query
13913                    .stream_find_iter(bytes_after_last_selection)
13914                    .map(|result| (last_selection.end, result))
13915                    .chain(
13916                        query
13917                            .stream_find_iter(bytes_before_first_selection)
13918                            .map(|result| (0, result)),
13919                    );
13920
13921                for (start_offset, query_match) in query_matches {
13922                    let query_match = query_match.unwrap(); // can only fail due to I/O
13923                    let offset_range =
13924                        start_offset + query_match.start()..start_offset + query_match.end();
13925
13926                    if !select_next_state.wordwise
13927                        || (!buffer.is_inside_word(offset_range.start, false)
13928                            && !buffer.is_inside_word(offset_range.end, false))
13929                    {
13930                        // TODO: This is n^2, because we might check all the selections
13931                        if !selections
13932                            .iter()
13933                            .any(|selection| selection.range().overlaps(&offset_range))
13934                        {
13935                            next_selected_range = Some(offset_range);
13936                            break;
13937                        }
13938                    }
13939                }
13940
13941                if let Some(next_selected_range) = next_selected_range {
13942                    self.select_match_ranges(
13943                        next_selected_range,
13944                        last_selection.reversed,
13945                        replace_newest,
13946                        autoscroll,
13947                        window,
13948                        cx,
13949                    );
13950                } else {
13951                    select_next_state.done = true;
13952                }
13953            }
13954
13955            self.select_next_state = Some(select_next_state);
13956        } else {
13957            let mut only_carets = true;
13958            let mut same_text_selected = true;
13959            let mut selected_text = None;
13960
13961            let mut selections_iter = selections.iter().peekable();
13962            while let Some(selection) = selections_iter.next() {
13963                if selection.start != selection.end {
13964                    only_carets = false;
13965                }
13966
13967                if same_text_selected {
13968                    if selected_text.is_none() {
13969                        selected_text =
13970                            Some(buffer.text_for_range(selection.range()).collect::<String>());
13971                    }
13972
13973                    if let Some(next_selection) = selections_iter.peek() {
13974                        if next_selection.range().len() == selection.range().len() {
13975                            let next_selected_text = buffer
13976                                .text_for_range(next_selection.range())
13977                                .collect::<String>();
13978                            if Some(next_selected_text) != selected_text {
13979                                same_text_selected = false;
13980                                selected_text = None;
13981                            }
13982                        } else {
13983                            same_text_selected = false;
13984                            selected_text = None;
13985                        }
13986                    }
13987                }
13988            }
13989
13990            if only_carets {
13991                for selection in &mut selections {
13992                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
13993                    selection.start = word_range.start;
13994                    selection.end = word_range.end;
13995                    selection.goal = SelectionGoal::None;
13996                    selection.reversed = false;
13997                    self.select_match_ranges(
13998                        selection.start..selection.end,
13999                        selection.reversed,
14000                        replace_newest,
14001                        autoscroll,
14002                        window,
14003                        cx,
14004                    );
14005                }
14006
14007                if selections.len() == 1 {
14008                    let selection = selections
14009                        .last()
14010                        .expect("ensured that there's only one selection");
14011                    let query = buffer
14012                        .text_for_range(selection.start..selection.end)
14013                        .collect::<String>();
14014                    let is_empty = query.is_empty();
14015                    let select_state = SelectNextState {
14016                        query: AhoCorasick::new(&[query])?,
14017                        wordwise: true,
14018                        done: is_empty,
14019                    };
14020                    self.select_next_state = Some(select_state);
14021                } else {
14022                    self.select_next_state = None;
14023                }
14024            } else if let Some(selected_text) = selected_text {
14025                self.select_next_state = Some(SelectNextState {
14026                    query: AhoCorasick::new(&[selected_text])?,
14027                    wordwise: false,
14028                    done: false,
14029                });
14030                self.select_next_match_internal(
14031                    display_map,
14032                    replace_newest,
14033                    autoscroll,
14034                    window,
14035                    cx,
14036                )?;
14037            }
14038        }
14039        Ok(())
14040    }
14041
14042    pub fn select_all_matches(
14043        &mut self,
14044        _action: &SelectAllMatches,
14045        window: &mut Window,
14046        cx: &mut Context<Self>,
14047    ) -> Result<()> {
14048        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14049
14050        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14051
14052        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14053        let Some(select_next_state) = self.select_next_state.as_mut() else {
14054            return Ok(());
14055        };
14056        if select_next_state.done {
14057            return Ok(());
14058        }
14059
14060        let mut new_selections = Vec::new();
14061
14062        let reversed = self.selections.oldest::<usize>(cx).reversed;
14063        let buffer = &display_map.buffer_snapshot;
14064        let query_matches = select_next_state
14065            .query
14066            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14067
14068        for query_match in query_matches.into_iter() {
14069            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14070            let offset_range = if reversed {
14071                query_match.end()..query_match.start()
14072            } else {
14073                query_match.start()..query_match.end()
14074            };
14075
14076            if !select_next_state.wordwise
14077                || (!buffer.is_inside_word(offset_range.start, false)
14078                    && !buffer.is_inside_word(offset_range.end, false))
14079            {
14080                new_selections.push(offset_range.start..offset_range.end);
14081            }
14082        }
14083
14084        select_next_state.done = true;
14085
14086        if new_selections.is_empty() {
14087            log::error!("bug: new_selections is empty in select_all_matches");
14088            return Ok(());
14089        }
14090
14091        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14092        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14093            selections.select_ranges(new_selections)
14094        });
14095
14096        Ok(())
14097    }
14098
14099    pub fn select_next(
14100        &mut self,
14101        action: &SelectNext,
14102        window: &mut Window,
14103        cx: &mut Context<Self>,
14104    ) -> Result<()> {
14105        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14106        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14107        self.select_next_match_internal(
14108            &display_map,
14109            action.replace_newest,
14110            Some(Autoscroll::newest()),
14111            window,
14112            cx,
14113        )?;
14114        Ok(())
14115    }
14116
14117    pub fn select_previous(
14118        &mut self,
14119        action: &SelectPrevious,
14120        window: &mut Window,
14121        cx: &mut Context<Self>,
14122    ) -> Result<()> {
14123        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14124        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14125        let buffer = &display_map.buffer_snapshot;
14126        let mut selections = self.selections.all::<usize>(cx);
14127        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14128            let query = &select_prev_state.query;
14129            if !select_prev_state.done {
14130                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14131                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14132                let mut next_selected_range = None;
14133                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14134                let bytes_before_last_selection =
14135                    buffer.reversed_bytes_in_range(0..last_selection.start);
14136                let bytes_after_first_selection =
14137                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14138                let query_matches = query
14139                    .stream_find_iter(bytes_before_last_selection)
14140                    .map(|result| (last_selection.start, result))
14141                    .chain(
14142                        query
14143                            .stream_find_iter(bytes_after_first_selection)
14144                            .map(|result| (buffer.len(), result)),
14145                    );
14146                for (end_offset, query_match) in query_matches {
14147                    let query_match = query_match.unwrap(); // can only fail due to I/O
14148                    let offset_range =
14149                        end_offset - query_match.end()..end_offset - query_match.start();
14150
14151                    if !select_prev_state.wordwise
14152                        || (!buffer.is_inside_word(offset_range.start, false)
14153                            && !buffer.is_inside_word(offset_range.end, false))
14154                    {
14155                        next_selected_range = Some(offset_range);
14156                        break;
14157                    }
14158                }
14159
14160                if let Some(next_selected_range) = next_selected_range {
14161                    self.select_match_ranges(
14162                        next_selected_range,
14163                        last_selection.reversed,
14164                        action.replace_newest,
14165                        Some(Autoscroll::newest()),
14166                        window,
14167                        cx,
14168                    );
14169                } else {
14170                    select_prev_state.done = true;
14171                }
14172            }
14173
14174            self.select_prev_state = Some(select_prev_state);
14175        } else {
14176            let mut only_carets = true;
14177            let mut same_text_selected = true;
14178            let mut selected_text = None;
14179
14180            let mut selections_iter = selections.iter().peekable();
14181            while let Some(selection) = selections_iter.next() {
14182                if selection.start != selection.end {
14183                    only_carets = false;
14184                }
14185
14186                if same_text_selected {
14187                    if selected_text.is_none() {
14188                        selected_text =
14189                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14190                    }
14191
14192                    if let Some(next_selection) = selections_iter.peek() {
14193                        if next_selection.range().len() == selection.range().len() {
14194                            let next_selected_text = buffer
14195                                .text_for_range(next_selection.range())
14196                                .collect::<String>();
14197                            if Some(next_selected_text) != selected_text {
14198                                same_text_selected = false;
14199                                selected_text = None;
14200                            }
14201                        } else {
14202                            same_text_selected = false;
14203                            selected_text = None;
14204                        }
14205                    }
14206                }
14207            }
14208
14209            if only_carets {
14210                for selection in &mut selections {
14211                    let (word_range, _) = buffer.surrounding_word(selection.start, false);
14212                    selection.start = word_range.start;
14213                    selection.end = word_range.end;
14214                    selection.goal = SelectionGoal::None;
14215                    selection.reversed = false;
14216                    self.select_match_ranges(
14217                        selection.start..selection.end,
14218                        selection.reversed,
14219                        action.replace_newest,
14220                        Some(Autoscroll::newest()),
14221                        window,
14222                        cx,
14223                    );
14224                }
14225                if selections.len() == 1 {
14226                    let selection = selections
14227                        .last()
14228                        .expect("ensured that there's only one selection");
14229                    let query = buffer
14230                        .text_for_range(selection.start..selection.end)
14231                        .collect::<String>();
14232                    let is_empty = query.is_empty();
14233                    let select_state = SelectNextState {
14234                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14235                        wordwise: true,
14236                        done: is_empty,
14237                    };
14238                    self.select_prev_state = Some(select_state);
14239                } else {
14240                    self.select_prev_state = None;
14241                }
14242            } else if let Some(selected_text) = selected_text {
14243                self.select_prev_state = Some(SelectNextState {
14244                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14245                    wordwise: false,
14246                    done: false,
14247                });
14248                self.select_previous(action, window, cx)?;
14249            }
14250        }
14251        Ok(())
14252    }
14253
14254    pub fn find_next_match(
14255        &mut self,
14256        _: &FindNextMatch,
14257        window: &mut Window,
14258        cx: &mut Context<Self>,
14259    ) -> Result<()> {
14260        let selections = self.selections.disjoint_anchors();
14261        match selections.first() {
14262            Some(first) if selections.len() >= 2 => {
14263                self.change_selections(Default::default(), window, cx, |s| {
14264                    s.select_ranges([first.range()]);
14265                });
14266            }
14267            _ => self.select_next(
14268                &SelectNext {
14269                    replace_newest: true,
14270                },
14271                window,
14272                cx,
14273            )?,
14274        }
14275        Ok(())
14276    }
14277
14278    pub fn find_previous_match(
14279        &mut self,
14280        _: &FindPreviousMatch,
14281        window: &mut Window,
14282        cx: &mut Context<Self>,
14283    ) -> Result<()> {
14284        let selections = self.selections.disjoint_anchors();
14285        match selections.last() {
14286            Some(last) if selections.len() >= 2 => {
14287                self.change_selections(Default::default(), window, cx, |s| {
14288                    s.select_ranges([last.range()]);
14289                });
14290            }
14291            _ => self.select_previous(
14292                &SelectPrevious {
14293                    replace_newest: true,
14294                },
14295                window,
14296                cx,
14297            )?,
14298        }
14299        Ok(())
14300    }
14301
14302    pub fn toggle_comments(
14303        &mut self,
14304        action: &ToggleComments,
14305        window: &mut Window,
14306        cx: &mut Context<Self>,
14307    ) {
14308        if self.read_only(cx) {
14309            return;
14310        }
14311        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14312        let text_layout_details = &self.text_layout_details(window);
14313        self.transact(window, cx, |this, window, cx| {
14314            let mut selections = this.selections.all::<MultiBufferPoint>(cx);
14315            let mut edits = Vec::new();
14316            let mut selection_edit_ranges = Vec::new();
14317            let mut last_toggled_row = None;
14318            let snapshot = this.buffer.read(cx).read(cx);
14319            let empty_str: Arc<str> = Arc::default();
14320            let mut suffixes_inserted = Vec::new();
14321            let ignore_indent = action.ignore_indent;
14322
14323            fn comment_prefix_range(
14324                snapshot: &MultiBufferSnapshot,
14325                row: MultiBufferRow,
14326                comment_prefix: &str,
14327                comment_prefix_whitespace: &str,
14328                ignore_indent: bool,
14329            ) -> Range<Point> {
14330                let indent_size = if ignore_indent {
14331                    0
14332                } else {
14333                    snapshot.indent_size_for_line(row).len
14334                };
14335
14336                let start = Point::new(row.0, indent_size);
14337
14338                let mut line_bytes = snapshot
14339                    .bytes_in_range(start..snapshot.max_point())
14340                    .flatten()
14341                    .copied();
14342
14343                // If this line currently begins with the line comment prefix, then record
14344                // the range containing the prefix.
14345                if line_bytes
14346                    .by_ref()
14347                    .take(comment_prefix.len())
14348                    .eq(comment_prefix.bytes())
14349                {
14350                    // Include any whitespace that matches the comment prefix.
14351                    let matching_whitespace_len = line_bytes
14352                        .zip(comment_prefix_whitespace.bytes())
14353                        .take_while(|(a, b)| a == b)
14354                        .count() as u32;
14355                    let end = Point::new(
14356                        start.row,
14357                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14358                    );
14359                    start..end
14360                } else {
14361                    start..start
14362                }
14363            }
14364
14365            fn comment_suffix_range(
14366                snapshot: &MultiBufferSnapshot,
14367                row: MultiBufferRow,
14368                comment_suffix: &str,
14369                comment_suffix_has_leading_space: bool,
14370            ) -> Range<Point> {
14371                let end = Point::new(row.0, snapshot.line_len(row));
14372                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14373
14374                let mut line_end_bytes = snapshot
14375                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14376                    .flatten()
14377                    .copied();
14378
14379                let leading_space_len = if suffix_start_column > 0
14380                    && line_end_bytes.next() == Some(b' ')
14381                    && comment_suffix_has_leading_space
14382                {
14383                    1
14384                } else {
14385                    0
14386                };
14387
14388                // If this line currently begins with the line comment prefix, then record
14389                // the range containing the prefix.
14390                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14391                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14392                    start..end
14393                } else {
14394                    end..end
14395                }
14396            }
14397
14398            // TODO: Handle selections that cross excerpts
14399            for selection in &mut selections {
14400                let start_column = snapshot
14401                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14402                    .len;
14403                let language = if let Some(language) =
14404                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14405                {
14406                    language
14407                } else {
14408                    continue;
14409                };
14410
14411                selection_edit_ranges.clear();
14412
14413                // If multiple selections contain a given row, avoid processing that
14414                // row more than once.
14415                let mut start_row = MultiBufferRow(selection.start.row);
14416                if last_toggled_row == Some(start_row) {
14417                    start_row = start_row.next_row();
14418                }
14419                let end_row =
14420                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14421                        MultiBufferRow(selection.end.row - 1)
14422                    } else {
14423                        MultiBufferRow(selection.end.row)
14424                    };
14425                last_toggled_row = Some(end_row);
14426
14427                if start_row > end_row {
14428                    continue;
14429                }
14430
14431                // If the language has line comments, toggle those.
14432                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14433
14434                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14435                if ignore_indent {
14436                    full_comment_prefixes = full_comment_prefixes
14437                        .into_iter()
14438                        .map(|s| Arc::from(s.trim_end()))
14439                        .collect();
14440                }
14441
14442                if !full_comment_prefixes.is_empty() {
14443                    let first_prefix = full_comment_prefixes
14444                        .first()
14445                        .expect("prefixes is non-empty");
14446                    let prefix_trimmed_lengths = full_comment_prefixes
14447                        .iter()
14448                        .map(|p| p.trim_end_matches(' ').len())
14449                        .collect::<SmallVec<[usize; 4]>>();
14450
14451                    let mut all_selection_lines_are_comments = true;
14452
14453                    for row in start_row.0..=end_row.0 {
14454                        let row = MultiBufferRow(row);
14455                        if start_row < end_row && snapshot.is_line_blank(row) {
14456                            continue;
14457                        }
14458
14459                        let prefix_range = full_comment_prefixes
14460                            .iter()
14461                            .zip(prefix_trimmed_lengths.iter().copied())
14462                            .map(|(prefix, trimmed_prefix_len)| {
14463                                comment_prefix_range(
14464                                    snapshot.deref(),
14465                                    row,
14466                                    &prefix[..trimmed_prefix_len],
14467                                    &prefix[trimmed_prefix_len..],
14468                                    ignore_indent,
14469                                )
14470                            })
14471                            .max_by_key(|range| range.end.column - range.start.column)
14472                            .expect("prefixes is non-empty");
14473
14474                        if prefix_range.is_empty() {
14475                            all_selection_lines_are_comments = false;
14476                        }
14477
14478                        selection_edit_ranges.push(prefix_range);
14479                    }
14480
14481                    if all_selection_lines_are_comments {
14482                        edits.extend(
14483                            selection_edit_ranges
14484                                .iter()
14485                                .cloned()
14486                                .map(|range| (range, empty_str.clone())),
14487                        );
14488                    } else {
14489                        let min_column = selection_edit_ranges
14490                            .iter()
14491                            .map(|range| range.start.column)
14492                            .min()
14493                            .unwrap_or(0);
14494                        edits.extend(selection_edit_ranges.iter().map(|range| {
14495                            let position = Point::new(range.start.row, min_column);
14496                            (position..position, first_prefix.clone())
14497                        }));
14498                    }
14499                } else if let Some(BlockCommentConfig {
14500                    start: full_comment_prefix,
14501                    end: comment_suffix,
14502                    ..
14503                }) = language.block_comment()
14504                {
14505                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14506                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14507                    let prefix_range = comment_prefix_range(
14508                        snapshot.deref(),
14509                        start_row,
14510                        comment_prefix,
14511                        comment_prefix_whitespace,
14512                        ignore_indent,
14513                    );
14514                    let suffix_range = comment_suffix_range(
14515                        snapshot.deref(),
14516                        end_row,
14517                        comment_suffix.trim_start_matches(' '),
14518                        comment_suffix.starts_with(' '),
14519                    );
14520
14521                    if prefix_range.is_empty() || suffix_range.is_empty() {
14522                        edits.push((
14523                            prefix_range.start..prefix_range.start,
14524                            full_comment_prefix.clone(),
14525                        ));
14526                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
14527                        suffixes_inserted.push((end_row, comment_suffix.len()));
14528                    } else {
14529                        edits.push((prefix_range, empty_str.clone()));
14530                        edits.push((suffix_range, empty_str.clone()));
14531                    }
14532                } else {
14533                    continue;
14534                }
14535            }
14536
14537            drop(snapshot);
14538            this.buffer.update(cx, |buffer, cx| {
14539                buffer.edit(edits, None, cx);
14540            });
14541
14542            // Adjust selections so that they end before any comment suffixes that
14543            // were inserted.
14544            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
14545            let mut selections = this.selections.all::<Point>(cx);
14546            let snapshot = this.buffer.read(cx).read(cx);
14547            for selection in &mut selections {
14548                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
14549                    match row.cmp(&MultiBufferRow(selection.end.row)) {
14550                        Ordering::Less => {
14551                            suffixes_inserted.next();
14552                            continue;
14553                        }
14554                        Ordering::Greater => break,
14555                        Ordering::Equal => {
14556                            if selection.end.column == snapshot.line_len(row) {
14557                                if selection.is_empty() {
14558                                    selection.start.column -= suffix_len as u32;
14559                                }
14560                                selection.end.column -= suffix_len as u32;
14561                            }
14562                            break;
14563                        }
14564                    }
14565                }
14566            }
14567
14568            drop(snapshot);
14569            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14570
14571            let selections = this.selections.all::<Point>(cx);
14572            let selections_on_single_row = selections.windows(2).all(|selections| {
14573                selections[0].start.row == selections[1].start.row
14574                    && selections[0].end.row == selections[1].end.row
14575                    && selections[0].start.row == selections[0].end.row
14576            });
14577            let selections_selecting = selections
14578                .iter()
14579                .any(|selection| selection.start != selection.end);
14580            let advance_downwards = action.advance_downwards
14581                && selections_on_single_row
14582                && !selections_selecting
14583                && !matches!(this.mode, EditorMode::SingleLine { .. });
14584
14585            if advance_downwards {
14586                let snapshot = this.buffer.read(cx).snapshot(cx);
14587
14588                this.change_selections(Default::default(), window, cx, |s| {
14589                    s.move_cursors_with(|display_snapshot, display_point, _| {
14590                        let mut point = display_point.to_point(display_snapshot);
14591                        point.row += 1;
14592                        point = snapshot.clip_point(point, Bias::Left);
14593                        let display_point = point.to_display_point(display_snapshot);
14594                        let goal = SelectionGoal::HorizontalPosition(
14595                            display_snapshot
14596                                .x_for_display_point(display_point, text_layout_details)
14597                                .into(),
14598                        );
14599                        (display_point, goal)
14600                    })
14601                });
14602            }
14603        });
14604    }
14605
14606    pub fn select_enclosing_symbol(
14607        &mut self,
14608        _: &SelectEnclosingSymbol,
14609        window: &mut Window,
14610        cx: &mut Context<Self>,
14611    ) {
14612        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14613
14614        let buffer = self.buffer.read(cx).snapshot(cx);
14615        let old_selections = self.selections.all::<usize>(cx).into_boxed_slice();
14616
14617        fn update_selection(
14618            selection: &Selection<usize>,
14619            buffer_snap: &MultiBufferSnapshot,
14620        ) -> Option<Selection<usize>> {
14621            let cursor = selection.head();
14622            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
14623            for symbol in symbols.iter().rev() {
14624                let start = symbol.range.start.to_offset(buffer_snap);
14625                let end = symbol.range.end.to_offset(buffer_snap);
14626                let new_range = start..end;
14627                if start < selection.start || end > selection.end {
14628                    return Some(Selection {
14629                        id: selection.id,
14630                        start: new_range.start,
14631                        end: new_range.end,
14632                        goal: SelectionGoal::None,
14633                        reversed: selection.reversed,
14634                    });
14635                }
14636            }
14637            None
14638        }
14639
14640        let mut selected_larger_symbol = false;
14641        let new_selections = old_selections
14642            .iter()
14643            .map(|selection| match update_selection(selection, &buffer) {
14644                Some(new_selection) => {
14645                    if new_selection.range() != selection.range() {
14646                        selected_larger_symbol = true;
14647                    }
14648                    new_selection
14649                }
14650                None => selection.clone(),
14651            })
14652            .collect::<Vec<_>>();
14653
14654        if selected_larger_symbol {
14655            self.change_selections(Default::default(), window, cx, |s| {
14656                s.select(new_selections);
14657            });
14658        }
14659    }
14660
14661    pub fn select_larger_syntax_node(
14662        &mut self,
14663        _: &SelectLargerSyntaxNode,
14664        window: &mut Window,
14665        cx: &mut Context<Self>,
14666    ) {
14667        let Some(visible_row_count) = self.visible_row_count() else {
14668            return;
14669        };
14670        let old_selections: Box<[_]> = self.selections.all::<usize>(cx).into();
14671        if old_selections.is_empty() {
14672            return;
14673        }
14674
14675        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14676
14677        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14678        let buffer = self.buffer.read(cx).snapshot(cx);
14679
14680        let mut selected_larger_node = false;
14681        let mut new_selections = old_selections
14682            .iter()
14683            .map(|selection| {
14684                let old_range = selection.start..selection.end;
14685
14686                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
14687                    // manually select word at selection
14688                    if ["string_content", "inline"].contains(&node.kind()) {
14689                        let (word_range, _) = buffer.surrounding_word(old_range.start, false);
14690                        // ignore if word is already selected
14691                        if !word_range.is_empty() && old_range != word_range {
14692                            let (last_word_range, _) =
14693                                buffer.surrounding_word(old_range.end, false);
14694                            // only select word if start and end point belongs to same word
14695                            if word_range == last_word_range {
14696                                selected_larger_node = true;
14697                                return Selection {
14698                                    id: selection.id,
14699                                    start: word_range.start,
14700                                    end: word_range.end,
14701                                    goal: SelectionGoal::None,
14702                                    reversed: selection.reversed,
14703                                };
14704                            }
14705                        }
14706                    }
14707                }
14708
14709                let mut new_range = old_range.clone();
14710                while let Some((_node, containing_range)) =
14711                    buffer.syntax_ancestor(new_range.clone())
14712                {
14713                    new_range = match containing_range {
14714                        MultiOrSingleBufferOffsetRange::Single(_) => break,
14715                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14716                    };
14717                    if !display_map.intersects_fold(new_range.start)
14718                        && !display_map.intersects_fold(new_range.end)
14719                    {
14720                        break;
14721                    }
14722                }
14723
14724                selected_larger_node |= new_range != old_range;
14725                Selection {
14726                    id: selection.id,
14727                    start: new_range.start,
14728                    end: new_range.end,
14729                    goal: SelectionGoal::None,
14730                    reversed: selection.reversed,
14731                }
14732            })
14733            .collect::<Vec<_>>();
14734
14735        if !selected_larger_node {
14736            return; // don't put this call in the history
14737        }
14738
14739        // scroll based on transformation done to the last selection created by the user
14740        let (last_old, last_new) = old_selections
14741            .last()
14742            .zip(new_selections.last().cloned())
14743            .expect("old_selections isn't empty");
14744
14745        // revert selection
14746        let is_selection_reversed = {
14747            let should_newest_selection_be_reversed = last_old.start != last_new.start;
14748            new_selections.last_mut().expect("checked above").reversed =
14749                should_newest_selection_be_reversed;
14750            should_newest_selection_be_reversed
14751        };
14752
14753        if selected_larger_node {
14754            self.select_syntax_node_history.disable_clearing = true;
14755            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14756                s.select(new_selections.clone());
14757            });
14758            self.select_syntax_node_history.disable_clearing = false;
14759        }
14760
14761        let start_row = last_new.start.to_display_point(&display_map).row().0;
14762        let end_row = last_new.end.to_display_point(&display_map).row().0;
14763        let selection_height = end_row - start_row + 1;
14764        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
14765
14766        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
14767        let scroll_behavior = if fits_on_the_screen {
14768            self.request_autoscroll(Autoscroll::fit(), cx);
14769            SelectSyntaxNodeScrollBehavior::FitSelection
14770        } else if is_selection_reversed {
14771            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14772            SelectSyntaxNodeScrollBehavior::CursorTop
14773        } else {
14774            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14775            SelectSyntaxNodeScrollBehavior::CursorBottom
14776        };
14777
14778        self.select_syntax_node_history.push((
14779            old_selections,
14780            scroll_behavior,
14781            is_selection_reversed,
14782        ));
14783    }
14784
14785    pub fn select_smaller_syntax_node(
14786        &mut self,
14787        _: &SelectSmallerSyntaxNode,
14788        window: &mut Window,
14789        cx: &mut Context<Self>,
14790    ) {
14791        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14792
14793        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
14794            self.select_syntax_node_history.pop()
14795        {
14796            if let Some(selection) = selections.last_mut() {
14797                selection.reversed = is_selection_reversed;
14798            }
14799
14800            self.select_syntax_node_history.disable_clearing = true;
14801            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14802                s.select(selections.to_vec());
14803            });
14804            self.select_syntax_node_history.disable_clearing = false;
14805
14806            match scroll_behavior {
14807                SelectSyntaxNodeScrollBehavior::CursorTop => {
14808                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
14809                }
14810                SelectSyntaxNodeScrollBehavior::FitSelection => {
14811                    self.request_autoscroll(Autoscroll::fit(), cx);
14812                }
14813                SelectSyntaxNodeScrollBehavior::CursorBottom => {
14814                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
14815                }
14816            }
14817        }
14818    }
14819
14820    pub fn unwrap_syntax_node(
14821        &mut self,
14822        _: &UnwrapSyntaxNode,
14823        window: &mut Window,
14824        cx: &mut Context<Self>,
14825    ) {
14826        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14827
14828        let buffer = self.buffer.read(cx).snapshot(cx);
14829        let selections = self
14830            .selections
14831            .all::<usize>(cx)
14832            .into_iter()
14833            // subtracting the offset requires sorting
14834            .sorted_by_key(|i| i.start);
14835
14836        let full_edits = selections
14837            .into_iter()
14838            .filter_map(|selection| {
14839                // Only requires two branches once if-let-chains stabilize (#53667)
14840                let child = if !selection.is_empty() {
14841                    selection.range()
14842                } else if let Some((_, ancestor_range)) =
14843                    buffer.syntax_ancestor(selection.start..selection.end)
14844                {
14845                    match ancestor_range {
14846                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14847                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14848                    }
14849                } else {
14850                    selection.range()
14851                };
14852
14853                let mut parent = child.clone();
14854                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
14855                    parent = match ancestor_range {
14856                        MultiOrSingleBufferOffsetRange::Single(range) => range,
14857                        MultiOrSingleBufferOffsetRange::Multi(range) => range,
14858                    };
14859                    if parent.start < child.start || parent.end > child.end {
14860                        break;
14861                    }
14862                }
14863
14864                if parent == child {
14865                    return None;
14866                }
14867                let text = buffer.text_for_range(child.clone()).collect::<String>();
14868                Some((selection.id, parent, text))
14869            })
14870            .collect::<Vec<_>>();
14871
14872        self.transact(window, cx, |this, window, cx| {
14873            this.buffer.update(cx, |buffer, cx| {
14874                buffer.edit(
14875                    full_edits
14876                        .iter()
14877                        .map(|(_, p, t)| (p.clone(), t.clone()))
14878                        .collect::<Vec<_>>(),
14879                    None,
14880                    cx,
14881                );
14882            });
14883            this.change_selections(Default::default(), window, cx, |s| {
14884                let mut offset = 0;
14885                let mut selections = vec![];
14886                for (id, parent, text) in full_edits {
14887                    let start = parent.start - offset;
14888                    offset += parent.len() - text.len();
14889                    selections.push(Selection {
14890                        id: id,
14891                        start,
14892                        end: start + text.len(),
14893                        reversed: false,
14894                        goal: Default::default(),
14895                    });
14896                }
14897                s.select(selections);
14898            });
14899        });
14900    }
14901
14902    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
14903        if !EditorSettings::get_global(cx).gutter.runnables {
14904            self.clear_tasks();
14905            return Task::ready(());
14906        }
14907        let project = self.project().map(Entity::downgrade);
14908        let task_sources = self.lsp_task_sources(cx);
14909        let multi_buffer = self.buffer.downgrade();
14910        cx.spawn_in(window, async move |editor, cx| {
14911            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
14912            let Some(project) = project.and_then(|p| p.upgrade()) else {
14913                return;
14914            };
14915            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
14916                this.display_map.update(cx, |map, cx| map.snapshot(cx))
14917            }) else {
14918                return;
14919            };
14920
14921            let hide_runnables = project
14922                .update(cx, |project, cx| {
14923                    // Do not display any test indicators in non-dev server remote projects.
14924                    project.is_via_collab() && project.ssh_connection_string(cx).is_none()
14925                })
14926                .unwrap_or(true);
14927            if hide_runnables {
14928                return;
14929            }
14930            let new_rows =
14931                cx.background_spawn({
14932                    let snapshot = display_snapshot.clone();
14933                    async move {
14934                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
14935                    }
14936                })
14937                    .await;
14938            let Ok(lsp_tasks) =
14939                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
14940            else {
14941                return;
14942            };
14943            let lsp_tasks = lsp_tasks.await;
14944
14945            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
14946                lsp_tasks
14947                    .into_iter()
14948                    .flat_map(|(kind, tasks)| {
14949                        tasks.into_iter().filter_map(move |(location, task)| {
14950                            Some((kind.clone(), location?, task))
14951                        })
14952                    })
14953                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
14954                        let buffer = location.target.buffer;
14955                        let buffer_snapshot = buffer.read(cx).snapshot();
14956                        let offset = display_snapshot.buffer_snapshot.excerpts().find_map(
14957                            |(excerpt_id, snapshot, _)| {
14958                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
14959                                    display_snapshot
14960                                        .buffer_snapshot
14961                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
14962                                } else {
14963                                    None
14964                                }
14965                            },
14966                        );
14967                        if let Some(offset) = offset {
14968                            let task_buffer_range =
14969                                location.target.range.to_point(&buffer_snapshot);
14970                            let context_buffer_range =
14971                                task_buffer_range.to_offset(&buffer_snapshot);
14972                            let context_range = BufferOffset(context_buffer_range.start)
14973                                ..BufferOffset(context_buffer_range.end);
14974
14975                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
14976                                .or_insert_with(|| RunnableTasks {
14977                                    templates: Vec::new(),
14978                                    offset,
14979                                    column: task_buffer_range.start.column,
14980                                    extra_variables: HashMap::default(),
14981                                    context_range,
14982                                })
14983                                .templates
14984                                .push((kind, task.original_task().clone()));
14985                        }
14986
14987                        acc
14988                    })
14989            }) else {
14990                return;
14991            };
14992
14993            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
14994                buffer.language_settings(cx).tasks.prefer_lsp
14995            }) else {
14996                return;
14997            };
14998
14999            let rows = Self::runnable_rows(
15000                project,
15001                display_snapshot,
15002                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15003                new_rows,
15004                cx.clone(),
15005            )
15006            .await;
15007            editor
15008                .update(cx, |editor, _| {
15009                    editor.clear_tasks();
15010                    for (key, mut value) in rows {
15011                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15012                            value.templates.extend(lsp_tasks.templates);
15013                        }
15014
15015                        editor.insert_tasks(key, value);
15016                    }
15017                    for (key, value) in lsp_tasks_by_rows {
15018                        editor.insert_tasks(key, value);
15019                    }
15020                })
15021                .ok();
15022        })
15023    }
15024    fn fetch_runnable_ranges(
15025        snapshot: &DisplaySnapshot,
15026        range: Range<Anchor>,
15027    ) -> Vec<language::RunnableRange> {
15028        snapshot.buffer_snapshot.runnable_ranges(range).collect()
15029    }
15030
15031    fn runnable_rows(
15032        project: Entity<Project>,
15033        snapshot: DisplaySnapshot,
15034        prefer_lsp: bool,
15035        runnable_ranges: Vec<RunnableRange>,
15036        cx: AsyncWindowContext,
15037    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15038        cx.spawn(async move |cx| {
15039            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15040            for mut runnable in runnable_ranges {
15041                let Some(tasks) = cx
15042                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15043                    .ok()
15044                else {
15045                    continue;
15046                };
15047                let mut tasks = tasks.await;
15048
15049                if prefer_lsp {
15050                    tasks.retain(|(task_kind, _)| {
15051                        !matches!(task_kind, TaskSourceKind::Language { .. })
15052                    });
15053                }
15054                if tasks.is_empty() {
15055                    continue;
15056                }
15057
15058                let point = runnable.run_range.start.to_point(&snapshot.buffer_snapshot);
15059                let Some(row) = snapshot
15060                    .buffer_snapshot
15061                    .buffer_line_for_row(MultiBufferRow(point.row))
15062                    .map(|(_, range)| range.start.row)
15063                else {
15064                    continue;
15065                };
15066
15067                let context_range =
15068                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15069                runnable_rows.push((
15070                    (runnable.buffer_id, row),
15071                    RunnableTasks {
15072                        templates: tasks,
15073                        offset: snapshot
15074                            .buffer_snapshot
15075                            .anchor_before(runnable.run_range.start),
15076                        context_range,
15077                        column: point.column,
15078                        extra_variables: runnable.extra_captures,
15079                    },
15080                ));
15081            }
15082            runnable_rows
15083        })
15084    }
15085
15086    fn templates_with_tags(
15087        project: &Entity<Project>,
15088        runnable: &mut Runnable,
15089        cx: &mut App,
15090    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15091        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15092            let (worktree_id, file) = project
15093                .buffer_for_id(runnable.buffer, cx)
15094                .and_then(|buffer| buffer.read(cx).file())
15095                .map(|file| (file.worktree_id(cx), file.clone()))
15096                .unzip();
15097
15098            (
15099                project.task_store().read(cx).task_inventory().cloned(),
15100                worktree_id,
15101                file,
15102            )
15103        });
15104
15105        let tags = mem::take(&mut runnable.tags);
15106        let language = runnable.language.clone();
15107        cx.spawn(async move |cx| {
15108            let mut templates_with_tags = Vec::new();
15109            if let Some(inventory) = inventory {
15110                for RunnableTag(tag) in tags {
15111                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15112                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15113                    }) else {
15114                        return templates_with_tags;
15115                    };
15116                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15117                        move |(_, template)| {
15118                            template.tags.iter().any(|source_tag| source_tag == &tag)
15119                        },
15120                    ));
15121                }
15122            }
15123            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15124
15125            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15126                // Strongest source wins; if we have worktree tag binding, prefer that to
15127                // global and language bindings;
15128                // if we have a global binding, prefer that to language binding.
15129                let first_mismatch = templates_with_tags
15130                    .iter()
15131                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15132                if let Some(index) = first_mismatch {
15133                    templates_with_tags.truncate(index);
15134                }
15135            }
15136
15137            templates_with_tags
15138        })
15139    }
15140
15141    pub fn move_to_enclosing_bracket(
15142        &mut self,
15143        _: &MoveToEnclosingBracket,
15144        window: &mut Window,
15145        cx: &mut Context<Self>,
15146    ) {
15147        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15148        self.change_selections(Default::default(), window, cx, |s| {
15149            s.move_offsets_with(|snapshot, selection| {
15150                let Some(enclosing_bracket_ranges) =
15151                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15152                else {
15153                    return;
15154                };
15155
15156                let mut best_length = usize::MAX;
15157                let mut best_inside = false;
15158                let mut best_in_bracket_range = false;
15159                let mut best_destination = None;
15160                for (open, close) in enclosing_bracket_ranges {
15161                    let close = close.to_inclusive();
15162                    let length = close.end() - open.start;
15163                    let inside = selection.start >= open.end && selection.end <= *close.start();
15164                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15165                        || close.contains(&selection.head());
15166
15167                    // If best is next to a bracket and current isn't, skip
15168                    if !in_bracket_range && best_in_bracket_range {
15169                        continue;
15170                    }
15171
15172                    // Prefer smaller lengths unless best is inside and current isn't
15173                    if length > best_length && (best_inside || !inside) {
15174                        continue;
15175                    }
15176
15177                    best_length = length;
15178                    best_inside = inside;
15179                    best_in_bracket_range = in_bracket_range;
15180                    best_destination = Some(
15181                        if close.contains(&selection.start) && close.contains(&selection.end) {
15182                            if inside { open.end } else { open.start }
15183                        } else if inside {
15184                            *close.start()
15185                        } else {
15186                            *close.end()
15187                        },
15188                    );
15189                }
15190
15191                if let Some(destination) = best_destination {
15192                    selection.collapse_to(destination, SelectionGoal::None);
15193                }
15194            })
15195        });
15196    }
15197
15198    pub fn undo_selection(
15199        &mut self,
15200        _: &UndoSelection,
15201        window: &mut Window,
15202        cx: &mut Context<Self>,
15203    ) {
15204        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15205        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15206            self.selection_history.mode = SelectionHistoryMode::Undoing;
15207            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15208                this.end_selection(window, cx);
15209                this.change_selections(
15210                    SelectionEffects::scroll(Autoscroll::newest()),
15211                    window,
15212                    cx,
15213                    |s| s.select_anchors(entry.selections.to_vec()),
15214                );
15215            });
15216            self.selection_history.mode = SelectionHistoryMode::Normal;
15217
15218            self.select_next_state = entry.select_next_state;
15219            self.select_prev_state = entry.select_prev_state;
15220            self.add_selections_state = entry.add_selections_state;
15221        }
15222    }
15223
15224    pub fn redo_selection(
15225        &mut self,
15226        _: &RedoSelection,
15227        window: &mut Window,
15228        cx: &mut Context<Self>,
15229    ) {
15230        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15231        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15232            self.selection_history.mode = SelectionHistoryMode::Redoing;
15233            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15234                this.end_selection(window, cx);
15235                this.change_selections(
15236                    SelectionEffects::scroll(Autoscroll::newest()),
15237                    window,
15238                    cx,
15239                    |s| s.select_anchors(entry.selections.to_vec()),
15240                );
15241            });
15242            self.selection_history.mode = SelectionHistoryMode::Normal;
15243
15244            self.select_next_state = entry.select_next_state;
15245            self.select_prev_state = entry.select_prev_state;
15246            self.add_selections_state = entry.add_selections_state;
15247        }
15248    }
15249
15250    pub fn expand_excerpts(
15251        &mut self,
15252        action: &ExpandExcerpts,
15253        _: &mut Window,
15254        cx: &mut Context<Self>,
15255    ) {
15256        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15257    }
15258
15259    pub fn expand_excerpts_down(
15260        &mut self,
15261        action: &ExpandExcerptsDown,
15262        _: &mut Window,
15263        cx: &mut Context<Self>,
15264    ) {
15265        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15266    }
15267
15268    pub fn expand_excerpts_up(
15269        &mut self,
15270        action: &ExpandExcerptsUp,
15271        _: &mut Window,
15272        cx: &mut Context<Self>,
15273    ) {
15274        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15275    }
15276
15277    pub fn expand_excerpts_for_direction(
15278        &mut self,
15279        lines: u32,
15280        direction: ExpandExcerptDirection,
15281
15282        cx: &mut Context<Self>,
15283    ) {
15284        let selections = self.selections.disjoint_anchors();
15285
15286        let lines = if lines == 0 {
15287            EditorSettings::get_global(cx).expand_excerpt_lines
15288        } else {
15289            lines
15290        };
15291
15292        self.buffer.update(cx, |buffer, cx| {
15293            let snapshot = buffer.snapshot(cx);
15294            let mut excerpt_ids = selections
15295                .iter()
15296                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15297                .collect::<Vec<_>>();
15298            excerpt_ids.sort();
15299            excerpt_ids.dedup();
15300            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15301        })
15302    }
15303
15304    pub fn expand_excerpt(
15305        &mut self,
15306        excerpt: ExcerptId,
15307        direction: ExpandExcerptDirection,
15308        window: &mut Window,
15309        cx: &mut Context<Self>,
15310    ) {
15311        let current_scroll_position = self.scroll_position(cx);
15312        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15313        let mut should_scroll_up = false;
15314
15315        if direction == ExpandExcerptDirection::Down {
15316            let multi_buffer = self.buffer.read(cx);
15317            let snapshot = multi_buffer.snapshot(cx);
15318            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15319                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15320                && let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
15321            {
15322                let buffer_snapshot = buffer.read(cx).snapshot();
15323                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15324                let last_row = buffer_snapshot.max_point().row;
15325                let lines_below = last_row.saturating_sub(excerpt_end_row);
15326                should_scroll_up = lines_below >= lines_to_expand;
15327            }
15328        }
15329
15330        self.buffer.update(cx, |buffer, cx| {
15331            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15332        });
15333
15334        if should_scroll_up {
15335            let new_scroll_position =
15336                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
15337            self.set_scroll_position(new_scroll_position, window, cx);
15338        }
15339    }
15340
15341    pub fn go_to_singleton_buffer_point(
15342        &mut self,
15343        point: Point,
15344        window: &mut Window,
15345        cx: &mut Context<Self>,
15346    ) {
15347        self.go_to_singleton_buffer_range(point..point, window, cx);
15348    }
15349
15350    pub fn go_to_singleton_buffer_range(
15351        &mut self,
15352        range: Range<Point>,
15353        window: &mut Window,
15354        cx: &mut Context<Self>,
15355    ) {
15356        let multibuffer = self.buffer().read(cx);
15357        let Some(buffer) = multibuffer.as_singleton() else {
15358            return;
15359        };
15360        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15361            return;
15362        };
15363        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15364            return;
15365        };
15366        self.change_selections(
15367            SelectionEffects::default().nav_history(true),
15368            window,
15369            cx,
15370            |s| s.select_anchor_ranges([start..end]),
15371        );
15372    }
15373
15374    pub fn go_to_diagnostic(
15375        &mut self,
15376        action: &GoToDiagnostic,
15377        window: &mut Window,
15378        cx: &mut Context<Self>,
15379    ) {
15380        if !self.diagnostics_enabled() {
15381            return;
15382        }
15383        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15384        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15385    }
15386
15387    pub fn go_to_prev_diagnostic(
15388        &mut self,
15389        action: &GoToPreviousDiagnostic,
15390        window: &mut Window,
15391        cx: &mut Context<Self>,
15392    ) {
15393        if !self.diagnostics_enabled() {
15394            return;
15395        }
15396        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15397        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15398    }
15399
15400    pub fn go_to_diagnostic_impl(
15401        &mut self,
15402        direction: Direction,
15403        severity: GoToDiagnosticSeverityFilter,
15404        window: &mut Window,
15405        cx: &mut Context<Self>,
15406    ) {
15407        let buffer = self.buffer.read(cx).snapshot(cx);
15408        let selection = self.selections.newest::<usize>(cx);
15409
15410        let mut active_group_id = None;
15411        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
15412            && active_group.active_range.start.to_offset(&buffer) == selection.start
15413        {
15414            active_group_id = Some(active_group.group_id);
15415        }
15416
15417        fn filtered(
15418            snapshot: EditorSnapshot,
15419            severity: GoToDiagnosticSeverityFilter,
15420            diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
15421        ) -> impl Iterator<Item = DiagnosticEntry<usize>> {
15422            diagnostics
15423                .filter(move |entry| severity.matches(entry.diagnostic.severity))
15424                .filter(|entry| entry.range.start != entry.range.end)
15425                .filter(|entry| !entry.diagnostic.is_unnecessary)
15426                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
15427        }
15428
15429        let snapshot = self.snapshot(window, cx);
15430        let before = filtered(
15431            snapshot.clone(),
15432            severity,
15433            buffer
15434                .diagnostics_in_range(0..selection.start)
15435                .filter(|entry| entry.range.start <= selection.start),
15436        );
15437        let after = filtered(
15438            snapshot,
15439            severity,
15440            buffer
15441                .diagnostics_in_range(selection.start..buffer.len())
15442                .filter(|entry| entry.range.start >= selection.start),
15443        );
15444
15445        let mut found: Option<DiagnosticEntry<usize>> = None;
15446        if direction == Direction::Prev {
15447            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
15448            {
15449                for diagnostic in prev_diagnostics.into_iter().rev() {
15450                    if diagnostic.range.start != selection.start
15451                        || active_group_id
15452                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
15453                    {
15454                        found = Some(diagnostic);
15455                        break 'outer;
15456                    }
15457                }
15458            }
15459        } else {
15460            for diagnostic in after.chain(before) {
15461                if diagnostic.range.start != selection.start
15462                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
15463                {
15464                    found = Some(diagnostic);
15465                    break;
15466                }
15467            }
15468        }
15469        let Some(next_diagnostic) = found else {
15470            return;
15471        };
15472
15473        let Some(buffer_id) = buffer.anchor_after(next_diagnostic.range.start).buffer_id else {
15474            return;
15475        };
15476        self.change_selections(Default::default(), window, cx, |s| {
15477            s.select_ranges(vec![
15478                next_diagnostic.range.start..next_diagnostic.range.start,
15479            ])
15480        });
15481        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
15482        self.refresh_edit_prediction(false, true, window, cx);
15483    }
15484
15485    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
15486        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15487        let snapshot = self.snapshot(window, cx);
15488        let selection = self.selections.newest::<Point>(cx);
15489        self.go_to_hunk_before_or_after_position(
15490            &snapshot,
15491            selection.head(),
15492            Direction::Next,
15493            window,
15494            cx,
15495        );
15496    }
15497
15498    pub fn go_to_hunk_before_or_after_position(
15499        &mut self,
15500        snapshot: &EditorSnapshot,
15501        position: Point,
15502        direction: Direction,
15503        window: &mut Window,
15504        cx: &mut Context<Editor>,
15505    ) {
15506        let row = if direction == Direction::Next {
15507            self.hunk_after_position(snapshot, position)
15508                .map(|hunk| hunk.row_range.start)
15509        } else {
15510            self.hunk_before_position(snapshot, position)
15511        };
15512
15513        if let Some(row) = row {
15514            let destination = Point::new(row.0, 0);
15515            let autoscroll = Autoscroll::center();
15516
15517            self.unfold_ranges(&[destination..destination], false, false, cx);
15518            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
15519                s.select_ranges([destination..destination]);
15520            });
15521        }
15522    }
15523
15524    fn hunk_after_position(
15525        &mut self,
15526        snapshot: &EditorSnapshot,
15527        position: Point,
15528    ) -> Option<MultiBufferDiffHunk> {
15529        snapshot
15530            .buffer_snapshot
15531            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
15532            .find(|hunk| hunk.row_range.start.0 > position.row)
15533            .or_else(|| {
15534                snapshot
15535                    .buffer_snapshot
15536                    .diff_hunks_in_range(Point::zero()..position)
15537                    .find(|hunk| hunk.row_range.end.0 < position.row)
15538            })
15539    }
15540
15541    fn go_to_prev_hunk(
15542        &mut self,
15543        _: &GoToPreviousHunk,
15544        window: &mut Window,
15545        cx: &mut Context<Self>,
15546    ) {
15547        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15548        let snapshot = self.snapshot(window, cx);
15549        let selection = self.selections.newest::<Point>(cx);
15550        self.go_to_hunk_before_or_after_position(
15551            &snapshot,
15552            selection.head(),
15553            Direction::Prev,
15554            window,
15555            cx,
15556        );
15557    }
15558
15559    fn hunk_before_position(
15560        &mut self,
15561        snapshot: &EditorSnapshot,
15562        position: Point,
15563    ) -> Option<MultiBufferRow> {
15564        snapshot
15565            .buffer_snapshot
15566            .diff_hunk_before(position)
15567            .or_else(|| snapshot.buffer_snapshot.diff_hunk_before(Point::MAX))
15568    }
15569
15570    fn go_to_next_change(
15571        &mut self,
15572        _: &GoToNextChange,
15573        window: &mut Window,
15574        cx: &mut Context<Self>,
15575    ) {
15576        if let Some(selections) = self
15577            .change_list
15578            .next_change(1, Direction::Next)
15579            .map(|s| s.to_vec())
15580        {
15581            self.change_selections(Default::default(), window, cx, |s| {
15582                let map = s.display_map();
15583                s.select_display_ranges(selections.iter().map(|a| {
15584                    let point = a.to_display_point(&map);
15585                    point..point
15586                }))
15587            })
15588        }
15589    }
15590
15591    fn go_to_previous_change(
15592        &mut self,
15593        _: &GoToPreviousChange,
15594        window: &mut Window,
15595        cx: &mut Context<Self>,
15596    ) {
15597        if let Some(selections) = self
15598            .change_list
15599            .next_change(1, Direction::Prev)
15600            .map(|s| s.to_vec())
15601        {
15602            self.change_selections(Default::default(), window, cx, |s| {
15603                let map = s.display_map();
15604                s.select_display_ranges(selections.iter().map(|a| {
15605                    let point = a.to_display_point(&map);
15606                    point..point
15607                }))
15608            })
15609        }
15610    }
15611
15612    fn go_to_line<T: 'static>(
15613        &mut self,
15614        position: Anchor,
15615        highlight_color: Option<Hsla>,
15616        window: &mut Window,
15617        cx: &mut Context<Self>,
15618    ) {
15619        let snapshot = self.snapshot(window, cx).display_snapshot;
15620        let position = position.to_point(&snapshot.buffer_snapshot);
15621        let start = snapshot
15622            .buffer_snapshot
15623            .clip_point(Point::new(position.row, 0), Bias::Left);
15624        let end = start + Point::new(1, 0);
15625        let start = snapshot.buffer_snapshot.anchor_before(start);
15626        let end = snapshot.buffer_snapshot.anchor_before(end);
15627
15628        self.highlight_rows::<T>(
15629            start..end,
15630            highlight_color
15631                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
15632            Default::default(),
15633            cx,
15634        );
15635
15636        if self.buffer.read(cx).is_singleton() {
15637            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
15638        }
15639    }
15640
15641    pub fn go_to_definition(
15642        &mut self,
15643        _: &GoToDefinition,
15644        window: &mut Window,
15645        cx: &mut Context<Self>,
15646    ) -> Task<Result<Navigated>> {
15647        let definition =
15648            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
15649        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
15650        cx.spawn_in(window, async move |editor, cx| {
15651            if definition.await? == Navigated::Yes {
15652                return Ok(Navigated::Yes);
15653            }
15654            match fallback_strategy {
15655                GoToDefinitionFallback::None => Ok(Navigated::No),
15656                GoToDefinitionFallback::FindAllReferences => {
15657                    match editor.update_in(cx, |editor, window, cx| {
15658                        editor.find_all_references(&FindAllReferences, window, cx)
15659                    })? {
15660                        Some(references) => references.await,
15661                        None => Ok(Navigated::No),
15662                    }
15663                }
15664            }
15665        })
15666    }
15667
15668    pub fn go_to_declaration(
15669        &mut self,
15670        _: &GoToDeclaration,
15671        window: &mut Window,
15672        cx: &mut Context<Self>,
15673    ) -> Task<Result<Navigated>> {
15674        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
15675    }
15676
15677    pub fn go_to_declaration_split(
15678        &mut self,
15679        _: &GoToDeclaration,
15680        window: &mut Window,
15681        cx: &mut Context<Self>,
15682    ) -> Task<Result<Navigated>> {
15683        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
15684    }
15685
15686    pub fn go_to_implementation(
15687        &mut self,
15688        _: &GoToImplementation,
15689        window: &mut Window,
15690        cx: &mut Context<Self>,
15691    ) -> Task<Result<Navigated>> {
15692        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
15693    }
15694
15695    pub fn go_to_implementation_split(
15696        &mut self,
15697        _: &GoToImplementationSplit,
15698        window: &mut Window,
15699        cx: &mut Context<Self>,
15700    ) -> Task<Result<Navigated>> {
15701        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
15702    }
15703
15704    pub fn go_to_type_definition(
15705        &mut self,
15706        _: &GoToTypeDefinition,
15707        window: &mut Window,
15708        cx: &mut Context<Self>,
15709    ) -> Task<Result<Navigated>> {
15710        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
15711    }
15712
15713    pub fn go_to_definition_split(
15714        &mut self,
15715        _: &GoToDefinitionSplit,
15716        window: &mut Window,
15717        cx: &mut Context<Self>,
15718    ) -> Task<Result<Navigated>> {
15719        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
15720    }
15721
15722    pub fn go_to_type_definition_split(
15723        &mut self,
15724        _: &GoToTypeDefinitionSplit,
15725        window: &mut Window,
15726        cx: &mut Context<Self>,
15727    ) -> Task<Result<Navigated>> {
15728        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
15729    }
15730
15731    fn go_to_definition_of_kind(
15732        &mut self,
15733        kind: GotoDefinitionKind,
15734        split: bool,
15735        window: &mut Window,
15736        cx: &mut Context<Self>,
15737    ) -> Task<Result<Navigated>> {
15738        let Some(provider) = self.semantics_provider.clone() else {
15739            return Task::ready(Ok(Navigated::No));
15740        };
15741        let head = self.selections.newest::<usize>(cx).head();
15742        let buffer = self.buffer.read(cx);
15743        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
15744            return Task::ready(Ok(Navigated::No));
15745        };
15746        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
15747            return Task::ready(Ok(Navigated::No));
15748        };
15749
15750        cx.spawn_in(window, async move |editor, cx| {
15751            let definitions = definitions.await?;
15752            let navigated = editor
15753                .update_in(cx, |editor, window, cx| {
15754                    editor.navigate_to_hover_links(
15755                        Some(kind),
15756                        definitions
15757                            .into_iter()
15758                            .filter(|location| {
15759                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
15760                            })
15761                            .map(HoverLink::Text)
15762                            .collect::<Vec<_>>(),
15763                        split,
15764                        window,
15765                        cx,
15766                    )
15767                })?
15768                .await?;
15769            anyhow::Ok(navigated)
15770        })
15771    }
15772
15773    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
15774        let selection = self.selections.newest_anchor();
15775        let head = selection.head();
15776        let tail = selection.tail();
15777
15778        let Some((buffer, start_position)) =
15779            self.buffer.read(cx).text_anchor_for_position(head, cx)
15780        else {
15781            return;
15782        };
15783
15784        let end_position = if head != tail {
15785            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
15786                return;
15787            };
15788            Some(pos)
15789        } else {
15790            None
15791        };
15792
15793        let url_finder = cx.spawn_in(window, async move |editor, cx| {
15794            let url = if let Some(end_pos) = end_position {
15795                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
15796            } else {
15797                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
15798            };
15799
15800            if let Some(url) = url {
15801                editor.update(cx, |_, cx| {
15802                    cx.open_url(&url);
15803                })
15804            } else {
15805                Ok(())
15806            }
15807        });
15808
15809        url_finder.detach();
15810    }
15811
15812    pub fn open_selected_filename(
15813        &mut self,
15814        _: &OpenSelectedFilename,
15815        window: &mut Window,
15816        cx: &mut Context<Self>,
15817    ) {
15818        let Some(workspace) = self.workspace() else {
15819            return;
15820        };
15821
15822        let position = self.selections.newest_anchor().head();
15823
15824        let Some((buffer, buffer_position)) =
15825            self.buffer.read(cx).text_anchor_for_position(position, cx)
15826        else {
15827            return;
15828        };
15829
15830        let project = self.project.clone();
15831
15832        cx.spawn_in(window, async move |_, cx| {
15833            let result = find_file(&buffer, project, buffer_position, cx).await;
15834
15835            if let Some((_, path)) = result {
15836                workspace
15837                    .update_in(cx, |workspace, window, cx| {
15838                        workspace.open_resolved_path(path, window, cx)
15839                    })?
15840                    .await?;
15841            }
15842            anyhow::Ok(())
15843        })
15844        .detach();
15845    }
15846
15847    pub(crate) fn navigate_to_hover_links(
15848        &mut self,
15849        kind: Option<GotoDefinitionKind>,
15850        definitions: Vec<HoverLink>,
15851        split: bool,
15852        window: &mut Window,
15853        cx: &mut Context<Editor>,
15854    ) -> Task<Result<Navigated>> {
15855        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
15856        let mut first_url_or_file = None;
15857        let definitions: Vec<_> = definitions
15858            .into_iter()
15859            .filter_map(|def| match def {
15860                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
15861                HoverLink::InlayHint(lsp_location, server_id) => {
15862                    let computation =
15863                        self.compute_target_location(lsp_location, server_id, window, cx);
15864                    Some(cx.background_spawn(computation))
15865                }
15866                HoverLink::Url(url) => {
15867                    first_url_or_file = Some(Either::Left(url));
15868                    None
15869                }
15870                HoverLink::File(path) => {
15871                    first_url_or_file = Some(Either::Right(path));
15872                    None
15873                }
15874            })
15875            .collect();
15876
15877        let workspace = self.workspace();
15878
15879        cx.spawn_in(window, async move |editor, acx| {
15880            let mut locations: Vec<Location> = future::join_all(definitions)
15881                .await
15882                .into_iter()
15883                .filter_map(|location| location.transpose())
15884                .collect::<Result<_>>()
15885                .context("location tasks")?;
15886
15887            if locations.len() > 1 {
15888                let Some(workspace) = workspace else {
15889                    return Ok(Navigated::No);
15890                };
15891
15892                let tab_kind = match kind {
15893                    Some(GotoDefinitionKind::Implementation) => "Implementations",
15894                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
15895                    Some(GotoDefinitionKind::Declaration) => "Declarations",
15896                    Some(GotoDefinitionKind::Type) => "Types",
15897                };
15898                let title = editor
15899                    .update_in(acx, |_, _, cx| {
15900                        let target = locations
15901                            .iter()
15902                            .map(|location| {
15903                                location
15904                                    .buffer
15905                                    .read(cx)
15906                                    .text_for_range(location.range.clone())
15907                                    .collect::<String>()
15908                            })
15909                            .filter(|text| !text.contains('\n'))
15910                            .unique()
15911                            .take(3)
15912                            .join(", ");
15913                        if target.is_empty() {
15914                            tab_kind.to_owned()
15915                        } else {
15916                            format!("{tab_kind} for {target}")
15917                        }
15918                    })
15919                    .context("buffer title")?;
15920
15921                let opened = workspace
15922                    .update_in(acx, |workspace, window, cx| {
15923                        Self::open_locations_in_multibuffer(
15924                            workspace,
15925                            locations,
15926                            title,
15927                            split,
15928                            MultibufferSelectionMode::First,
15929                            window,
15930                            cx,
15931                        )
15932                    })
15933                    .is_ok();
15934
15935                anyhow::Ok(Navigated::from_bool(opened))
15936            } else if locations.is_empty() {
15937                // If there is one definition, just open it directly
15938                match first_url_or_file {
15939                    Some(Either::Left(url)) => {
15940                        acx.update(|_, cx| cx.open_url(&url))?;
15941                        Ok(Navigated::Yes)
15942                    }
15943                    Some(Either::Right(path)) => {
15944                        let Some(workspace) = workspace else {
15945                            return Ok(Navigated::No);
15946                        };
15947
15948                        workspace
15949                            .update_in(acx, |workspace, window, cx| {
15950                                workspace.open_resolved_path(path, window, cx)
15951                            })?
15952                            .await?;
15953                        Ok(Navigated::Yes)
15954                    }
15955                    None => Ok(Navigated::No),
15956                }
15957            } else {
15958                let Some(workspace) = workspace else {
15959                    return Ok(Navigated::No);
15960                };
15961
15962                let target = locations.pop().unwrap();
15963                editor.update_in(acx, |editor, window, cx| {
15964                    let pane = workspace.read(cx).active_pane().clone();
15965
15966                    let range = target.range.to_point(target.buffer.read(cx));
15967                    let range = editor.range_for_match(&range);
15968                    let range = collapse_multiline_range(range);
15969
15970                    if !split
15971                        && Some(&target.buffer) == editor.buffer.read(cx).as_singleton().as_ref()
15972                    {
15973                        editor.go_to_singleton_buffer_range(range.clone(), window, cx);
15974                    } else {
15975                        window.defer(cx, move |window, cx| {
15976                            let target_editor: Entity<Self> =
15977                                workspace.update(cx, |workspace, cx| {
15978                                    let pane = if split {
15979                                        workspace.adjacent_pane(window, cx)
15980                                    } else {
15981                                        workspace.active_pane().clone()
15982                                    };
15983
15984                                    workspace.open_project_item(
15985                                        pane,
15986                                        target.buffer.clone(),
15987                                        true,
15988                                        true,
15989                                        window,
15990                                        cx,
15991                                    )
15992                                });
15993                            target_editor.update(cx, |target_editor, cx| {
15994                                // When selecting a definition in a different buffer, disable the nav history
15995                                // to avoid creating a history entry at the previous cursor location.
15996                                pane.update(cx, |pane, _| pane.disable_history());
15997                                target_editor.go_to_singleton_buffer_range(range, window, cx);
15998                                pane.update(cx, |pane, _| pane.enable_history());
15999                            });
16000                        });
16001                    }
16002                    Navigated::Yes
16003                })
16004            }
16005        })
16006    }
16007
16008    fn compute_target_location(
16009        &self,
16010        lsp_location: lsp::Location,
16011        server_id: LanguageServerId,
16012        window: &mut Window,
16013        cx: &mut Context<Self>,
16014    ) -> Task<anyhow::Result<Option<Location>>> {
16015        let Some(project) = self.project.clone() else {
16016            return Task::ready(Ok(None));
16017        };
16018
16019        cx.spawn_in(window, async move |editor, cx| {
16020            let location_task = editor.update(cx, |_, cx| {
16021                project.update(cx, |project, cx| {
16022                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16023                })
16024            })?;
16025            let location = Some({
16026                let target_buffer_handle = location_task.await.context("open local buffer")?;
16027                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16028                    let target_start = target_buffer
16029                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16030                    let target_end = target_buffer
16031                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16032                    target_buffer.anchor_after(target_start)
16033                        ..target_buffer.anchor_before(target_end)
16034                })?;
16035                Location {
16036                    buffer: target_buffer_handle,
16037                    range,
16038                }
16039            });
16040            Ok(location)
16041        })
16042    }
16043
16044    pub fn find_all_references(
16045        &mut self,
16046        _: &FindAllReferences,
16047        window: &mut Window,
16048        cx: &mut Context<Self>,
16049    ) -> Option<Task<Result<Navigated>>> {
16050        let selection = self.selections.newest::<usize>(cx);
16051        let multi_buffer = self.buffer.read(cx);
16052        let head = selection.head();
16053
16054        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16055        let head_anchor = multi_buffer_snapshot.anchor_at(
16056            head,
16057            if head < selection.tail() {
16058                Bias::Right
16059            } else {
16060                Bias::Left
16061            },
16062        );
16063
16064        match self
16065            .find_all_references_task_sources
16066            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16067        {
16068            Ok(_) => {
16069                log::info!(
16070                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16071                );
16072                return None;
16073            }
16074            Err(i) => {
16075                self.find_all_references_task_sources.insert(i, head_anchor);
16076            }
16077        }
16078
16079        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16080        let workspace = self.workspace()?;
16081        let project = workspace.read(cx).project().clone();
16082        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16083        Some(cx.spawn_in(window, async move |editor, cx| {
16084            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16085                if let Ok(i) = editor
16086                    .find_all_references_task_sources
16087                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16088                {
16089                    editor.find_all_references_task_sources.remove(i);
16090                }
16091            });
16092
16093            let locations = references.await?;
16094            if locations.is_empty() {
16095                return anyhow::Ok(Navigated::No);
16096            }
16097
16098            workspace.update_in(cx, |workspace, window, cx| {
16099                let target = locations
16100                    .iter()
16101                    .map(|location| {
16102                        location
16103                            .buffer
16104                            .read(cx)
16105                            .text_for_range(location.range.clone())
16106                            .collect::<String>()
16107                    })
16108                    .filter(|text| !text.contains('\n'))
16109                    .unique()
16110                    .take(3)
16111                    .join(", ");
16112                let title = if target.is_empty() {
16113                    "References".to_owned()
16114                } else {
16115                    format!("References to {target}")
16116                };
16117                Self::open_locations_in_multibuffer(
16118                    workspace,
16119                    locations,
16120                    title,
16121                    false,
16122                    MultibufferSelectionMode::First,
16123                    window,
16124                    cx,
16125                );
16126                Navigated::Yes
16127            })
16128        }))
16129    }
16130
16131    /// Opens a multibuffer with the given project locations in it
16132    pub fn open_locations_in_multibuffer(
16133        workspace: &mut Workspace,
16134        mut locations: Vec<Location>,
16135        title: String,
16136        split: bool,
16137        multibuffer_selection_mode: MultibufferSelectionMode,
16138        window: &mut Window,
16139        cx: &mut Context<Workspace>,
16140    ) {
16141        if locations.is_empty() {
16142            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16143            return;
16144        }
16145
16146        // If there are multiple definitions, open them in a multibuffer
16147        locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
16148        let mut locations = locations.into_iter().peekable();
16149        let mut ranges: Vec<Range<Anchor>> = Vec::new();
16150        let capability = workspace.project().read(cx).capability();
16151
16152        let excerpt_buffer = cx.new(|cx| {
16153            let mut multibuffer = MultiBuffer::new(capability);
16154            while let Some(location) = locations.next() {
16155                let buffer = location.buffer.read(cx);
16156                let mut ranges_for_buffer = Vec::new();
16157                let range = location.range.to_point(buffer);
16158                ranges_for_buffer.push(range.clone());
16159
16160                while let Some(next_location) = locations.peek() {
16161                    if next_location.buffer == location.buffer {
16162                        ranges_for_buffer.push(next_location.range.to_point(buffer));
16163                        locations.next();
16164                    } else {
16165                        break;
16166                    }
16167                }
16168
16169                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
16170                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
16171                    PathKey::for_buffer(&location.buffer, cx),
16172                    location.buffer.clone(),
16173                    ranges_for_buffer,
16174                    DEFAULT_MULTIBUFFER_CONTEXT,
16175                    cx,
16176                );
16177                ranges.extend(new_ranges)
16178            }
16179
16180            multibuffer.with_title(title)
16181        });
16182
16183        let editor = cx.new(|cx| {
16184            Editor::for_multibuffer(
16185                excerpt_buffer,
16186                Some(workspace.project().clone()),
16187                window,
16188                cx,
16189            )
16190        });
16191        editor.update(cx, |editor, cx| {
16192            match multibuffer_selection_mode {
16193                MultibufferSelectionMode::First => {
16194                    if let Some(first_range) = ranges.first() {
16195                        editor.change_selections(
16196                            SelectionEffects::no_scroll(),
16197                            window,
16198                            cx,
16199                            |selections| {
16200                                selections.clear_disjoint();
16201                                selections
16202                                    .select_anchor_ranges(std::iter::once(first_range.clone()));
16203                            },
16204                        );
16205                    }
16206                    editor.highlight_background::<Self>(
16207                        &ranges,
16208                        |theme| theme.colors().editor_highlighted_line_background,
16209                        cx,
16210                    );
16211                }
16212                MultibufferSelectionMode::All => {
16213                    editor.change_selections(
16214                        SelectionEffects::no_scroll(),
16215                        window,
16216                        cx,
16217                        |selections| {
16218                            selections.clear_disjoint();
16219                            selections.select_anchor_ranges(ranges);
16220                        },
16221                    );
16222                }
16223            }
16224            editor.register_buffers_with_language_servers(cx);
16225        });
16226
16227        let item = Box::new(editor);
16228        let item_id = item.item_id();
16229
16230        if split {
16231            workspace.split_item(SplitDirection::Right, item.clone(), window, cx);
16232        } else {
16233            if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
16234                let (preview_item_id, preview_item_idx) =
16235                    workspace.active_pane().read_with(cx, |pane, _| {
16236                        (pane.preview_item_id(), pane.preview_item_idx())
16237                    });
16238
16239                workspace.add_item_to_active_pane(item.clone(), preview_item_idx, true, window, cx);
16240
16241                if let Some(preview_item_id) = preview_item_id {
16242                    workspace.active_pane().update(cx, |pane, cx| {
16243                        pane.remove_item(preview_item_id, false, false, window, cx);
16244                    });
16245                }
16246            } else {
16247                workspace.add_item_to_active_pane(item.clone(), None, true, window, cx);
16248            }
16249        }
16250        workspace.active_pane().update(cx, |pane, cx| {
16251            pane.set_preview_item_id(Some(item_id), cx);
16252        });
16253    }
16254
16255    pub fn rename(
16256        &mut self,
16257        _: &Rename,
16258        window: &mut Window,
16259        cx: &mut Context<Self>,
16260    ) -> Option<Task<Result<()>>> {
16261        use language::ToOffset as _;
16262
16263        let provider = self.semantics_provider.clone()?;
16264        let selection = self.selections.newest_anchor().clone();
16265        let (cursor_buffer, cursor_buffer_position) = self
16266            .buffer
16267            .read(cx)
16268            .text_anchor_for_position(selection.head(), cx)?;
16269        let (tail_buffer, cursor_buffer_position_end) = self
16270            .buffer
16271            .read(cx)
16272            .text_anchor_for_position(selection.tail(), cx)?;
16273        if tail_buffer != cursor_buffer {
16274            return None;
16275        }
16276
16277        let snapshot = cursor_buffer.read(cx).snapshot();
16278        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
16279        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
16280        let prepare_rename = provider
16281            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
16282            .unwrap_or_else(|| Task::ready(Ok(None)));
16283        drop(snapshot);
16284
16285        Some(cx.spawn_in(window, async move |this, cx| {
16286            let rename_range = if let Some(range) = prepare_rename.await? {
16287                Some(range)
16288            } else {
16289                this.update(cx, |this, cx| {
16290                    let buffer = this.buffer.read(cx).snapshot(cx);
16291                    let mut buffer_highlights = this
16292                        .document_highlights_for_position(selection.head(), &buffer)
16293                        .filter(|highlight| {
16294                            highlight.start.excerpt_id == selection.head().excerpt_id
16295                                && highlight.end.excerpt_id == selection.head().excerpt_id
16296                        });
16297                    buffer_highlights
16298                        .next()
16299                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
16300                })?
16301            };
16302            if let Some(rename_range) = rename_range {
16303                this.update_in(cx, |this, window, cx| {
16304                    let snapshot = cursor_buffer.read(cx).snapshot();
16305                    let rename_buffer_range = rename_range.to_offset(&snapshot);
16306                    let cursor_offset_in_rename_range =
16307                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
16308                    let cursor_offset_in_rename_range_end =
16309                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
16310
16311                    this.take_rename(false, window, cx);
16312                    let buffer = this.buffer.read(cx).read(cx);
16313                    let cursor_offset = selection.head().to_offset(&buffer);
16314                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
16315                    let rename_end = rename_start + rename_buffer_range.len();
16316                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
16317                    let mut old_highlight_id = None;
16318                    let old_name: Arc<str> = buffer
16319                        .chunks(rename_start..rename_end, true)
16320                        .map(|chunk| {
16321                            if old_highlight_id.is_none() {
16322                                old_highlight_id = chunk.syntax_highlight_id;
16323                            }
16324                            chunk.text
16325                        })
16326                        .collect::<String>()
16327                        .into();
16328
16329                    drop(buffer);
16330
16331                    // Position the selection in the rename editor so that it matches the current selection.
16332                    this.show_local_selections = false;
16333                    let rename_editor = cx.new(|cx| {
16334                        let mut editor = Editor::single_line(window, cx);
16335                        editor.buffer.update(cx, |buffer, cx| {
16336                            buffer.edit([(0..0, old_name.clone())], None, cx)
16337                        });
16338                        let rename_selection_range = match cursor_offset_in_rename_range
16339                            .cmp(&cursor_offset_in_rename_range_end)
16340                        {
16341                            Ordering::Equal => {
16342                                editor.select_all(&SelectAll, window, cx);
16343                                return editor;
16344                            }
16345                            Ordering::Less => {
16346                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
16347                            }
16348                            Ordering::Greater => {
16349                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
16350                            }
16351                        };
16352                        if rename_selection_range.end > old_name.len() {
16353                            editor.select_all(&SelectAll, window, cx);
16354                        } else {
16355                            editor.change_selections(Default::default(), window, cx, |s| {
16356                                s.select_ranges([rename_selection_range]);
16357                            });
16358                        }
16359                        editor
16360                    });
16361                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
16362                        if e == &EditorEvent::Focused {
16363                            cx.emit(EditorEvent::FocusedIn)
16364                        }
16365                    })
16366                    .detach();
16367
16368                    let write_highlights =
16369                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
16370                    let read_highlights =
16371                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
16372                    let ranges = write_highlights
16373                        .iter()
16374                        .flat_map(|(_, ranges)| ranges.iter())
16375                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
16376                        .cloned()
16377                        .collect();
16378
16379                    this.highlight_text::<Rename>(
16380                        ranges,
16381                        HighlightStyle {
16382                            fade_out: Some(0.6),
16383                            ..Default::default()
16384                        },
16385                        cx,
16386                    );
16387                    let rename_focus_handle = rename_editor.focus_handle(cx);
16388                    window.focus(&rename_focus_handle);
16389                    let block_id = this.insert_blocks(
16390                        [BlockProperties {
16391                            style: BlockStyle::Flex,
16392                            placement: BlockPlacement::Below(range.start),
16393                            height: Some(1),
16394                            render: Arc::new({
16395                                let rename_editor = rename_editor.clone();
16396                                move |cx: &mut BlockContext| {
16397                                    let mut text_style = cx.editor_style.text.clone();
16398                                    if let Some(highlight_style) = old_highlight_id
16399                                        .and_then(|h| h.style(&cx.editor_style.syntax))
16400                                    {
16401                                        text_style = text_style.highlight(highlight_style);
16402                                    }
16403                                    div()
16404                                        .block_mouse_except_scroll()
16405                                        .pl(cx.anchor_x)
16406                                        .child(EditorElement::new(
16407                                            &rename_editor,
16408                                            EditorStyle {
16409                                                background: cx.theme().system().transparent,
16410                                                local_player: cx.editor_style.local_player,
16411                                                text: text_style,
16412                                                scrollbar_width: cx.editor_style.scrollbar_width,
16413                                                syntax: cx.editor_style.syntax.clone(),
16414                                                status: cx.editor_style.status.clone(),
16415                                                inlay_hints_style: HighlightStyle {
16416                                                    font_weight: Some(FontWeight::BOLD),
16417                                                    ..make_inlay_hints_style(cx.app)
16418                                                },
16419                                                edit_prediction_styles: make_suggestion_styles(
16420                                                    cx.app,
16421                                                ),
16422                                                ..EditorStyle::default()
16423                                            },
16424                                        ))
16425                                        .into_any_element()
16426                                }
16427                            }),
16428                            priority: 0,
16429                        }],
16430                        Some(Autoscroll::fit()),
16431                        cx,
16432                    )[0];
16433                    this.pending_rename = Some(RenameState {
16434                        range,
16435                        old_name,
16436                        editor: rename_editor,
16437                        block_id,
16438                    });
16439                })?;
16440            }
16441
16442            Ok(())
16443        }))
16444    }
16445
16446    pub fn confirm_rename(
16447        &mut self,
16448        _: &ConfirmRename,
16449        window: &mut Window,
16450        cx: &mut Context<Self>,
16451    ) -> Option<Task<Result<()>>> {
16452        let rename = self.take_rename(false, window, cx)?;
16453        let workspace = self.workspace()?.downgrade();
16454        let (buffer, start) = self
16455            .buffer
16456            .read(cx)
16457            .text_anchor_for_position(rename.range.start, cx)?;
16458        let (end_buffer, _) = self
16459            .buffer
16460            .read(cx)
16461            .text_anchor_for_position(rename.range.end, cx)?;
16462        if buffer != end_buffer {
16463            return None;
16464        }
16465
16466        let old_name = rename.old_name;
16467        let new_name = rename.editor.read(cx).text(cx);
16468
16469        let rename = self.semantics_provider.as_ref()?.perform_rename(
16470            &buffer,
16471            start,
16472            new_name.clone(),
16473            cx,
16474        )?;
16475
16476        Some(cx.spawn_in(window, async move |editor, cx| {
16477            let project_transaction = rename.await?;
16478            Self::open_project_transaction(
16479                &editor,
16480                workspace,
16481                project_transaction,
16482                format!("Rename: {}{}", old_name, new_name),
16483                cx,
16484            )
16485            .await?;
16486
16487            editor.update(cx, |editor, cx| {
16488                editor.refresh_document_highlights(cx);
16489            })?;
16490            Ok(())
16491        }))
16492    }
16493
16494    fn take_rename(
16495        &mut self,
16496        moving_cursor: bool,
16497        window: &mut Window,
16498        cx: &mut Context<Self>,
16499    ) -> Option<RenameState> {
16500        let rename = self.pending_rename.take()?;
16501        if rename.editor.focus_handle(cx).is_focused(window) {
16502            window.focus(&self.focus_handle);
16503        }
16504
16505        self.remove_blocks(
16506            [rename.block_id].into_iter().collect(),
16507            Some(Autoscroll::fit()),
16508            cx,
16509        );
16510        self.clear_highlights::<Rename>(cx);
16511        self.show_local_selections = true;
16512
16513        if moving_cursor {
16514            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
16515                editor.selections.newest::<usize>(cx).head()
16516            });
16517
16518            // Update the selection to match the position of the selection inside
16519            // the rename editor.
16520            let snapshot = self.buffer.read(cx).read(cx);
16521            let rename_range = rename.range.to_offset(&snapshot);
16522            let cursor_in_editor = snapshot
16523                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
16524                .min(rename_range.end);
16525            drop(snapshot);
16526
16527            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16528                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
16529            });
16530        } else {
16531            self.refresh_document_highlights(cx);
16532        }
16533
16534        Some(rename)
16535    }
16536
16537    pub fn pending_rename(&self) -> Option<&RenameState> {
16538        self.pending_rename.as_ref()
16539    }
16540
16541    fn format(
16542        &mut self,
16543        _: &Format,
16544        window: &mut Window,
16545        cx: &mut Context<Self>,
16546    ) -> Option<Task<Result<()>>> {
16547        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16548
16549        let project = match &self.project {
16550            Some(project) => project.clone(),
16551            None => return None,
16552        };
16553
16554        Some(self.perform_format(
16555            project,
16556            FormatTrigger::Manual,
16557            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
16558            window,
16559            cx,
16560        ))
16561    }
16562
16563    fn format_selections(
16564        &mut self,
16565        _: &FormatSelections,
16566        window: &mut Window,
16567        cx: &mut Context<Self>,
16568    ) -> Option<Task<Result<()>>> {
16569        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16570
16571        let project = match &self.project {
16572            Some(project) => project.clone(),
16573            None => return None,
16574        };
16575
16576        let ranges = self
16577            .selections
16578            .all_adjusted(cx)
16579            .into_iter()
16580            .map(|selection| selection.range())
16581            .collect_vec();
16582
16583        Some(self.perform_format(
16584            project,
16585            FormatTrigger::Manual,
16586            FormatTarget::Ranges(ranges),
16587            window,
16588            cx,
16589        ))
16590    }
16591
16592    fn perform_format(
16593        &mut self,
16594        project: Entity<Project>,
16595        trigger: FormatTrigger,
16596        target: FormatTarget,
16597        window: &mut Window,
16598        cx: &mut Context<Self>,
16599    ) -> Task<Result<()>> {
16600        let buffer = self.buffer.clone();
16601        let (buffers, target) = match target {
16602            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
16603            FormatTarget::Ranges(selection_ranges) => {
16604                let multi_buffer = buffer.read(cx);
16605                let snapshot = multi_buffer.read(cx);
16606                let mut buffers = HashSet::default();
16607                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
16608                    BTreeMap::new();
16609                for selection_range in selection_ranges {
16610                    for (buffer, buffer_range, _) in
16611                        snapshot.range_to_buffer_ranges(selection_range)
16612                    {
16613                        let buffer_id = buffer.remote_id();
16614                        let start = buffer.anchor_before(buffer_range.start);
16615                        let end = buffer.anchor_after(buffer_range.end);
16616                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
16617                        buffer_id_to_ranges
16618                            .entry(buffer_id)
16619                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
16620                            .or_insert_with(|| vec![start..end]);
16621                    }
16622                }
16623                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
16624            }
16625        };
16626
16627        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
16628        let selections_prev = transaction_id_prev
16629            .and_then(|transaction_id_prev| {
16630                // default to selections as they were after the last edit, if we have them,
16631                // instead of how they are now.
16632                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
16633                // will take you back to where you made the last edit, instead of staying where you scrolled
16634                self.selection_history
16635                    .transaction(transaction_id_prev)
16636                    .map(|t| t.0.clone())
16637            })
16638            .unwrap_or_else(|| {
16639                log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
16640                self.selections.disjoint_anchors()
16641            });
16642
16643        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
16644        let format = project.update(cx, |project, cx| {
16645            project.format(buffers, target, true, trigger, cx)
16646        });
16647
16648        cx.spawn_in(window, async move |editor, cx| {
16649            let transaction = futures::select_biased! {
16650                transaction = format.log_err().fuse() => transaction,
16651                () = timeout => {
16652                    log::warn!("timed out waiting for formatting");
16653                    None
16654                }
16655            };
16656
16657            buffer
16658                .update(cx, |buffer, cx| {
16659                    if let Some(transaction) = transaction
16660                        && !buffer.is_singleton()
16661                    {
16662                        buffer.push_transaction(&transaction.0, cx);
16663                    }
16664                    cx.notify();
16665                })
16666                .ok();
16667
16668            if let Some(transaction_id_now) =
16669                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
16670            {
16671                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
16672                if has_new_transaction {
16673                    _ = editor.update(cx, |editor, _| {
16674                        editor
16675                            .selection_history
16676                            .insert_transaction(transaction_id_now, selections_prev);
16677                    });
16678                }
16679            }
16680
16681            Ok(())
16682        })
16683    }
16684
16685    fn organize_imports(
16686        &mut self,
16687        _: &OrganizeImports,
16688        window: &mut Window,
16689        cx: &mut Context<Self>,
16690    ) -> Option<Task<Result<()>>> {
16691        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16692        let project = match &self.project {
16693            Some(project) => project.clone(),
16694            None => return None,
16695        };
16696        Some(self.perform_code_action_kind(
16697            project,
16698            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
16699            window,
16700            cx,
16701        ))
16702    }
16703
16704    fn perform_code_action_kind(
16705        &mut self,
16706        project: Entity<Project>,
16707        kind: CodeActionKind,
16708        window: &mut Window,
16709        cx: &mut Context<Self>,
16710    ) -> Task<Result<()>> {
16711        let buffer = self.buffer.clone();
16712        let buffers = buffer.read(cx).all_buffers();
16713        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
16714        let apply_action = project.update(cx, |project, cx| {
16715            project.apply_code_action_kind(buffers, kind, true, cx)
16716        });
16717        cx.spawn_in(window, async move |_, cx| {
16718            let transaction = futures::select_biased! {
16719                () = timeout => {
16720                    log::warn!("timed out waiting for executing code action");
16721                    None
16722                }
16723                transaction = apply_action.log_err().fuse() => transaction,
16724            };
16725            buffer
16726                .update(cx, |buffer, cx| {
16727                    // check if we need this
16728                    if let Some(transaction) = transaction
16729                        && !buffer.is_singleton()
16730                    {
16731                        buffer.push_transaction(&transaction.0, cx);
16732                    }
16733                    cx.notify();
16734                })
16735                .ok();
16736            Ok(())
16737        })
16738    }
16739
16740    pub fn restart_language_server(
16741        &mut self,
16742        _: &RestartLanguageServer,
16743        _: &mut Window,
16744        cx: &mut Context<Self>,
16745    ) {
16746        if let Some(project) = self.project.clone() {
16747            self.buffer.update(cx, |multi_buffer, cx| {
16748                project.update(cx, |project, cx| {
16749                    project.restart_language_servers_for_buffers(
16750                        multi_buffer.all_buffers().into_iter().collect(),
16751                        HashSet::default(),
16752                        cx,
16753                    );
16754                });
16755            })
16756        }
16757    }
16758
16759    pub fn stop_language_server(
16760        &mut self,
16761        _: &StopLanguageServer,
16762        _: &mut Window,
16763        cx: &mut Context<Self>,
16764    ) {
16765        if let Some(project) = self.project.clone() {
16766            self.buffer.update(cx, |multi_buffer, cx| {
16767                project.update(cx, |project, cx| {
16768                    project.stop_language_servers_for_buffers(
16769                        multi_buffer.all_buffers().into_iter().collect(),
16770                        HashSet::default(),
16771                        cx,
16772                    );
16773                    cx.emit(project::Event::RefreshInlayHints);
16774                });
16775            });
16776        }
16777    }
16778
16779    fn cancel_language_server_work(
16780        workspace: &mut Workspace,
16781        _: &actions::CancelLanguageServerWork,
16782        _: &mut Window,
16783        cx: &mut Context<Workspace>,
16784    ) {
16785        let project = workspace.project();
16786        let buffers = workspace
16787            .active_item(cx)
16788            .and_then(|item| item.act_as::<Editor>(cx))
16789            .map_or(HashSet::default(), |editor| {
16790                editor.read(cx).buffer.read(cx).all_buffers()
16791            });
16792        project.update(cx, |project, cx| {
16793            project.cancel_language_server_work_for_buffers(buffers, cx);
16794        });
16795    }
16796
16797    fn show_character_palette(
16798        &mut self,
16799        _: &ShowCharacterPalette,
16800        window: &mut Window,
16801        _: &mut Context<Self>,
16802    ) {
16803        window.show_character_palette();
16804    }
16805
16806    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
16807        if !self.diagnostics_enabled() {
16808            return;
16809        }
16810
16811        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
16812            let buffer = self.buffer.read(cx).snapshot(cx);
16813            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
16814            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
16815            let is_valid = buffer
16816                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
16817                .any(|entry| {
16818                    entry.diagnostic.is_primary
16819                        && !entry.range.is_empty()
16820                        && entry.range.start == primary_range_start
16821                        && entry.diagnostic.message == active_diagnostics.active_message
16822                });
16823
16824            if !is_valid {
16825                self.dismiss_diagnostics(cx);
16826            }
16827        }
16828    }
16829
16830    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
16831        match &self.active_diagnostics {
16832            ActiveDiagnostic::Group(group) => Some(group),
16833            _ => None,
16834        }
16835    }
16836
16837    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
16838        if !self.diagnostics_enabled() {
16839            return;
16840        }
16841        self.dismiss_diagnostics(cx);
16842        self.active_diagnostics = ActiveDiagnostic::All;
16843    }
16844
16845    fn activate_diagnostics(
16846        &mut self,
16847        buffer_id: BufferId,
16848        diagnostic: DiagnosticEntry<usize>,
16849        window: &mut Window,
16850        cx: &mut Context<Self>,
16851    ) {
16852        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16853            return;
16854        }
16855        self.dismiss_diagnostics(cx);
16856        let snapshot = self.snapshot(window, cx);
16857        let buffer = self.buffer.read(cx).snapshot(cx);
16858        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
16859            return;
16860        };
16861
16862        let diagnostic_group = buffer
16863            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
16864            .collect::<Vec<_>>();
16865
16866        let blocks =
16867            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
16868
16869        let blocks = self.display_map.update(cx, |display_map, cx| {
16870            display_map.insert_blocks(blocks, cx).into_iter().collect()
16871        });
16872        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
16873            active_range: buffer.anchor_before(diagnostic.range.start)
16874                ..buffer.anchor_after(diagnostic.range.end),
16875            active_message: diagnostic.diagnostic.message.clone(),
16876            group_id: diagnostic.diagnostic.group_id,
16877            blocks,
16878        });
16879        cx.notify();
16880    }
16881
16882    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
16883        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
16884            return;
16885        };
16886
16887        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
16888        if let ActiveDiagnostic::Group(group) = prev {
16889            self.display_map.update(cx, |display_map, cx| {
16890                display_map.remove_blocks(group.blocks, cx);
16891            });
16892            cx.notify();
16893        }
16894    }
16895
16896    /// Disable inline diagnostics rendering for this editor.
16897    pub fn disable_inline_diagnostics(&mut self) {
16898        self.inline_diagnostics_enabled = false;
16899        self.inline_diagnostics_update = Task::ready(());
16900        self.inline_diagnostics.clear();
16901    }
16902
16903    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
16904        self.diagnostics_enabled = false;
16905        self.dismiss_diagnostics(cx);
16906        self.inline_diagnostics_update = Task::ready(());
16907        self.inline_diagnostics.clear();
16908    }
16909
16910    pub fn diagnostics_enabled(&self) -> bool {
16911        self.diagnostics_enabled && self.mode.is_full()
16912    }
16913
16914    pub fn inline_diagnostics_enabled(&self) -> bool {
16915        self.inline_diagnostics_enabled && self.diagnostics_enabled()
16916    }
16917
16918    pub fn show_inline_diagnostics(&self) -> bool {
16919        self.show_inline_diagnostics
16920    }
16921
16922    pub fn toggle_inline_diagnostics(
16923        &mut self,
16924        _: &ToggleInlineDiagnostics,
16925        window: &mut Window,
16926        cx: &mut Context<Editor>,
16927    ) {
16928        self.show_inline_diagnostics = !self.show_inline_diagnostics;
16929        self.refresh_inline_diagnostics(false, window, cx);
16930    }
16931
16932    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
16933        self.diagnostics_max_severity = severity;
16934        self.display_map.update(cx, |display_map, _| {
16935            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
16936        });
16937    }
16938
16939    pub fn toggle_diagnostics(
16940        &mut self,
16941        _: &ToggleDiagnostics,
16942        window: &mut Window,
16943        cx: &mut Context<Editor>,
16944    ) {
16945        if !self.diagnostics_enabled() {
16946            return;
16947        }
16948
16949        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16950            EditorSettings::get_global(cx)
16951                .diagnostics_max_severity
16952                .filter(|severity| severity != &DiagnosticSeverity::Off)
16953                .unwrap_or(DiagnosticSeverity::Hint)
16954        } else {
16955            DiagnosticSeverity::Off
16956        };
16957        self.set_max_diagnostics_severity(new_severity, cx);
16958        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
16959            self.active_diagnostics = ActiveDiagnostic::None;
16960            self.inline_diagnostics_update = Task::ready(());
16961            self.inline_diagnostics.clear();
16962        } else {
16963            self.refresh_inline_diagnostics(false, window, cx);
16964        }
16965
16966        cx.notify();
16967    }
16968
16969    pub fn toggle_minimap(
16970        &mut self,
16971        _: &ToggleMinimap,
16972        window: &mut Window,
16973        cx: &mut Context<Editor>,
16974    ) {
16975        if self.supports_minimap(cx) {
16976            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
16977        }
16978    }
16979
16980    fn refresh_inline_diagnostics(
16981        &mut self,
16982        debounce: bool,
16983        window: &mut Window,
16984        cx: &mut Context<Self>,
16985    ) {
16986        let max_severity = ProjectSettings::get_global(cx)
16987            .diagnostics
16988            .inline
16989            .max_severity
16990            .unwrap_or(self.diagnostics_max_severity);
16991
16992        if !self.inline_diagnostics_enabled()
16993            || !self.show_inline_diagnostics
16994            || max_severity == DiagnosticSeverity::Off
16995        {
16996            self.inline_diagnostics_update = Task::ready(());
16997            self.inline_diagnostics.clear();
16998            return;
16999        }
17000
17001        let debounce_ms = ProjectSettings::get_global(cx)
17002            .diagnostics
17003            .inline
17004            .update_debounce_ms;
17005        let debounce = if debounce && debounce_ms > 0 {
17006            Some(Duration::from_millis(debounce_ms))
17007        } else {
17008            None
17009        };
17010        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17011            if let Some(debounce) = debounce {
17012                cx.background_executor().timer(debounce).await;
17013            }
17014            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17015                editor
17016                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17017                    .ok()
17018            }) else {
17019                return;
17020            };
17021
17022            let new_inline_diagnostics = cx
17023                .background_spawn(async move {
17024                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17025                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17026                        let message = diagnostic_entry
17027                            .diagnostic
17028                            .message
17029                            .split_once('\n')
17030                            .map(|(line, _)| line)
17031                            .map(SharedString::new)
17032                            .unwrap_or_else(|| {
17033                                SharedString::from(diagnostic_entry.diagnostic.message)
17034                            });
17035                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17036                        let (Ok(i) | Err(i)) = inline_diagnostics
17037                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17038                        inline_diagnostics.insert(
17039                            i,
17040                            (
17041                                start_anchor,
17042                                InlineDiagnostic {
17043                                    message,
17044                                    group_id: diagnostic_entry.diagnostic.group_id,
17045                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17046                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17047                                    severity: diagnostic_entry.diagnostic.severity,
17048                                },
17049                            ),
17050                        );
17051                    }
17052                    inline_diagnostics
17053                })
17054                .await;
17055
17056            editor
17057                .update(cx, |editor, cx| {
17058                    editor.inline_diagnostics = new_inline_diagnostics;
17059                    cx.notify();
17060                })
17061                .ok();
17062        });
17063    }
17064
17065    fn pull_diagnostics(
17066        &mut self,
17067        buffer_id: Option<BufferId>,
17068        window: &Window,
17069        cx: &mut Context<Self>,
17070    ) -> Option<()> {
17071        if !self.mode().is_full() {
17072            return None;
17073        }
17074        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17075            .diagnostics
17076            .lsp_pull_diagnostics;
17077        if !pull_diagnostics_settings.enabled {
17078            return None;
17079        }
17080        let project = self.project()?.downgrade();
17081        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17082        let mut buffers = self.buffer.read(cx).all_buffers();
17083        if let Some(buffer_id) = buffer_id {
17084            buffers.retain(|buffer| buffer.read(cx).remote_id() == buffer_id);
17085        }
17086
17087        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17088            cx.background_executor().timer(debounce).await;
17089
17090            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17091                buffers
17092                    .into_iter()
17093                    .filter_map(|buffer| {
17094                        project
17095                            .update(cx, |project, cx| {
17096                                project.lsp_store().update(cx, |lsp_store, cx| {
17097                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17098                                })
17099                            })
17100                            .ok()
17101                    })
17102                    .collect::<FuturesUnordered<_>>()
17103            }) else {
17104                return;
17105            };
17106
17107            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17108                match pull_task {
17109                    Ok(()) => {
17110                        if editor
17111                            .update_in(cx, |editor, window, cx| {
17112                                editor.update_diagnostics_state(window, cx);
17113                            })
17114                            .is_err()
17115                        {
17116                            return;
17117                        }
17118                    }
17119                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17120                }
17121            }
17122        });
17123
17124        Some(())
17125    }
17126
17127    pub fn set_selections_from_remote(
17128        &mut self,
17129        selections: Vec<Selection<Anchor>>,
17130        pending_selection: Option<Selection<Anchor>>,
17131        window: &mut Window,
17132        cx: &mut Context<Self>,
17133    ) {
17134        let old_cursor_position = self.selections.newest_anchor().head();
17135        self.selections.change_with(cx, |s| {
17136            s.select_anchors(selections);
17137            if let Some(pending_selection) = pending_selection {
17138                s.set_pending(pending_selection, SelectMode::Character);
17139            } else {
17140                s.clear_pending();
17141            }
17142        });
17143        self.selections_did_change(
17144            false,
17145            &old_cursor_position,
17146            SelectionEffects::default(),
17147            window,
17148            cx,
17149        );
17150    }
17151
17152    pub fn transact(
17153        &mut self,
17154        window: &mut Window,
17155        cx: &mut Context<Self>,
17156        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
17157    ) -> Option<TransactionId> {
17158        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17159            this.start_transaction_at(Instant::now(), window, cx);
17160            update(this, window, cx);
17161            this.end_transaction_at(Instant::now(), cx)
17162        })
17163    }
17164
17165    pub fn start_transaction_at(
17166        &mut self,
17167        now: Instant,
17168        window: &mut Window,
17169        cx: &mut Context<Self>,
17170    ) -> Option<TransactionId> {
17171        self.end_selection(window, cx);
17172        if let Some(tx_id) = self
17173            .buffer
17174            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
17175        {
17176            self.selection_history
17177                .insert_transaction(tx_id, self.selections.disjoint_anchors());
17178            cx.emit(EditorEvent::TransactionBegun {
17179                transaction_id: tx_id,
17180            });
17181            Some(tx_id)
17182        } else {
17183            None
17184        }
17185    }
17186
17187    pub fn end_transaction_at(
17188        &mut self,
17189        now: Instant,
17190        cx: &mut Context<Self>,
17191    ) -> Option<TransactionId> {
17192        if let Some(transaction_id) = self
17193            .buffer
17194            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
17195        {
17196            if let Some((_, end_selections)) =
17197                self.selection_history.transaction_mut(transaction_id)
17198            {
17199                *end_selections = Some(self.selections.disjoint_anchors());
17200            } else {
17201                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
17202            }
17203
17204            cx.emit(EditorEvent::Edited { transaction_id });
17205            Some(transaction_id)
17206        } else {
17207            None
17208        }
17209    }
17210
17211    pub fn modify_transaction_selection_history(
17212        &mut self,
17213        transaction_id: TransactionId,
17214        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
17215    ) -> bool {
17216        self.selection_history
17217            .transaction_mut(transaction_id)
17218            .map(modify)
17219            .is_some()
17220    }
17221
17222    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
17223        if self.selection_mark_mode {
17224            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17225                s.move_with(|_, sel| {
17226                    sel.collapse_to(sel.head(), SelectionGoal::None);
17227                });
17228            })
17229        }
17230        self.selection_mark_mode = true;
17231        cx.notify();
17232    }
17233
17234    pub fn swap_selection_ends(
17235        &mut self,
17236        _: &actions::SwapSelectionEnds,
17237        window: &mut Window,
17238        cx: &mut Context<Self>,
17239    ) {
17240        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17241            s.move_with(|_, sel| {
17242                if sel.start != sel.end {
17243                    sel.reversed = !sel.reversed
17244                }
17245            });
17246        });
17247        self.request_autoscroll(Autoscroll::newest(), cx);
17248        cx.notify();
17249    }
17250
17251    pub fn toggle_focus(
17252        workspace: &mut Workspace,
17253        _: &actions::ToggleFocus,
17254        window: &mut Window,
17255        cx: &mut Context<Workspace>,
17256    ) {
17257        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
17258            return;
17259        };
17260        workspace.activate_item(&item, true, true, window, cx);
17261    }
17262
17263    pub fn toggle_fold(
17264        &mut self,
17265        _: &actions::ToggleFold,
17266        window: &mut Window,
17267        cx: &mut Context<Self>,
17268    ) {
17269        if self.is_singleton(cx) {
17270            let selection = self.selections.newest::<Point>(cx);
17271
17272            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17273            let range = if selection.is_empty() {
17274                let point = selection.head().to_display_point(&display_map);
17275                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17276                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17277                    .to_point(&display_map);
17278                start..end
17279            } else {
17280                selection.range()
17281            };
17282            if display_map.folds_in_range(range).next().is_some() {
17283                self.unfold_lines(&Default::default(), window, cx)
17284            } else {
17285                self.fold(&Default::default(), window, cx)
17286            }
17287        } else {
17288            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17289            let buffer_ids: HashSet<_> = self
17290                .selections
17291                .disjoint_anchor_ranges()
17292                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17293                .collect();
17294
17295            let should_unfold = buffer_ids
17296                .iter()
17297                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17298
17299            for buffer_id in buffer_ids {
17300                if should_unfold {
17301                    self.unfold_buffer(buffer_id, cx);
17302                } else {
17303                    self.fold_buffer(buffer_id, cx);
17304                }
17305            }
17306        }
17307    }
17308
17309    pub fn toggle_fold_recursive(
17310        &mut self,
17311        _: &actions::ToggleFoldRecursive,
17312        window: &mut Window,
17313        cx: &mut Context<Self>,
17314    ) {
17315        let selection = self.selections.newest::<Point>(cx);
17316
17317        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17318        let range = if selection.is_empty() {
17319            let point = selection.head().to_display_point(&display_map);
17320            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
17321            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
17322                .to_point(&display_map);
17323            start..end
17324        } else {
17325            selection.range()
17326        };
17327        if display_map.folds_in_range(range).next().is_some() {
17328            self.unfold_recursive(&Default::default(), window, cx)
17329        } else {
17330            self.fold_recursive(&Default::default(), window, cx)
17331        }
17332    }
17333
17334    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
17335        if self.is_singleton(cx) {
17336            let mut to_fold = Vec::new();
17337            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17338            let selections = self.selections.all_adjusted(cx);
17339
17340            for selection in selections {
17341                let range = selection.range().sorted();
17342                let buffer_start_row = range.start.row;
17343
17344                if range.start.row != range.end.row {
17345                    let mut found = false;
17346                    let mut row = range.start.row;
17347                    while row <= range.end.row {
17348                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17349                        {
17350                            found = true;
17351                            row = crease.range().end.row + 1;
17352                            to_fold.push(crease);
17353                        } else {
17354                            row += 1
17355                        }
17356                    }
17357                    if found {
17358                        continue;
17359                    }
17360                }
17361
17362                for row in (0..=range.start.row).rev() {
17363                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
17364                        && crease.range().end.row >= buffer_start_row
17365                    {
17366                        to_fold.push(crease);
17367                        if row <= range.start.row {
17368                            break;
17369                        }
17370                    }
17371                }
17372            }
17373
17374            self.fold_creases(to_fold, true, window, cx);
17375        } else {
17376            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17377            let buffer_ids = self
17378                .selections
17379                .disjoint_anchor_ranges()
17380                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17381                .collect::<HashSet<_>>();
17382            for buffer_id in buffer_ids {
17383                self.fold_buffer(buffer_id, cx);
17384            }
17385        }
17386    }
17387
17388    pub fn toggle_fold_all(
17389        &mut self,
17390        _: &actions::ToggleFoldAll,
17391        window: &mut Window,
17392        cx: &mut Context<Self>,
17393    ) {
17394        if self.buffer.read(cx).is_singleton() {
17395            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17396            let has_folds = display_map
17397                .folds_in_range(0..display_map.buffer_snapshot.len())
17398                .next()
17399                .is_some();
17400
17401            if has_folds {
17402                self.unfold_all(&actions::UnfoldAll, window, cx);
17403            } else {
17404                self.fold_all(&actions::FoldAll, window, cx);
17405            }
17406        } else {
17407            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
17408            let should_unfold = buffer_ids
17409                .iter()
17410                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
17411
17412            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17413                editor
17414                    .update_in(cx, |editor, _, cx| {
17415                        for buffer_id in buffer_ids {
17416                            if should_unfold {
17417                                editor.unfold_buffer(buffer_id, cx);
17418                            } else {
17419                                editor.fold_buffer(buffer_id, cx);
17420                            }
17421                        }
17422                    })
17423                    .ok();
17424            });
17425        }
17426    }
17427
17428    fn fold_at_level(
17429        &mut self,
17430        fold_at: &FoldAtLevel,
17431        window: &mut Window,
17432        cx: &mut Context<Self>,
17433    ) {
17434        if !self.buffer.read(cx).is_singleton() {
17435            return;
17436        }
17437
17438        let fold_at_level = fold_at.0;
17439        let snapshot = self.buffer.read(cx).snapshot(cx);
17440        let mut to_fold = Vec::new();
17441        let mut stack = vec![(0, snapshot.max_row().0, 1)];
17442
17443        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
17444            while start_row < end_row {
17445                match self
17446                    .snapshot(window, cx)
17447                    .crease_for_buffer_row(MultiBufferRow(start_row))
17448                {
17449                    Some(crease) => {
17450                        let nested_start_row = crease.range().start.row + 1;
17451                        let nested_end_row = crease.range().end.row;
17452
17453                        if current_level < fold_at_level {
17454                            stack.push((nested_start_row, nested_end_row, current_level + 1));
17455                        } else if current_level == fold_at_level {
17456                            to_fold.push(crease);
17457                        }
17458
17459                        start_row = nested_end_row + 1;
17460                    }
17461                    None => start_row += 1,
17462                }
17463            }
17464        }
17465
17466        self.fold_creases(to_fold, true, window, cx);
17467    }
17468
17469    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
17470        if self.buffer.read(cx).is_singleton() {
17471            let mut fold_ranges = Vec::new();
17472            let snapshot = self.buffer.read(cx).snapshot(cx);
17473
17474            for row in 0..snapshot.max_row().0 {
17475                if let Some(foldable_range) = self
17476                    .snapshot(window, cx)
17477                    .crease_for_buffer_row(MultiBufferRow(row))
17478                {
17479                    fold_ranges.push(foldable_range);
17480                }
17481            }
17482
17483            self.fold_creases(fold_ranges, true, window, cx);
17484        } else {
17485            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
17486                editor
17487                    .update_in(cx, |editor, _, cx| {
17488                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17489                            editor.fold_buffer(buffer_id, cx);
17490                        }
17491                    })
17492                    .ok();
17493            });
17494        }
17495    }
17496
17497    pub fn fold_function_bodies(
17498        &mut self,
17499        _: &actions::FoldFunctionBodies,
17500        window: &mut Window,
17501        cx: &mut Context<Self>,
17502    ) {
17503        let snapshot = self.buffer.read(cx).snapshot(cx);
17504
17505        let ranges = snapshot
17506            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
17507            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
17508            .collect::<Vec<_>>();
17509
17510        let creases = ranges
17511            .into_iter()
17512            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
17513            .collect();
17514
17515        self.fold_creases(creases, true, window, cx);
17516    }
17517
17518    pub fn fold_recursive(
17519        &mut self,
17520        _: &actions::FoldRecursive,
17521        window: &mut Window,
17522        cx: &mut Context<Self>,
17523    ) {
17524        let mut to_fold = Vec::new();
17525        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17526        let selections = self.selections.all_adjusted(cx);
17527
17528        for selection in selections {
17529            let range = selection.range().sorted();
17530            let buffer_start_row = range.start.row;
17531
17532            if range.start.row != range.end.row {
17533                let mut found = false;
17534                for row in range.start.row..=range.end.row {
17535                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17536                        found = true;
17537                        to_fold.push(crease);
17538                    }
17539                }
17540                if found {
17541                    continue;
17542                }
17543            }
17544
17545            for row in (0..=range.start.row).rev() {
17546                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
17547                    if crease.range().end.row >= buffer_start_row {
17548                        to_fold.push(crease);
17549                    } else {
17550                        break;
17551                    }
17552                }
17553            }
17554        }
17555
17556        self.fold_creases(to_fold, true, window, cx);
17557    }
17558
17559    pub fn fold_at(
17560        &mut self,
17561        buffer_row: MultiBufferRow,
17562        window: &mut Window,
17563        cx: &mut Context<Self>,
17564    ) {
17565        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17566
17567        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
17568            let autoscroll = self
17569                .selections
17570                .all::<Point>(cx)
17571                .iter()
17572                .any(|selection| crease.range().overlaps(&selection.range()));
17573
17574            self.fold_creases(vec![crease], autoscroll, window, cx);
17575        }
17576    }
17577
17578    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
17579        if self.is_singleton(cx) {
17580            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17581            let buffer = &display_map.buffer_snapshot;
17582            let selections = self.selections.all::<Point>(cx);
17583            let ranges = selections
17584                .iter()
17585                .map(|s| {
17586                    let range = s.display_range(&display_map).sorted();
17587                    let mut start = range.start.to_point(&display_map);
17588                    let mut end = range.end.to_point(&display_map);
17589                    start.column = 0;
17590                    end.column = buffer.line_len(MultiBufferRow(end.row));
17591                    start..end
17592                })
17593                .collect::<Vec<_>>();
17594
17595            self.unfold_ranges(&ranges, true, true, cx);
17596        } else {
17597            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
17598            let buffer_ids = self
17599                .selections
17600                .disjoint_anchor_ranges()
17601                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
17602                .collect::<HashSet<_>>();
17603            for buffer_id in buffer_ids {
17604                self.unfold_buffer(buffer_id, cx);
17605            }
17606        }
17607    }
17608
17609    pub fn unfold_recursive(
17610        &mut self,
17611        _: &UnfoldRecursive,
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        let selections = self.selections.all::<Point>(cx);
17617        let ranges = selections
17618            .iter()
17619            .map(|s| {
17620                let mut range = s.display_range(&display_map).sorted();
17621                *range.start.column_mut() = 0;
17622                *range.end.column_mut() = display_map.line_len(range.end.row());
17623                let start = range.start.to_point(&display_map);
17624                let end = range.end.to_point(&display_map);
17625                start..end
17626            })
17627            .collect::<Vec<_>>();
17628
17629        self.unfold_ranges(&ranges, true, true, cx);
17630    }
17631
17632    pub fn unfold_at(
17633        &mut self,
17634        buffer_row: MultiBufferRow,
17635        _window: &mut Window,
17636        cx: &mut Context<Self>,
17637    ) {
17638        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17639
17640        let intersection_range = Point::new(buffer_row.0, 0)
17641            ..Point::new(
17642                buffer_row.0,
17643                display_map.buffer_snapshot.line_len(buffer_row),
17644            );
17645
17646        let autoscroll = self
17647            .selections
17648            .all::<Point>(cx)
17649            .iter()
17650            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
17651
17652        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
17653    }
17654
17655    pub fn unfold_all(
17656        &mut self,
17657        _: &actions::UnfoldAll,
17658        _window: &mut Window,
17659        cx: &mut Context<Self>,
17660    ) {
17661        if self.buffer.read(cx).is_singleton() {
17662            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17663            self.unfold_ranges(&[0..display_map.buffer_snapshot.len()], true, true, cx);
17664        } else {
17665            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
17666                editor
17667                    .update(cx, |editor, cx| {
17668                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
17669                            editor.unfold_buffer(buffer_id, cx);
17670                        }
17671                    })
17672                    .ok();
17673            });
17674        }
17675    }
17676
17677    pub fn fold_selected_ranges(
17678        &mut self,
17679        _: &FoldSelectedRanges,
17680        window: &mut Window,
17681        cx: &mut Context<Self>,
17682    ) {
17683        let selections = self.selections.all_adjusted(cx);
17684        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17685        let ranges = selections
17686            .into_iter()
17687            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
17688            .collect::<Vec<_>>();
17689        self.fold_creases(ranges, true, window, cx);
17690    }
17691
17692    pub fn fold_ranges<T: ToOffset + Clone>(
17693        &mut self,
17694        ranges: Vec<Range<T>>,
17695        auto_scroll: bool,
17696        window: &mut Window,
17697        cx: &mut Context<Self>,
17698    ) {
17699        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17700        let ranges = ranges
17701            .into_iter()
17702            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
17703            .collect::<Vec<_>>();
17704        self.fold_creases(ranges, auto_scroll, window, cx);
17705    }
17706
17707    pub fn fold_creases<T: ToOffset + Clone>(
17708        &mut self,
17709        creases: Vec<Crease<T>>,
17710        auto_scroll: bool,
17711        _window: &mut Window,
17712        cx: &mut Context<Self>,
17713    ) {
17714        if creases.is_empty() {
17715            return;
17716        }
17717
17718        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
17719
17720        if auto_scroll {
17721            self.request_autoscroll(Autoscroll::fit(), cx);
17722        }
17723
17724        cx.notify();
17725
17726        self.scrollbar_marker_state.dirty = true;
17727        self.folds_did_change(cx);
17728    }
17729
17730    /// Removes any folds whose ranges intersect any of the given ranges.
17731    pub fn unfold_ranges<T: ToOffset + Clone>(
17732        &mut self,
17733        ranges: &[Range<T>],
17734        inclusive: bool,
17735        auto_scroll: bool,
17736        cx: &mut Context<Self>,
17737    ) {
17738        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17739            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
17740        });
17741        self.folds_did_change(cx);
17742    }
17743
17744    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17745        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
17746            return;
17747        }
17748        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17749        self.display_map.update(cx, |display_map, cx| {
17750            display_map.fold_buffers([buffer_id], cx)
17751        });
17752        cx.emit(EditorEvent::BufferFoldToggled {
17753            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
17754            folded: true,
17755        });
17756        cx.notify();
17757    }
17758
17759    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17760        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
17761            return;
17762        }
17763        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
17764        self.display_map.update(cx, |display_map, cx| {
17765            display_map.unfold_buffers([buffer_id], cx);
17766        });
17767        cx.emit(EditorEvent::BufferFoldToggled {
17768            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
17769            folded: false,
17770        });
17771        cx.notify();
17772    }
17773
17774    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
17775        self.display_map.read(cx).is_buffer_folded(buffer)
17776    }
17777
17778    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
17779        self.display_map.read(cx).folded_buffers()
17780    }
17781
17782    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
17783        self.display_map.update(cx, |display_map, cx| {
17784            display_map.disable_header_for_buffer(buffer_id, cx);
17785        });
17786        cx.notify();
17787    }
17788
17789    /// Removes any folds with the given ranges.
17790    pub fn remove_folds_with_type<T: ToOffset + Clone>(
17791        &mut self,
17792        ranges: &[Range<T>],
17793        type_id: TypeId,
17794        auto_scroll: bool,
17795        cx: &mut Context<Self>,
17796    ) {
17797        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
17798            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
17799        });
17800        self.folds_did_change(cx);
17801    }
17802
17803    fn remove_folds_with<T: ToOffset + Clone>(
17804        &mut self,
17805        ranges: &[Range<T>],
17806        auto_scroll: bool,
17807        cx: &mut Context<Self>,
17808        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
17809    ) {
17810        if ranges.is_empty() {
17811            return;
17812        }
17813
17814        let mut buffers_affected = HashSet::default();
17815        let multi_buffer = self.buffer().read(cx);
17816        for range in ranges {
17817            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
17818                buffers_affected.insert(buffer.read(cx).remote_id());
17819            };
17820        }
17821
17822        self.display_map.update(cx, update);
17823
17824        if auto_scroll {
17825            self.request_autoscroll(Autoscroll::fit(), cx);
17826        }
17827
17828        cx.notify();
17829        self.scrollbar_marker_state.dirty = true;
17830        self.active_indent_guides_state.dirty = true;
17831    }
17832
17833    pub fn update_renderer_widths(
17834        &mut self,
17835        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
17836        cx: &mut Context<Self>,
17837    ) -> bool {
17838        self.display_map
17839            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
17840    }
17841
17842    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
17843        self.display_map.read(cx).fold_placeholder.clone()
17844    }
17845
17846    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
17847        self.buffer.update(cx, |buffer, cx| {
17848            buffer.set_all_diff_hunks_expanded(cx);
17849        });
17850    }
17851
17852    pub fn expand_all_diff_hunks(
17853        &mut self,
17854        _: &ExpandAllDiffHunks,
17855        _window: &mut Window,
17856        cx: &mut Context<Self>,
17857    ) {
17858        self.buffer.update(cx, |buffer, cx| {
17859            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
17860        });
17861    }
17862
17863    pub fn toggle_selected_diff_hunks(
17864        &mut self,
17865        _: &ToggleSelectedDiffHunks,
17866        _window: &mut Window,
17867        cx: &mut Context<Self>,
17868    ) {
17869        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17870        self.toggle_diff_hunks_in_ranges(ranges, cx);
17871    }
17872
17873    pub fn diff_hunks_in_ranges<'a>(
17874        &'a self,
17875        ranges: &'a [Range<Anchor>],
17876        buffer: &'a MultiBufferSnapshot,
17877    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
17878        ranges.iter().flat_map(move |range| {
17879            let end_excerpt_id = range.end.excerpt_id;
17880            let range = range.to_point(buffer);
17881            let mut peek_end = range.end;
17882            if range.end.row < buffer.max_row().0 {
17883                peek_end = Point::new(range.end.row + 1, 0);
17884            }
17885            buffer
17886                .diff_hunks_in_range(range.start..peek_end)
17887                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
17888        })
17889    }
17890
17891    pub fn has_stageable_diff_hunks_in_ranges(
17892        &self,
17893        ranges: &[Range<Anchor>],
17894        snapshot: &MultiBufferSnapshot,
17895    ) -> bool {
17896        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
17897        hunks.any(|hunk| hunk.status().has_secondary_hunk())
17898    }
17899
17900    pub fn toggle_staged_selected_diff_hunks(
17901        &mut self,
17902        _: &::git::ToggleStaged,
17903        _: &mut Window,
17904        cx: &mut Context<Self>,
17905    ) {
17906        let snapshot = self.buffer.read(cx).snapshot(cx);
17907        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
17908        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
17909        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
17910    }
17911
17912    pub fn set_render_diff_hunk_controls(
17913        &mut self,
17914        render_diff_hunk_controls: RenderDiffHunkControlsFn,
17915        cx: &mut Context<Self>,
17916    ) {
17917        self.render_diff_hunk_controls = render_diff_hunk_controls;
17918        cx.notify();
17919    }
17920
17921    pub fn stage_and_next(
17922        &mut self,
17923        _: &::git::StageAndNext,
17924        window: &mut Window,
17925        cx: &mut Context<Self>,
17926    ) {
17927        self.do_stage_or_unstage_and_next(true, window, cx);
17928    }
17929
17930    pub fn unstage_and_next(
17931        &mut self,
17932        _: &::git::UnstageAndNext,
17933        window: &mut Window,
17934        cx: &mut Context<Self>,
17935    ) {
17936        self.do_stage_or_unstage_and_next(false, window, cx);
17937    }
17938
17939    pub fn stage_or_unstage_diff_hunks(
17940        &mut self,
17941        stage: bool,
17942        ranges: Vec<Range<Anchor>>,
17943        cx: &mut Context<Self>,
17944    ) {
17945        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
17946        cx.spawn(async move |this, cx| {
17947            task.await?;
17948            this.update(cx, |this, cx| {
17949                let snapshot = this.buffer.read(cx).snapshot(cx);
17950                let chunk_by = this
17951                    .diff_hunks_in_ranges(&ranges, &snapshot)
17952                    .chunk_by(|hunk| hunk.buffer_id);
17953                for (buffer_id, hunks) in &chunk_by {
17954                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
17955                }
17956            })
17957        })
17958        .detach_and_log_err(cx);
17959    }
17960
17961    fn save_buffers_for_ranges_if_needed(
17962        &mut self,
17963        ranges: &[Range<Anchor>],
17964        cx: &mut Context<Editor>,
17965    ) -> Task<Result<()>> {
17966        let multibuffer = self.buffer.read(cx);
17967        let snapshot = multibuffer.read(cx);
17968        let buffer_ids: HashSet<_> = ranges
17969            .iter()
17970            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
17971            .collect();
17972        drop(snapshot);
17973
17974        let mut buffers = HashSet::default();
17975        for buffer_id in buffer_ids {
17976            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
17977                let buffer = buffer_entity.read(cx);
17978                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
17979                {
17980                    buffers.insert(buffer_entity);
17981                }
17982            }
17983        }
17984
17985        if let Some(project) = &self.project {
17986            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
17987        } else {
17988            Task::ready(Ok(()))
17989        }
17990    }
17991
17992    fn do_stage_or_unstage_and_next(
17993        &mut self,
17994        stage: bool,
17995        window: &mut Window,
17996        cx: &mut Context<Self>,
17997    ) {
17998        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
17999
18000        if ranges.iter().any(|range| range.start != range.end) {
18001            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18002            return;
18003        }
18004
18005        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18006        let snapshot = self.snapshot(window, cx);
18007        let position = self.selections.newest::<Point>(cx).head();
18008        let mut row = snapshot
18009            .buffer_snapshot
18010            .diff_hunks_in_range(position..snapshot.buffer_snapshot.max_point())
18011            .find(|hunk| hunk.row_range.start.0 > position.row)
18012            .map(|hunk| hunk.row_range.start);
18013
18014        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18015        // Outside of the project diff editor, wrap around to the beginning.
18016        if !all_diff_hunks_expanded {
18017            row = row.or_else(|| {
18018                snapshot
18019                    .buffer_snapshot
18020                    .diff_hunks_in_range(Point::zero()..position)
18021                    .find(|hunk| hunk.row_range.end.0 < position.row)
18022                    .map(|hunk| hunk.row_range.start)
18023            });
18024        }
18025
18026        if let Some(row) = row {
18027            let destination = Point::new(row.0, 0);
18028            let autoscroll = Autoscroll::center();
18029
18030            self.unfold_ranges(&[destination..destination], false, false, cx);
18031            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18032                s.select_ranges([destination..destination]);
18033            });
18034        }
18035    }
18036
18037    fn do_stage_or_unstage(
18038        &self,
18039        stage: bool,
18040        buffer_id: BufferId,
18041        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
18042        cx: &mut App,
18043    ) -> Option<()> {
18044        let project = self.project()?;
18045        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
18046        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
18047        let buffer_snapshot = buffer.read(cx).snapshot();
18048        let file_exists = buffer_snapshot
18049            .file()
18050            .is_some_and(|file| file.disk_state().exists());
18051        diff.update(cx, |diff, cx| {
18052            diff.stage_or_unstage_hunks(
18053                stage,
18054                &hunks
18055                    .map(|hunk| buffer_diff::DiffHunk {
18056                        buffer_range: hunk.buffer_range,
18057                        diff_base_byte_range: hunk.diff_base_byte_range,
18058                        secondary_status: hunk.secondary_status,
18059                        range: Point::zero()..Point::zero(), // unused
18060                    })
18061                    .collect::<Vec<_>>(),
18062                &buffer_snapshot,
18063                file_exists,
18064                cx,
18065            )
18066        });
18067        None
18068    }
18069
18070    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
18071        let ranges: Vec<_> = self.selections.disjoint.iter().map(|s| s.range()).collect();
18072        self.buffer
18073            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
18074    }
18075
18076    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
18077        self.buffer.update(cx, |buffer, cx| {
18078            let ranges = vec![Anchor::min()..Anchor::max()];
18079            if !buffer.all_diff_hunks_expanded()
18080                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
18081            {
18082                buffer.collapse_diff_hunks(ranges, cx);
18083                true
18084            } else {
18085                false
18086            }
18087        })
18088    }
18089
18090    fn toggle_diff_hunks_in_ranges(
18091        &mut self,
18092        ranges: Vec<Range<Anchor>>,
18093        cx: &mut Context<Editor>,
18094    ) {
18095        self.buffer.update(cx, |buffer, cx| {
18096            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
18097            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
18098        })
18099    }
18100
18101    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
18102        self.buffer.update(cx, |buffer, cx| {
18103            let snapshot = buffer.snapshot(cx);
18104            let excerpt_id = range.end.excerpt_id;
18105            let point_range = range.to_point(&snapshot);
18106            let expand = !buffer.single_hunk_is_expanded(range, cx);
18107            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
18108        })
18109    }
18110
18111    pub(crate) fn apply_all_diff_hunks(
18112        &mut self,
18113        _: &ApplyAllDiffHunks,
18114        window: &mut Window,
18115        cx: &mut Context<Self>,
18116    ) {
18117        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18118
18119        let buffers = self.buffer.read(cx).all_buffers();
18120        for branch_buffer in buffers {
18121            branch_buffer.update(cx, |branch_buffer, cx| {
18122                branch_buffer.merge_into_base(Vec::new(), cx);
18123            });
18124        }
18125
18126        if let Some(project) = self.project.clone() {
18127            self.save(
18128                SaveOptions {
18129                    format: true,
18130                    autosave: false,
18131                },
18132                project,
18133                window,
18134                cx,
18135            )
18136            .detach_and_log_err(cx);
18137        }
18138    }
18139
18140    pub(crate) fn apply_selected_diff_hunks(
18141        &mut self,
18142        _: &ApplyDiffHunk,
18143        window: &mut Window,
18144        cx: &mut Context<Self>,
18145    ) {
18146        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18147        let snapshot = self.snapshot(window, cx);
18148        let hunks = snapshot.hunks_for_ranges(self.selections.ranges(cx));
18149        let mut ranges_by_buffer = HashMap::default();
18150        self.transact(window, cx, |editor, _window, cx| {
18151            for hunk in hunks {
18152                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
18153                    ranges_by_buffer
18154                        .entry(buffer.clone())
18155                        .or_insert_with(Vec::new)
18156                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
18157                }
18158            }
18159
18160            for (buffer, ranges) in ranges_by_buffer {
18161                buffer.update(cx, |buffer, cx| {
18162                    buffer.merge_into_base(ranges, cx);
18163                });
18164            }
18165        });
18166
18167        if let Some(project) = self.project.clone() {
18168            self.save(
18169                SaveOptions {
18170                    format: true,
18171                    autosave: false,
18172                },
18173                project,
18174                window,
18175                cx,
18176            )
18177            .detach_and_log_err(cx);
18178        }
18179    }
18180
18181    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
18182        if hovered != self.gutter_hovered {
18183            self.gutter_hovered = hovered;
18184            cx.notify();
18185        }
18186    }
18187
18188    pub fn insert_blocks(
18189        &mut self,
18190        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
18191        autoscroll: Option<Autoscroll>,
18192        cx: &mut Context<Self>,
18193    ) -> Vec<CustomBlockId> {
18194        let blocks = self
18195            .display_map
18196            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
18197        if let Some(autoscroll) = autoscroll {
18198            self.request_autoscroll(autoscroll, cx);
18199        }
18200        cx.notify();
18201        blocks
18202    }
18203
18204    pub fn resize_blocks(
18205        &mut self,
18206        heights: HashMap<CustomBlockId, u32>,
18207        autoscroll: Option<Autoscroll>,
18208        cx: &mut Context<Self>,
18209    ) {
18210        self.display_map
18211            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
18212        if let Some(autoscroll) = autoscroll {
18213            self.request_autoscroll(autoscroll, cx);
18214        }
18215        cx.notify();
18216    }
18217
18218    pub fn replace_blocks(
18219        &mut self,
18220        renderers: HashMap<CustomBlockId, RenderBlock>,
18221        autoscroll: Option<Autoscroll>,
18222        cx: &mut Context<Self>,
18223    ) {
18224        self.display_map
18225            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
18226        if let Some(autoscroll) = autoscroll {
18227            self.request_autoscroll(autoscroll, cx);
18228        }
18229        cx.notify();
18230    }
18231
18232    pub fn remove_blocks(
18233        &mut self,
18234        block_ids: HashSet<CustomBlockId>,
18235        autoscroll: Option<Autoscroll>,
18236        cx: &mut Context<Self>,
18237    ) {
18238        self.display_map.update(cx, |display_map, cx| {
18239            display_map.remove_blocks(block_ids, cx)
18240        });
18241        if let Some(autoscroll) = autoscroll {
18242            self.request_autoscroll(autoscroll, cx);
18243        }
18244        cx.notify();
18245    }
18246
18247    pub fn row_for_block(
18248        &self,
18249        block_id: CustomBlockId,
18250        cx: &mut Context<Self>,
18251    ) -> Option<DisplayRow> {
18252        self.display_map
18253            .update(cx, |map, cx| map.row_for_block(block_id, cx))
18254    }
18255
18256    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
18257        self.focused_block = Some(focused_block);
18258    }
18259
18260    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
18261        self.focused_block.take()
18262    }
18263
18264    pub fn insert_creases(
18265        &mut self,
18266        creases: impl IntoIterator<Item = Crease<Anchor>>,
18267        cx: &mut Context<Self>,
18268    ) -> Vec<CreaseId> {
18269        self.display_map
18270            .update(cx, |map, cx| map.insert_creases(creases, cx))
18271    }
18272
18273    pub fn remove_creases(
18274        &mut self,
18275        ids: impl IntoIterator<Item = CreaseId>,
18276        cx: &mut Context<Self>,
18277    ) -> Vec<(CreaseId, Range<Anchor>)> {
18278        self.display_map
18279            .update(cx, |map, cx| map.remove_creases(ids, cx))
18280    }
18281
18282    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
18283        self.display_map
18284            .update(cx, |map, cx| map.snapshot(cx))
18285            .longest_row()
18286    }
18287
18288    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
18289        self.display_map
18290            .update(cx, |map, cx| map.snapshot(cx))
18291            .max_point()
18292    }
18293
18294    pub fn text(&self, cx: &App) -> String {
18295        self.buffer.read(cx).read(cx).text()
18296    }
18297
18298    pub fn is_empty(&self, cx: &App) -> bool {
18299        self.buffer.read(cx).read(cx).is_empty()
18300    }
18301
18302    pub fn text_option(&self, cx: &App) -> Option<String> {
18303        let text = self.text(cx);
18304        let text = text.trim();
18305
18306        if text.is_empty() {
18307            return None;
18308        }
18309
18310        Some(text.to_string())
18311    }
18312
18313    pub fn set_text(
18314        &mut self,
18315        text: impl Into<Arc<str>>,
18316        window: &mut Window,
18317        cx: &mut Context<Self>,
18318    ) {
18319        self.transact(window, cx, |this, _, cx| {
18320            this.buffer
18321                .read(cx)
18322                .as_singleton()
18323                .expect("you can only call set_text on editors for singleton buffers")
18324                .update(cx, |buffer, cx| buffer.set_text(text, cx));
18325        });
18326    }
18327
18328    pub fn display_text(&self, cx: &mut App) -> String {
18329        self.display_map
18330            .update(cx, |map, cx| map.snapshot(cx))
18331            .text()
18332    }
18333
18334    fn create_minimap(
18335        &self,
18336        minimap_settings: MinimapSettings,
18337        window: &mut Window,
18338        cx: &mut Context<Self>,
18339    ) -> Option<Entity<Self>> {
18340        (minimap_settings.minimap_enabled() && self.is_singleton(cx))
18341            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
18342    }
18343
18344    fn initialize_new_minimap(
18345        &self,
18346        minimap_settings: MinimapSettings,
18347        window: &mut Window,
18348        cx: &mut Context<Self>,
18349    ) -> Entity<Self> {
18350        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
18351
18352        let mut minimap = Editor::new_internal(
18353            EditorMode::Minimap {
18354                parent: cx.weak_entity(),
18355            },
18356            self.buffer.clone(),
18357            None,
18358            Some(self.display_map.clone()),
18359            window,
18360            cx,
18361        );
18362        minimap.scroll_manager.clone_state(&self.scroll_manager);
18363        minimap.set_text_style_refinement(TextStyleRefinement {
18364            font_size: Some(MINIMAP_FONT_SIZE),
18365            font_weight: Some(MINIMAP_FONT_WEIGHT),
18366            ..Default::default()
18367        });
18368        minimap.update_minimap_configuration(minimap_settings, cx);
18369        cx.new(|_| minimap)
18370    }
18371
18372    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
18373        let current_line_highlight = minimap_settings
18374            .current_line_highlight
18375            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
18376        self.set_current_line_highlight(Some(current_line_highlight));
18377    }
18378
18379    pub fn minimap(&self) -> Option<&Entity<Self>> {
18380        self.minimap
18381            .as_ref()
18382            .filter(|_| self.minimap_visibility.visible())
18383    }
18384
18385    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
18386        let mut wrap_guides = smallvec![];
18387
18388        if self.show_wrap_guides == Some(false) {
18389            return wrap_guides;
18390        }
18391
18392        let settings = self.buffer.read(cx).language_settings(cx);
18393        if settings.show_wrap_guides {
18394            match self.soft_wrap_mode(cx) {
18395                SoftWrap::Column(soft_wrap) => {
18396                    wrap_guides.push((soft_wrap as usize, true));
18397                }
18398                SoftWrap::Bounded(soft_wrap) => {
18399                    wrap_guides.push((soft_wrap as usize, true));
18400                }
18401                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
18402            }
18403            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
18404        }
18405
18406        wrap_guides
18407    }
18408
18409    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
18410        let settings = self.buffer.read(cx).language_settings(cx);
18411        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
18412        match mode {
18413            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
18414                SoftWrap::None
18415            }
18416            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
18417            language_settings::SoftWrap::PreferredLineLength => {
18418                SoftWrap::Column(settings.preferred_line_length)
18419            }
18420            language_settings::SoftWrap::Bounded => {
18421                SoftWrap::Bounded(settings.preferred_line_length)
18422            }
18423        }
18424    }
18425
18426    pub fn set_soft_wrap_mode(
18427        &mut self,
18428        mode: language_settings::SoftWrap,
18429
18430        cx: &mut Context<Self>,
18431    ) {
18432        self.soft_wrap_mode_override = Some(mode);
18433        cx.notify();
18434    }
18435
18436    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
18437        self.hard_wrap = hard_wrap;
18438        cx.notify();
18439    }
18440
18441    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
18442        self.text_style_refinement = Some(style);
18443    }
18444
18445    /// called by the Element so we know what style we were most recently rendered with.
18446    pub(crate) fn set_style(
18447        &mut self,
18448        style: EditorStyle,
18449        window: &mut Window,
18450        cx: &mut Context<Self>,
18451    ) {
18452        // We intentionally do not inform the display map about the minimap style
18453        // so that wrapping is not recalculated and stays consistent for the editor
18454        // and its linked minimap.
18455        if !self.mode.is_minimap() {
18456            let rem_size = window.rem_size();
18457            self.display_map.update(cx, |map, cx| {
18458                map.set_font(
18459                    style.text.font(),
18460                    style.text.font_size.to_pixels(rem_size),
18461                    cx,
18462                )
18463            });
18464        }
18465        self.style = Some(style);
18466    }
18467
18468    pub fn style(&self) -> Option<&EditorStyle> {
18469        self.style.as_ref()
18470    }
18471
18472    // Called by the element. This method is not designed to be called outside of the editor
18473    // element's layout code because it does not notify when rewrapping is computed synchronously.
18474    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
18475        self.display_map
18476            .update(cx, |map, cx| map.set_wrap_width(width, cx))
18477    }
18478
18479    pub fn set_soft_wrap(&mut self) {
18480        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
18481    }
18482
18483    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
18484        if self.soft_wrap_mode_override.is_some() {
18485            self.soft_wrap_mode_override.take();
18486        } else {
18487            let soft_wrap = match self.soft_wrap_mode(cx) {
18488                SoftWrap::GitDiff => return,
18489                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
18490                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
18491                    language_settings::SoftWrap::None
18492                }
18493            };
18494            self.soft_wrap_mode_override = Some(soft_wrap);
18495        }
18496        cx.notify();
18497    }
18498
18499    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
18500        let Some(workspace) = self.workspace() else {
18501            return;
18502        };
18503        let fs = workspace.read(cx).app_state().fs.clone();
18504        let current_show = TabBarSettings::get_global(cx).show;
18505        update_settings_file::<TabBarSettings>(fs, cx, move |setting, _| {
18506            setting.show = Some(!current_show);
18507        });
18508    }
18509
18510    pub fn toggle_indent_guides(
18511        &mut self,
18512        _: &ToggleIndentGuides,
18513        _: &mut Window,
18514        cx: &mut Context<Self>,
18515    ) {
18516        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
18517            self.buffer
18518                .read(cx)
18519                .language_settings(cx)
18520                .indent_guides
18521                .enabled
18522        });
18523        self.show_indent_guides = Some(!currently_enabled);
18524        cx.notify();
18525    }
18526
18527    fn should_show_indent_guides(&self) -> Option<bool> {
18528        self.show_indent_guides
18529    }
18530
18531    pub fn toggle_line_numbers(
18532        &mut self,
18533        _: &ToggleLineNumbers,
18534        _: &mut Window,
18535        cx: &mut Context<Self>,
18536    ) {
18537        let mut editor_settings = EditorSettings::get_global(cx).clone();
18538        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
18539        EditorSettings::override_global(editor_settings, cx);
18540    }
18541
18542    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
18543        if let Some(show_line_numbers) = self.show_line_numbers {
18544            return show_line_numbers;
18545        }
18546        EditorSettings::get_global(cx).gutter.line_numbers
18547    }
18548
18549    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
18550        self.use_relative_line_numbers
18551            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
18552    }
18553
18554    pub fn toggle_relative_line_numbers(
18555        &mut self,
18556        _: &ToggleRelativeLineNumbers,
18557        _: &mut Window,
18558        cx: &mut Context<Self>,
18559    ) {
18560        let is_relative = self.should_use_relative_line_numbers(cx);
18561        self.set_relative_line_number(Some(!is_relative), cx)
18562    }
18563
18564    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
18565        self.use_relative_line_numbers = is_relative;
18566        cx.notify();
18567    }
18568
18569    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
18570        self.show_gutter = show_gutter;
18571        cx.notify();
18572    }
18573
18574    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
18575        self.show_scrollbars = ScrollbarAxes {
18576            horizontal: show,
18577            vertical: show,
18578        };
18579        cx.notify();
18580    }
18581
18582    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18583        self.show_scrollbars.vertical = show;
18584        cx.notify();
18585    }
18586
18587    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
18588        self.show_scrollbars.horizontal = show;
18589        cx.notify();
18590    }
18591
18592    pub fn set_minimap_visibility(
18593        &mut self,
18594        minimap_visibility: MinimapVisibility,
18595        window: &mut Window,
18596        cx: &mut Context<Self>,
18597    ) {
18598        if self.minimap_visibility != minimap_visibility {
18599            if minimap_visibility.visible() && self.minimap.is_none() {
18600                let minimap_settings = EditorSettings::get_global(cx).minimap;
18601                self.minimap =
18602                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
18603            }
18604            self.minimap_visibility = minimap_visibility;
18605            cx.notify();
18606        }
18607    }
18608
18609    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18610        self.set_show_scrollbars(false, cx);
18611        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
18612    }
18613
18614    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
18615        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
18616    }
18617
18618    /// Normally the text in full mode and auto height editors is padded on the
18619    /// left side by roughly half a character width for improved hit testing.
18620    ///
18621    /// Use this method to disable this for cases where this is not wanted (e.g.
18622    /// if you want to align the editor text with some other text above or below)
18623    /// or if you want to add this padding to single-line editors.
18624    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
18625        self.offset_content = offset_content;
18626        cx.notify();
18627    }
18628
18629    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
18630        self.show_line_numbers = Some(show_line_numbers);
18631        cx.notify();
18632    }
18633
18634    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
18635        self.disable_expand_excerpt_buttons = true;
18636        cx.notify();
18637    }
18638
18639    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
18640        self.show_git_diff_gutter = Some(show_git_diff_gutter);
18641        cx.notify();
18642    }
18643
18644    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
18645        self.show_code_actions = Some(show_code_actions);
18646        cx.notify();
18647    }
18648
18649    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
18650        self.show_runnables = Some(show_runnables);
18651        cx.notify();
18652    }
18653
18654    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
18655        self.show_breakpoints = Some(show_breakpoints);
18656        cx.notify();
18657    }
18658
18659    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
18660        if self.display_map.read(cx).masked != masked {
18661            self.display_map.update(cx, |map, _| map.masked = masked);
18662        }
18663        cx.notify()
18664    }
18665
18666    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
18667        self.show_wrap_guides = Some(show_wrap_guides);
18668        cx.notify();
18669    }
18670
18671    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
18672        self.show_indent_guides = Some(show_indent_guides);
18673        cx.notify();
18674    }
18675
18676    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
18677        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
18678            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
18679                && let Some(dir) = file.abs_path(cx).parent()
18680            {
18681                return Some(dir.to_owned());
18682            }
18683
18684            if let Some(project_path) = buffer.read(cx).project_path(cx) {
18685                return Some(project_path.path.to_path_buf());
18686            }
18687        }
18688
18689        None
18690    }
18691
18692    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
18693        self.active_excerpt(cx)?
18694            .1
18695            .read(cx)
18696            .file()
18697            .and_then(|f| f.as_local())
18698    }
18699
18700    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18701        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18702            let buffer = buffer.read(cx);
18703            if let Some(project_path) = buffer.project_path(cx) {
18704                let project = self.project()?.read(cx);
18705                project.absolute_path(&project_path, cx)
18706            } else {
18707                buffer
18708                    .file()
18709                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
18710            }
18711        })
18712    }
18713
18714    fn target_file_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
18715        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
18716            let project_path = buffer.read(cx).project_path(cx)?;
18717            let project = self.project()?.read(cx);
18718            let entry = project.entry_for_path(&project_path, cx)?;
18719            let path = entry.path.to_path_buf();
18720            Some(path)
18721        })
18722    }
18723
18724    pub fn reveal_in_finder(
18725        &mut self,
18726        _: &RevealInFileManager,
18727        _window: &mut Window,
18728        cx: &mut Context<Self>,
18729    ) {
18730        if let Some(target) = self.target_file(cx) {
18731            cx.reveal_path(&target.abs_path(cx));
18732        }
18733    }
18734
18735    pub fn copy_path(
18736        &mut self,
18737        _: &zed_actions::workspace::CopyPath,
18738        _window: &mut Window,
18739        cx: &mut Context<Self>,
18740    ) {
18741        if let Some(path) = self.target_file_abs_path(cx)
18742            && let Some(path) = path.to_str()
18743        {
18744            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18745        }
18746    }
18747
18748    pub fn copy_relative_path(
18749        &mut self,
18750        _: &zed_actions::workspace::CopyRelativePath,
18751        _window: &mut Window,
18752        cx: &mut Context<Self>,
18753    ) {
18754        if let Some(path) = self.target_file_path(cx)
18755            && let Some(path) = path.to_str()
18756        {
18757            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
18758        }
18759    }
18760
18761    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
18762        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
18763            buffer.read(cx).project_path(cx)
18764        } else {
18765            None
18766        }
18767    }
18768
18769    // Returns true if the editor handled a go-to-line request
18770    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
18771        maybe!({
18772            let breakpoint_store = self.breakpoint_store.as_ref()?;
18773
18774            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
18775            else {
18776                self.clear_row_highlights::<ActiveDebugLine>();
18777                return None;
18778            };
18779
18780            let position = active_stack_frame.position;
18781            let buffer_id = position.buffer_id?;
18782            let snapshot = self
18783                .project
18784                .as_ref()?
18785                .read(cx)
18786                .buffer_for_id(buffer_id, cx)?
18787                .read(cx)
18788                .snapshot();
18789
18790            let mut handled = false;
18791            for (id, ExcerptRange { context, .. }) in
18792                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
18793            {
18794                if context.start.cmp(&position, &snapshot).is_ge()
18795                    || context.end.cmp(&position, &snapshot).is_lt()
18796                {
18797                    continue;
18798                }
18799                let snapshot = self.buffer.read(cx).snapshot(cx);
18800                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
18801
18802                handled = true;
18803                self.clear_row_highlights::<ActiveDebugLine>();
18804
18805                self.go_to_line::<ActiveDebugLine>(
18806                    multibuffer_anchor,
18807                    Some(cx.theme().colors().editor_debugger_active_line_background),
18808                    window,
18809                    cx,
18810                );
18811
18812                cx.notify();
18813            }
18814
18815            handled.then_some(())
18816        })
18817        .is_some()
18818    }
18819
18820    pub fn copy_file_name_without_extension(
18821        &mut self,
18822        _: &CopyFileNameWithoutExtension,
18823        _: &mut Window,
18824        cx: &mut Context<Self>,
18825    ) {
18826        if let Some(file) = self.target_file(cx)
18827            && let Some(file_stem) = file.path().file_stem()
18828            && let Some(name) = file_stem.to_str()
18829        {
18830            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18831        }
18832    }
18833
18834    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
18835        if let Some(file) = self.target_file(cx)
18836            && let Some(file_name) = file.path().file_name()
18837            && let Some(name) = file_name.to_str()
18838        {
18839            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
18840        }
18841    }
18842
18843    pub fn toggle_git_blame(
18844        &mut self,
18845        _: &::git::Blame,
18846        window: &mut Window,
18847        cx: &mut Context<Self>,
18848    ) {
18849        self.show_git_blame_gutter = !self.show_git_blame_gutter;
18850
18851        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
18852            self.start_git_blame(true, window, cx);
18853        }
18854
18855        cx.notify();
18856    }
18857
18858    pub fn toggle_git_blame_inline(
18859        &mut self,
18860        _: &ToggleGitBlameInline,
18861        window: &mut Window,
18862        cx: &mut Context<Self>,
18863    ) {
18864        self.toggle_git_blame_inline_internal(true, window, cx);
18865        cx.notify();
18866    }
18867
18868    pub fn open_git_blame_commit(
18869        &mut self,
18870        _: &OpenGitBlameCommit,
18871        window: &mut Window,
18872        cx: &mut Context<Self>,
18873    ) {
18874        self.open_git_blame_commit_internal(window, cx);
18875    }
18876
18877    fn open_git_blame_commit_internal(
18878        &mut self,
18879        window: &mut Window,
18880        cx: &mut Context<Self>,
18881    ) -> Option<()> {
18882        let blame = self.blame.as_ref()?;
18883        let snapshot = self.snapshot(window, cx);
18884        let cursor = self.selections.newest::<Point>(cx).head();
18885        let (buffer, point, _) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)?;
18886        let blame_entry = blame
18887            .update(cx, |blame, cx| {
18888                blame
18889                    .blame_for_rows(
18890                        &[RowInfo {
18891                            buffer_id: Some(buffer.remote_id()),
18892                            buffer_row: Some(point.row),
18893                            ..Default::default()
18894                        }],
18895                        cx,
18896                    )
18897                    .next()
18898            })
18899            .flatten()?;
18900        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
18901        let repo = blame.read(cx).repository(cx)?;
18902        let workspace = self.workspace()?.downgrade();
18903        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
18904        None
18905    }
18906
18907    pub fn git_blame_inline_enabled(&self) -> bool {
18908        self.git_blame_inline_enabled
18909    }
18910
18911    pub fn toggle_selection_menu(
18912        &mut self,
18913        _: &ToggleSelectionMenu,
18914        _: &mut Window,
18915        cx: &mut Context<Self>,
18916    ) {
18917        self.show_selection_menu = self
18918            .show_selection_menu
18919            .map(|show_selections_menu| !show_selections_menu)
18920            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
18921
18922        cx.notify();
18923    }
18924
18925    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
18926        self.show_selection_menu
18927            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
18928    }
18929
18930    fn start_git_blame(
18931        &mut self,
18932        user_triggered: bool,
18933        window: &mut Window,
18934        cx: &mut Context<Self>,
18935    ) {
18936        if let Some(project) = self.project() {
18937            let Some(buffer) = self.buffer().read(cx).as_singleton() else {
18938                return;
18939            };
18940
18941            if buffer.read(cx).file().is_none() {
18942                return;
18943            }
18944
18945            let focused = self.focus_handle(cx).contains_focused(window, cx);
18946
18947            let project = project.clone();
18948            let blame = cx.new(|cx| GitBlame::new(buffer, project, user_triggered, focused, cx));
18949            self.blame_subscription =
18950                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
18951            self.blame = Some(blame);
18952        }
18953    }
18954
18955    fn toggle_git_blame_inline_internal(
18956        &mut self,
18957        user_triggered: bool,
18958        window: &mut Window,
18959        cx: &mut Context<Self>,
18960    ) {
18961        if self.git_blame_inline_enabled {
18962            self.git_blame_inline_enabled = false;
18963            self.show_git_blame_inline = false;
18964            self.show_git_blame_inline_delay_task.take();
18965        } else {
18966            self.git_blame_inline_enabled = true;
18967            self.start_git_blame_inline(user_triggered, window, cx);
18968        }
18969
18970        cx.notify();
18971    }
18972
18973    fn start_git_blame_inline(
18974        &mut self,
18975        user_triggered: bool,
18976        window: &mut Window,
18977        cx: &mut Context<Self>,
18978    ) {
18979        self.start_git_blame(user_triggered, window, cx);
18980
18981        if ProjectSettings::get_global(cx)
18982            .git
18983            .inline_blame_delay()
18984            .is_some()
18985        {
18986            self.start_inline_blame_timer(window, cx);
18987        } else {
18988            self.show_git_blame_inline = true
18989        }
18990    }
18991
18992    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
18993        self.blame.as_ref()
18994    }
18995
18996    pub fn show_git_blame_gutter(&self) -> bool {
18997        self.show_git_blame_gutter
18998    }
18999
19000    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19001        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19002    }
19003
19004    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19005        self.show_git_blame_inline
19006            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19007            && !self.newest_selection_head_on_empty_line(cx)
19008            && self.has_blame_entries(cx)
19009    }
19010
19011    fn has_blame_entries(&self, cx: &App) -> bool {
19012        self.blame()
19013            .map_or(false, |blame| blame.read(cx).has_generated_entries())
19014    }
19015
19016    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
19017        let cursor_anchor = self.selections.newest_anchor().head();
19018
19019        let snapshot = self.buffer.read(cx).snapshot(cx);
19020        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
19021
19022        snapshot.line_len(buffer_row) == 0
19023    }
19024
19025    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
19026        let buffer_and_selection = maybe!({
19027            let selection = self.selections.newest::<Point>(cx);
19028            let selection_range = selection.range();
19029
19030            let multi_buffer = self.buffer().read(cx);
19031            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19032            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
19033
19034            let (buffer, range, _) = if selection.reversed {
19035                buffer_ranges.first()
19036            } else {
19037                buffer_ranges.last()
19038            }?;
19039
19040            let selection = text::ToPoint::to_point(&range.start, buffer).row
19041                ..text::ToPoint::to_point(&range.end, buffer).row;
19042            Some((
19043                multi_buffer.buffer(buffer.remote_id()).unwrap().clone(),
19044                selection,
19045            ))
19046        });
19047
19048        let Some((buffer, selection)) = buffer_and_selection else {
19049            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
19050        };
19051
19052        let Some(project) = self.project() else {
19053            return Task::ready(Err(anyhow!("editor does not have project")));
19054        };
19055
19056        project.update(cx, |project, cx| {
19057            project.get_permalink_to_line(&buffer, selection, cx)
19058        })
19059    }
19060
19061    pub fn copy_permalink_to_line(
19062        &mut self,
19063        _: &CopyPermalinkToLine,
19064        window: &mut Window,
19065        cx: &mut Context<Self>,
19066    ) {
19067        let permalink_task = self.get_permalink_to_line(cx);
19068        let workspace = self.workspace();
19069
19070        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19071            Ok(permalink) => {
19072                cx.update(|_, cx| {
19073                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
19074                })
19075                .ok();
19076            }
19077            Err(err) => {
19078                let message = format!("Failed to copy permalink: {err}");
19079
19080                anyhow::Result::<()>::Err(err).log_err();
19081
19082                if let Some(workspace) = workspace {
19083                    workspace
19084                        .update_in(cx, |workspace, _, cx| {
19085                            struct CopyPermalinkToLine;
19086
19087                            workspace.show_toast(
19088                                Toast::new(
19089                                    NotificationId::unique::<CopyPermalinkToLine>(),
19090                                    message,
19091                                ),
19092                                cx,
19093                            )
19094                        })
19095                        .ok();
19096                }
19097            }
19098        })
19099        .detach();
19100    }
19101
19102    pub fn copy_file_location(
19103        &mut self,
19104        _: &CopyFileLocation,
19105        _: &mut Window,
19106        cx: &mut Context<Self>,
19107    ) {
19108        let selection = self.selections.newest::<Point>(cx).start.row + 1;
19109        if let Some(file) = self.target_file(cx)
19110            && let Some(path) = file.path().to_str()
19111        {
19112            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
19113        }
19114    }
19115
19116    pub fn open_permalink_to_line(
19117        &mut self,
19118        _: &OpenPermalinkToLine,
19119        window: &mut Window,
19120        cx: &mut Context<Self>,
19121    ) {
19122        let permalink_task = self.get_permalink_to_line(cx);
19123        let workspace = self.workspace();
19124
19125        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
19126            Ok(permalink) => {
19127                cx.update(|_, cx| {
19128                    cx.open_url(permalink.as_ref());
19129                })
19130                .ok();
19131            }
19132            Err(err) => {
19133                let message = format!("Failed to open permalink: {err}");
19134
19135                anyhow::Result::<()>::Err(err).log_err();
19136
19137                if let Some(workspace) = workspace {
19138                    workspace
19139                        .update(cx, |workspace, cx| {
19140                            struct OpenPermalinkToLine;
19141
19142                            workspace.show_toast(
19143                                Toast::new(
19144                                    NotificationId::unique::<OpenPermalinkToLine>(),
19145                                    message,
19146                                ),
19147                                cx,
19148                            )
19149                        })
19150                        .ok();
19151                }
19152            }
19153        })
19154        .detach();
19155    }
19156
19157    pub fn insert_uuid_v4(
19158        &mut self,
19159        _: &InsertUuidV4,
19160        window: &mut Window,
19161        cx: &mut Context<Self>,
19162    ) {
19163        self.insert_uuid(UuidVersion::V4, window, cx);
19164    }
19165
19166    pub fn insert_uuid_v7(
19167        &mut self,
19168        _: &InsertUuidV7,
19169        window: &mut Window,
19170        cx: &mut Context<Self>,
19171    ) {
19172        self.insert_uuid(UuidVersion::V7, window, cx);
19173    }
19174
19175    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
19176        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19177        self.transact(window, cx, |this, window, cx| {
19178            let edits = this
19179                .selections
19180                .all::<Point>(cx)
19181                .into_iter()
19182                .map(|selection| {
19183                    let uuid = match version {
19184                        UuidVersion::V4 => uuid::Uuid::new_v4(),
19185                        UuidVersion::V7 => uuid::Uuid::now_v7(),
19186                    };
19187
19188                    (selection.range(), uuid.to_string())
19189                });
19190            this.edit(edits, cx);
19191            this.refresh_edit_prediction(true, false, window, cx);
19192        });
19193    }
19194
19195    pub fn open_selections_in_multibuffer(
19196        &mut self,
19197        _: &OpenSelectionsInMultibuffer,
19198        window: &mut Window,
19199        cx: &mut Context<Self>,
19200    ) {
19201        let multibuffer = self.buffer.read(cx);
19202
19203        let Some(buffer) = multibuffer.as_singleton() else {
19204            return;
19205        };
19206
19207        let Some(workspace) = self.workspace() else {
19208            return;
19209        };
19210
19211        let title = multibuffer.title(cx).to_string();
19212
19213        let locations = self
19214            .selections
19215            .all_anchors(cx)
19216            .into_iter()
19217            .map(|selection| Location {
19218                buffer: buffer.clone(),
19219                range: selection.start.text_anchor..selection.end.text_anchor,
19220            })
19221            .collect::<Vec<_>>();
19222
19223        cx.spawn_in(window, async move |_, cx| {
19224            workspace.update_in(cx, |workspace, window, cx| {
19225                Self::open_locations_in_multibuffer(
19226                    workspace,
19227                    locations,
19228                    format!("Selections for '{title}'"),
19229                    false,
19230                    MultibufferSelectionMode::All,
19231                    window,
19232                    cx,
19233                );
19234            })
19235        })
19236        .detach();
19237    }
19238
19239    /// Adds a row highlight for the given range. If a row has multiple highlights, the
19240    /// last highlight added will be used.
19241    ///
19242    /// If the range ends at the beginning of a line, then that line will not be highlighted.
19243    pub fn highlight_rows<T: 'static>(
19244        &mut self,
19245        range: Range<Anchor>,
19246        color: Hsla,
19247        options: RowHighlightOptions,
19248        cx: &mut Context<Self>,
19249    ) {
19250        let snapshot = self.buffer().read(cx).snapshot(cx);
19251        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19252        let ix = row_highlights.binary_search_by(|highlight| {
19253            Ordering::Equal
19254                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
19255                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
19256        });
19257
19258        if let Err(mut ix) = ix {
19259            let index = post_inc(&mut self.highlight_order);
19260
19261            // If this range intersects with the preceding highlight, then merge it with
19262            // the preceding highlight. Otherwise insert a new highlight.
19263            let mut merged = false;
19264            if ix > 0 {
19265                let prev_highlight = &mut row_highlights[ix - 1];
19266                if prev_highlight
19267                    .range
19268                    .end
19269                    .cmp(&range.start, &snapshot)
19270                    .is_ge()
19271                {
19272                    ix -= 1;
19273                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
19274                        prev_highlight.range.end = range.end;
19275                    }
19276                    merged = true;
19277                    prev_highlight.index = index;
19278                    prev_highlight.color = color;
19279                    prev_highlight.options = options;
19280                }
19281            }
19282
19283            if !merged {
19284                row_highlights.insert(
19285                    ix,
19286                    RowHighlight {
19287                        range: range.clone(),
19288                        index,
19289                        color,
19290                        options,
19291                        type_id: TypeId::of::<T>(),
19292                    },
19293                );
19294            }
19295
19296            // If any of the following highlights intersect with this one, merge them.
19297            while let Some(next_highlight) = row_highlights.get(ix + 1) {
19298                let highlight = &row_highlights[ix];
19299                if next_highlight
19300                    .range
19301                    .start
19302                    .cmp(&highlight.range.end, &snapshot)
19303                    .is_le()
19304                {
19305                    if next_highlight
19306                        .range
19307                        .end
19308                        .cmp(&highlight.range.end, &snapshot)
19309                        .is_gt()
19310                    {
19311                        row_highlights[ix].range.end = next_highlight.range.end;
19312                    }
19313                    row_highlights.remove(ix + 1);
19314                } else {
19315                    break;
19316                }
19317            }
19318        }
19319    }
19320
19321    /// Remove any highlighted row ranges of the given type that intersect the
19322    /// given ranges.
19323    pub fn remove_highlighted_rows<T: 'static>(
19324        &mut self,
19325        ranges_to_remove: Vec<Range<Anchor>>,
19326        cx: &mut Context<Self>,
19327    ) {
19328        let snapshot = self.buffer().read(cx).snapshot(cx);
19329        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
19330        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19331        row_highlights.retain(|highlight| {
19332            while let Some(range_to_remove) = ranges_to_remove.peek() {
19333                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
19334                    Ordering::Less | Ordering::Equal => {
19335                        ranges_to_remove.next();
19336                    }
19337                    Ordering::Greater => {
19338                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
19339                            Ordering::Less | Ordering::Equal => {
19340                                return false;
19341                            }
19342                            Ordering::Greater => break,
19343                        }
19344                    }
19345                }
19346            }
19347
19348            true
19349        })
19350    }
19351
19352    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
19353    pub fn clear_row_highlights<T: 'static>(&mut self) {
19354        self.highlighted_rows.remove(&TypeId::of::<T>());
19355    }
19356
19357    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
19358    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
19359        self.highlighted_rows
19360            .get(&TypeId::of::<T>())
19361            .map_or(&[] as &[_], |vec| vec.as_slice())
19362            .iter()
19363            .map(|highlight| (highlight.range.clone(), highlight.color))
19364    }
19365
19366    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
19367    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
19368    /// Allows to ignore certain kinds of highlights.
19369    pub fn highlighted_display_rows(
19370        &self,
19371        window: &mut Window,
19372        cx: &mut App,
19373    ) -> BTreeMap<DisplayRow, LineHighlight> {
19374        let snapshot = self.snapshot(window, cx);
19375        let mut used_highlight_orders = HashMap::default();
19376        self.highlighted_rows
19377            .iter()
19378            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
19379            .fold(
19380                BTreeMap::<DisplayRow, LineHighlight>::new(),
19381                |mut unique_rows, highlight| {
19382                    let start = highlight.range.start.to_display_point(&snapshot);
19383                    let end = highlight.range.end.to_display_point(&snapshot);
19384                    let start_row = start.row().0;
19385                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
19386                        && end.column() == 0
19387                    {
19388                        end.row().0.saturating_sub(1)
19389                    } else {
19390                        end.row().0
19391                    };
19392                    for row in start_row..=end_row {
19393                        let used_index =
19394                            used_highlight_orders.entry(row).or_insert(highlight.index);
19395                        if highlight.index >= *used_index {
19396                            *used_index = highlight.index;
19397                            unique_rows.insert(
19398                                DisplayRow(row),
19399                                LineHighlight {
19400                                    include_gutter: highlight.options.include_gutter,
19401                                    border: None,
19402                                    background: highlight.color.into(),
19403                                    type_id: Some(highlight.type_id),
19404                                },
19405                            );
19406                        }
19407                    }
19408                    unique_rows
19409                },
19410            )
19411    }
19412
19413    pub fn highlighted_display_row_for_autoscroll(
19414        &self,
19415        snapshot: &DisplaySnapshot,
19416    ) -> Option<DisplayRow> {
19417        self.highlighted_rows
19418            .values()
19419            .flat_map(|highlighted_rows| highlighted_rows.iter())
19420            .filter_map(|highlight| {
19421                if highlight.options.autoscroll {
19422                    Some(highlight.range.start.to_display_point(snapshot).row())
19423                } else {
19424                    None
19425                }
19426            })
19427            .min()
19428    }
19429
19430    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
19431        self.highlight_background::<SearchWithinRange>(
19432            ranges,
19433            |colors| colors.colors().editor_document_highlight_read_background,
19434            cx,
19435        )
19436    }
19437
19438    pub fn set_breadcrumb_header(&mut self, new_header: String) {
19439        self.breadcrumb_header = Some(new_header);
19440    }
19441
19442    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
19443        self.clear_background_highlights::<SearchWithinRange>(cx);
19444    }
19445
19446    pub fn highlight_background<T: 'static>(
19447        &mut self,
19448        ranges: &[Range<Anchor>],
19449        color_fetcher: fn(&Theme) -> Hsla,
19450        cx: &mut Context<Self>,
19451    ) {
19452        self.background_highlights.insert(
19453            HighlightKey::Type(TypeId::of::<T>()),
19454            (color_fetcher, Arc::from(ranges)),
19455        );
19456        self.scrollbar_marker_state.dirty = true;
19457        cx.notify();
19458    }
19459
19460    pub fn highlight_background_key<T: 'static>(
19461        &mut self,
19462        key: usize,
19463        ranges: &[Range<Anchor>],
19464        color_fetcher: fn(&Theme) -> Hsla,
19465        cx: &mut Context<Self>,
19466    ) {
19467        self.background_highlights.insert(
19468            HighlightKey::TypePlus(TypeId::of::<T>(), key),
19469            (color_fetcher, Arc::from(ranges)),
19470        );
19471        self.scrollbar_marker_state.dirty = true;
19472        cx.notify();
19473    }
19474
19475    pub fn clear_background_highlights<T: 'static>(
19476        &mut self,
19477        cx: &mut Context<Self>,
19478    ) -> Option<BackgroundHighlight> {
19479        let text_highlights = self
19480            .background_highlights
19481            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
19482        if !text_highlights.1.is_empty() {
19483            self.scrollbar_marker_state.dirty = true;
19484            cx.notify();
19485        }
19486        Some(text_highlights)
19487    }
19488
19489    pub fn highlight_gutter<T: 'static>(
19490        &mut self,
19491        ranges: impl Into<Vec<Range<Anchor>>>,
19492        color_fetcher: fn(&App) -> Hsla,
19493        cx: &mut Context<Self>,
19494    ) {
19495        self.gutter_highlights
19496            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
19497        cx.notify();
19498    }
19499
19500    pub fn clear_gutter_highlights<T: 'static>(
19501        &mut self,
19502        cx: &mut Context<Self>,
19503    ) -> Option<GutterHighlight> {
19504        cx.notify();
19505        self.gutter_highlights.remove(&TypeId::of::<T>())
19506    }
19507
19508    pub fn insert_gutter_highlight<T: 'static>(
19509        &mut self,
19510        range: Range<Anchor>,
19511        color_fetcher: fn(&App) -> Hsla,
19512        cx: &mut Context<Self>,
19513    ) {
19514        let snapshot = self.buffer().read(cx).snapshot(cx);
19515        let mut highlights = self
19516            .gutter_highlights
19517            .remove(&TypeId::of::<T>())
19518            .map(|(_, highlights)| highlights)
19519            .unwrap_or_default();
19520        let ix = highlights.binary_search_by(|highlight| {
19521            Ordering::Equal
19522                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
19523                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
19524        });
19525        if let Err(ix) = ix {
19526            highlights.insert(ix, range);
19527        }
19528        self.gutter_highlights
19529            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
19530    }
19531
19532    pub fn remove_gutter_highlights<T: 'static>(
19533        &mut self,
19534        ranges_to_remove: Vec<Range<Anchor>>,
19535        cx: &mut Context<Self>,
19536    ) {
19537        let snapshot = self.buffer().read(cx).snapshot(cx);
19538        let Some((color_fetcher, mut gutter_highlights)) =
19539            self.gutter_highlights.remove(&TypeId::of::<T>())
19540        else {
19541            return;
19542        };
19543        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
19544        gutter_highlights.retain(|highlight| {
19545            while let Some(range_to_remove) = ranges_to_remove.peek() {
19546                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
19547                    Ordering::Less | Ordering::Equal => {
19548                        ranges_to_remove.next();
19549                    }
19550                    Ordering::Greater => {
19551                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
19552                            Ordering::Less | Ordering::Equal => {
19553                                return false;
19554                            }
19555                            Ordering::Greater => break,
19556                        }
19557                    }
19558                }
19559            }
19560
19561            true
19562        });
19563        self.gutter_highlights
19564            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
19565    }
19566
19567    #[cfg(feature = "test-support")]
19568    pub fn all_text_highlights(
19569        &self,
19570        window: &mut Window,
19571        cx: &mut Context<Self>,
19572    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
19573        let snapshot = self.snapshot(window, cx);
19574        self.display_map.update(cx, |display_map, _| {
19575            display_map
19576                .all_text_highlights()
19577                .map(|highlight| {
19578                    let (style, ranges) = highlight.as_ref();
19579                    (
19580                        *style,
19581                        ranges
19582                            .iter()
19583                            .map(|range| range.clone().to_display_points(&snapshot))
19584                            .collect(),
19585                    )
19586                })
19587                .collect()
19588        })
19589    }
19590
19591    #[cfg(feature = "test-support")]
19592    pub fn all_text_background_highlights(
19593        &self,
19594        window: &mut Window,
19595        cx: &mut Context<Self>,
19596    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19597        let snapshot = self.snapshot(window, cx);
19598        let buffer = &snapshot.buffer_snapshot;
19599        let start = buffer.anchor_before(0);
19600        let end = buffer.anchor_after(buffer.len());
19601        self.background_highlights_in_range(start..end, &snapshot, cx.theme())
19602    }
19603
19604    #[cfg(feature = "test-support")]
19605    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
19606        let snapshot = self.buffer().read(cx).snapshot(cx);
19607
19608        let highlights = self
19609            .background_highlights
19610            .get(&HighlightKey::Type(TypeId::of::<
19611                items::BufferSearchHighlights,
19612            >()));
19613
19614        if let Some((_color, ranges)) = highlights {
19615            ranges
19616                .iter()
19617                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
19618                .collect_vec()
19619        } else {
19620            vec![]
19621        }
19622    }
19623
19624    fn document_highlights_for_position<'a>(
19625        &'a self,
19626        position: Anchor,
19627        buffer: &'a MultiBufferSnapshot,
19628    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
19629        let read_highlights = self
19630            .background_highlights
19631            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
19632            .map(|h| &h.1);
19633        let write_highlights = self
19634            .background_highlights
19635            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
19636            .map(|h| &h.1);
19637        let left_position = position.bias_left(buffer);
19638        let right_position = position.bias_right(buffer);
19639        read_highlights
19640            .into_iter()
19641            .chain(write_highlights)
19642            .flat_map(move |ranges| {
19643                let start_ix = match ranges.binary_search_by(|probe| {
19644                    let cmp = probe.end.cmp(&left_position, buffer);
19645                    if cmp.is_ge() {
19646                        Ordering::Greater
19647                    } else {
19648                        Ordering::Less
19649                    }
19650                }) {
19651                    Ok(i) | Err(i) => i,
19652                };
19653
19654                ranges[start_ix..]
19655                    .iter()
19656                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
19657            })
19658    }
19659
19660    pub fn has_background_highlights<T: 'static>(&self) -> bool {
19661        self.background_highlights
19662            .get(&HighlightKey::Type(TypeId::of::<T>()))
19663            .map_or(false, |(_, highlights)| !highlights.is_empty())
19664    }
19665
19666    pub fn background_highlights_in_range(
19667        &self,
19668        search_range: Range<Anchor>,
19669        display_snapshot: &DisplaySnapshot,
19670        theme: &Theme,
19671    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19672        let mut results = Vec::new();
19673        for (color_fetcher, ranges) in self.background_highlights.values() {
19674            let color = color_fetcher(theme);
19675            let start_ix = match ranges.binary_search_by(|probe| {
19676                let cmp = probe
19677                    .end
19678                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19679                if cmp.is_gt() {
19680                    Ordering::Greater
19681                } else {
19682                    Ordering::Less
19683                }
19684            }) {
19685                Ok(i) | Err(i) => i,
19686            };
19687            for range in &ranges[start_ix..] {
19688                if range
19689                    .start
19690                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19691                    .is_ge()
19692                {
19693                    break;
19694                }
19695
19696                let start = range.start.to_display_point(display_snapshot);
19697                let end = range.end.to_display_point(display_snapshot);
19698                results.push((start..end, color))
19699            }
19700        }
19701        results
19702    }
19703
19704    pub fn background_highlight_row_ranges<T: 'static>(
19705        &self,
19706        search_range: Range<Anchor>,
19707        display_snapshot: &DisplaySnapshot,
19708        count: usize,
19709    ) -> Vec<RangeInclusive<DisplayPoint>> {
19710        let mut results = Vec::new();
19711        let Some((_, ranges)) = self
19712            .background_highlights
19713            .get(&HighlightKey::Type(TypeId::of::<T>()))
19714        else {
19715            return vec![];
19716        };
19717
19718        let start_ix = match ranges.binary_search_by(|probe| {
19719            let cmp = probe
19720                .end
19721                .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19722            if cmp.is_gt() {
19723                Ordering::Greater
19724            } else {
19725                Ordering::Less
19726            }
19727        }) {
19728            Ok(i) | Err(i) => i,
19729        };
19730        let mut push_region = |start: Option<Point>, end: Option<Point>| {
19731            if let (Some(start_display), Some(end_display)) = (start, end) {
19732                results.push(
19733                    start_display.to_display_point(display_snapshot)
19734                        ..=end_display.to_display_point(display_snapshot),
19735                );
19736            }
19737        };
19738        let mut start_row: Option<Point> = None;
19739        let mut end_row: Option<Point> = None;
19740        if ranges.len() > count {
19741            return Vec::new();
19742        }
19743        for range in &ranges[start_ix..] {
19744            if range
19745                .start
19746                .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19747                .is_ge()
19748            {
19749                break;
19750            }
19751            let end = range.end.to_point(&display_snapshot.buffer_snapshot);
19752            if let Some(current_row) = &end_row
19753                && end.row == current_row.row
19754            {
19755                continue;
19756            }
19757            let start = range.start.to_point(&display_snapshot.buffer_snapshot);
19758            if start_row.is_none() {
19759                assert_eq!(end_row, None);
19760                start_row = Some(start);
19761                end_row = Some(end);
19762                continue;
19763            }
19764            if let Some(current_end) = end_row.as_mut() {
19765                if start.row > current_end.row + 1 {
19766                    push_region(start_row, end_row);
19767                    start_row = Some(start);
19768                    end_row = Some(end);
19769                } else {
19770                    // Merge two hunks.
19771                    *current_end = end;
19772                }
19773            } else {
19774                unreachable!();
19775            }
19776        }
19777        // We might still have a hunk that was not rendered (if there was a search hit on the last line)
19778        push_region(start_row, end_row);
19779        results
19780    }
19781
19782    pub fn gutter_highlights_in_range(
19783        &self,
19784        search_range: Range<Anchor>,
19785        display_snapshot: &DisplaySnapshot,
19786        cx: &App,
19787    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
19788        let mut results = Vec::new();
19789        for (color_fetcher, ranges) in self.gutter_highlights.values() {
19790            let color = color_fetcher(cx);
19791            let start_ix = match ranges.binary_search_by(|probe| {
19792                let cmp = probe
19793                    .end
19794                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot);
19795                if cmp.is_gt() {
19796                    Ordering::Greater
19797                } else {
19798                    Ordering::Less
19799                }
19800            }) {
19801                Ok(i) | Err(i) => i,
19802            };
19803            for range in &ranges[start_ix..] {
19804                if range
19805                    .start
19806                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot)
19807                    .is_ge()
19808                {
19809                    break;
19810                }
19811
19812                let start = range.start.to_display_point(display_snapshot);
19813                let end = range.end.to_display_point(display_snapshot);
19814                results.push((start..end, color))
19815            }
19816        }
19817        results
19818    }
19819
19820    /// Get the text ranges corresponding to the redaction query
19821    pub fn redacted_ranges(
19822        &self,
19823        search_range: Range<Anchor>,
19824        display_snapshot: &DisplaySnapshot,
19825        cx: &App,
19826    ) -> Vec<Range<DisplayPoint>> {
19827        display_snapshot
19828            .buffer_snapshot
19829            .redacted_ranges(search_range, |file| {
19830                if let Some(file) = file {
19831                    file.is_private()
19832                        && EditorSettings::get(
19833                            Some(SettingsLocation {
19834                                worktree_id: file.worktree_id(cx),
19835                                path: file.path().as_ref(),
19836                            }),
19837                            cx,
19838                        )
19839                        .redact_private_values
19840                } else {
19841                    false
19842                }
19843            })
19844            .map(|range| {
19845                range.start.to_display_point(display_snapshot)
19846                    ..range.end.to_display_point(display_snapshot)
19847            })
19848            .collect()
19849    }
19850
19851    pub fn highlight_text_key<T: 'static>(
19852        &mut self,
19853        key: usize,
19854        ranges: Vec<Range<Anchor>>,
19855        style: HighlightStyle,
19856        cx: &mut Context<Self>,
19857    ) {
19858        self.display_map.update(cx, |map, _| {
19859            map.highlight_text(
19860                HighlightKey::TypePlus(TypeId::of::<T>(), key),
19861                ranges,
19862                style,
19863            );
19864        });
19865        cx.notify();
19866    }
19867
19868    pub fn highlight_text<T: 'static>(
19869        &mut self,
19870        ranges: Vec<Range<Anchor>>,
19871        style: HighlightStyle,
19872        cx: &mut Context<Self>,
19873    ) {
19874        self.display_map.update(cx, |map, _| {
19875            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
19876        });
19877        cx.notify();
19878    }
19879
19880    pub(crate) fn highlight_inlays<T: 'static>(
19881        &mut self,
19882        highlights: Vec<InlayHighlight>,
19883        style: HighlightStyle,
19884        cx: &mut Context<Self>,
19885    ) {
19886        self.display_map.update(cx, |map, _| {
19887            map.highlight_inlays(TypeId::of::<T>(), highlights, style)
19888        });
19889        cx.notify();
19890    }
19891
19892    pub fn text_highlights<'a, T: 'static>(
19893        &'a self,
19894        cx: &'a App,
19895    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
19896        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
19897    }
19898
19899    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
19900        let cleared = self
19901            .display_map
19902            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
19903        if cleared {
19904            cx.notify();
19905        }
19906    }
19907
19908    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
19909        (self.read_only(cx) || self.blink_manager.read(cx).visible())
19910            && self.focus_handle.is_focused(window)
19911    }
19912
19913    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
19914        self.show_cursor_when_unfocused = is_enabled;
19915        cx.notify();
19916    }
19917
19918    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
19919        cx.notify();
19920    }
19921
19922    fn on_debug_session_event(
19923        &mut self,
19924        _session: Entity<Session>,
19925        event: &SessionEvent,
19926        cx: &mut Context<Self>,
19927    ) {
19928        match event {
19929            SessionEvent::InvalidateInlineValue => {
19930                self.refresh_inline_values(cx);
19931            }
19932            _ => {}
19933        }
19934    }
19935
19936    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
19937        let Some(project) = self.project.clone() else {
19938            return;
19939        };
19940
19941        if !self.inline_value_cache.enabled {
19942            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
19943            self.splice_inlays(&inlays, Vec::new(), cx);
19944            return;
19945        }
19946
19947        let current_execution_position = self
19948            .highlighted_rows
19949            .get(&TypeId::of::<ActiveDebugLine>())
19950            .and_then(|lines| lines.last().map(|line| line.range.end));
19951
19952        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
19953            let inline_values = editor
19954                .update(cx, |editor, cx| {
19955                    let Some(current_execution_position) = current_execution_position else {
19956                        return Some(Task::ready(Ok(Vec::new())));
19957                    };
19958
19959                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
19960                        let snapshot = buffer.snapshot(cx);
19961
19962                        let excerpt = snapshot.excerpt_containing(
19963                            current_execution_position..current_execution_position,
19964                        )?;
19965
19966                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
19967                    })?;
19968
19969                    let range =
19970                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
19971
19972                    project.inline_values(buffer, range, cx)
19973                })
19974                .ok()
19975                .flatten()?
19976                .await
19977                .context("refreshing debugger inlays")
19978                .log_err()?;
19979
19980            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
19981
19982            for (buffer_id, inline_value) in inline_values
19983                .into_iter()
19984                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
19985            {
19986                buffer_inline_values
19987                    .entry(buffer_id)
19988                    .or_default()
19989                    .push(inline_value);
19990            }
19991
19992            editor
19993                .update(cx, |editor, cx| {
19994                    let snapshot = editor.buffer.read(cx).snapshot(cx);
19995                    let mut new_inlays = Vec::default();
19996
19997                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
19998                        let buffer_id = buffer_snapshot.remote_id();
19999                        buffer_inline_values
20000                            .get(&buffer_id)
20001                            .into_iter()
20002                            .flatten()
20003                            .for_each(|hint| {
20004                                let inlay = Inlay::debugger(
20005                                    post_inc(&mut editor.next_inlay_id),
20006                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20007                                    hint.text(),
20008                                );
20009                                if !inlay.text.chars().contains(&'\n') {
20010                                    new_inlays.push(inlay);
20011                                }
20012                            });
20013                    }
20014
20015                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20016                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20017
20018                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20019                })
20020                .ok()?;
20021            Some(())
20022        });
20023    }
20024
20025    fn on_buffer_event(
20026        &mut self,
20027        multibuffer: &Entity<MultiBuffer>,
20028        event: &multi_buffer::Event,
20029        window: &mut Window,
20030        cx: &mut Context<Self>,
20031    ) {
20032        match event {
20033            multi_buffer::Event::Edited {
20034                singleton_buffer_edited,
20035                edited_buffer,
20036            } => {
20037                self.scrollbar_marker_state.dirty = true;
20038                self.active_indent_guides_state.dirty = true;
20039                self.refresh_active_diagnostics(cx);
20040                self.refresh_code_actions(window, cx);
20041                self.refresh_selected_text_highlights(true, window, cx);
20042                self.refresh_single_line_folds(window, cx);
20043                refresh_matching_bracket_highlights(self, window, cx);
20044                if self.has_active_edit_prediction() {
20045                    self.update_visible_edit_prediction(window, cx);
20046                }
20047                if let Some(project) = self.project.as_ref()
20048                    && let Some(edited_buffer) = edited_buffer
20049                {
20050                    project.update(cx, |project, cx| {
20051                        self.registered_buffers
20052                            .entry(edited_buffer.read(cx).remote_id())
20053                            .or_insert_with(|| {
20054                                project.register_buffer_with_language_servers(edited_buffer, cx)
20055                            });
20056                    });
20057                }
20058                cx.emit(EditorEvent::BufferEdited);
20059                cx.emit(SearchEvent::MatchesInvalidated);
20060
20061                if let Some(buffer) = edited_buffer {
20062                    self.update_lsp_data(false, Some(buffer.read(cx).remote_id()), window, cx);
20063                }
20064
20065                if *singleton_buffer_edited {
20066                    if let Some(buffer) = edited_buffer
20067                        && buffer.read(cx).file().is_none()
20068                    {
20069                        cx.emit(EditorEvent::TitleChanged);
20070                    }
20071                    if let Some(project) = &self.project {
20072                        #[allow(clippy::mutable_key_type)]
20073                        let languages_affected = multibuffer.update(cx, |multibuffer, cx| {
20074                            multibuffer
20075                                .all_buffers()
20076                                .into_iter()
20077                                .filter_map(|buffer| {
20078                                    buffer.update(cx, |buffer, cx| {
20079                                        let language = buffer.language()?;
20080                                        let should_discard = project.update(cx, |project, cx| {
20081                                            project.is_local()
20082                                                && !project.has_language_servers_for(buffer, cx)
20083                                        });
20084                                        should_discard.not().then_some(language.clone())
20085                                    })
20086                                })
20087                                .collect::<HashSet<_>>()
20088                        });
20089                        if !languages_affected.is_empty() {
20090                            self.refresh_inlay_hints(
20091                                InlayHintRefreshReason::BufferEdited(languages_affected),
20092                                cx,
20093                            );
20094                        }
20095                    }
20096                }
20097
20098                let Some(project) = &self.project else { return };
20099                let (telemetry, is_via_ssh) = {
20100                    let project = project.read(cx);
20101                    let telemetry = project.client().telemetry().clone();
20102                    let is_via_ssh = project.is_via_ssh();
20103                    (telemetry, is_via_ssh)
20104                };
20105                refresh_linked_ranges(self, window, cx);
20106                telemetry.log_edit_event("editor", is_via_ssh);
20107            }
20108            multi_buffer::Event::ExcerptsAdded {
20109                buffer,
20110                predecessor,
20111                excerpts,
20112            } => {
20113                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20114                let buffer_id = buffer.read(cx).remote_id();
20115                if self.buffer.read(cx).diff_for(buffer_id).is_none()
20116                    && let Some(project) = &self.project
20117                {
20118                    update_uncommitted_diff_for_buffer(
20119                        cx.entity(),
20120                        project,
20121                        [buffer.clone()],
20122                        self.buffer.clone(),
20123                        cx,
20124                    )
20125                    .detach();
20126                }
20127                self.update_lsp_data(false, Some(buffer_id), window, cx);
20128                cx.emit(EditorEvent::ExcerptsAdded {
20129                    buffer: buffer.clone(),
20130                    predecessor: *predecessor,
20131                    excerpts: excerpts.clone(),
20132                });
20133                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20134            }
20135            multi_buffer::Event::ExcerptsRemoved {
20136                ids,
20137                removed_buffer_ids,
20138            } => {
20139                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
20140                let buffer = self.buffer.read(cx);
20141                self.registered_buffers
20142                    .retain(|buffer_id, _| buffer.buffer(*buffer_id).is_some());
20143                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20144                cx.emit(EditorEvent::ExcerptsRemoved {
20145                    ids: ids.clone(),
20146                    removed_buffer_ids: removed_buffer_ids.clone(),
20147                });
20148            }
20149            multi_buffer::Event::ExcerptsEdited {
20150                excerpt_ids,
20151                buffer_ids,
20152            } => {
20153                self.display_map.update(cx, |map, cx| {
20154                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
20155                });
20156                cx.emit(EditorEvent::ExcerptsEdited {
20157                    ids: excerpt_ids.clone(),
20158                });
20159            }
20160            multi_buffer::Event::ExcerptsExpanded { ids } => {
20161                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
20162                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
20163            }
20164            multi_buffer::Event::Reparsed(buffer_id) => {
20165                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20166                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20167
20168                cx.emit(EditorEvent::Reparsed(*buffer_id));
20169            }
20170            multi_buffer::Event::DiffHunksToggled => {
20171                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20172            }
20173            multi_buffer::Event::LanguageChanged(buffer_id) => {
20174                linked_editing_ranges::refresh_linked_ranges(self, window, cx);
20175                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
20176                cx.emit(EditorEvent::Reparsed(*buffer_id));
20177                cx.notify();
20178            }
20179            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
20180            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
20181            multi_buffer::Event::FileHandleChanged
20182            | multi_buffer::Event::Reloaded
20183            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
20184            multi_buffer::Event::Closed => cx.emit(EditorEvent::Closed),
20185            multi_buffer::Event::DiagnosticsUpdated => {
20186                self.update_diagnostics_state(window, cx);
20187            }
20188            _ => {}
20189        };
20190    }
20191
20192    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
20193        if !self.diagnostics_enabled() {
20194            return;
20195        }
20196        self.refresh_active_diagnostics(cx);
20197        self.refresh_inline_diagnostics(true, window, cx);
20198        self.scrollbar_marker_state.dirty = true;
20199        cx.notify();
20200    }
20201
20202    pub fn start_temporary_diff_override(&mut self) {
20203        self.load_diff_task.take();
20204        self.temporary_diff_override = true;
20205    }
20206
20207    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
20208        self.temporary_diff_override = false;
20209        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
20210        self.buffer.update(cx, |buffer, cx| {
20211            buffer.set_all_diff_hunks_collapsed(cx);
20212        });
20213
20214        if let Some(project) = self.project.clone() {
20215            self.load_diff_task = Some(
20216                update_uncommitted_diff_for_buffer(
20217                    cx.entity(),
20218                    &project,
20219                    self.buffer.read(cx).all_buffers(),
20220                    self.buffer.clone(),
20221                    cx,
20222                )
20223                .shared(),
20224            );
20225        }
20226    }
20227
20228    fn on_display_map_changed(
20229        &mut self,
20230        _: Entity<DisplayMap>,
20231        _: &mut Window,
20232        cx: &mut Context<Self>,
20233    ) {
20234        cx.notify();
20235    }
20236
20237    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20238        if self.diagnostics_enabled() {
20239            let new_severity = EditorSettings::get_global(cx)
20240                .diagnostics_max_severity
20241                .unwrap_or(DiagnosticSeverity::Hint);
20242            self.set_max_diagnostics_severity(new_severity, cx);
20243        }
20244        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
20245        self.update_edit_prediction_settings(cx);
20246        self.refresh_edit_prediction(true, false, window, cx);
20247        self.refresh_inline_values(cx);
20248        self.refresh_inlay_hints(
20249            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
20250                self.selections.newest_anchor().head(),
20251                &self.buffer.read(cx).snapshot(cx),
20252                cx,
20253            )),
20254            cx,
20255        );
20256
20257        let old_cursor_shape = self.cursor_shape;
20258        let old_show_breadcrumbs = self.show_breadcrumbs;
20259
20260        {
20261            let editor_settings = EditorSettings::get_global(cx);
20262            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
20263            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
20264            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
20265            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
20266        }
20267
20268        if old_cursor_shape != self.cursor_shape {
20269            cx.emit(EditorEvent::CursorShapeChanged);
20270        }
20271
20272        if old_show_breadcrumbs != self.show_breadcrumbs {
20273            cx.emit(EditorEvent::BreadcrumbsChanged);
20274        }
20275
20276        let project_settings = ProjectSettings::get_global(cx);
20277        self.serialize_dirty_buffers =
20278            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
20279
20280        if self.mode.is_full() {
20281            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
20282            let inline_blame_enabled = project_settings.git.inline_blame_enabled();
20283            if self.show_inline_diagnostics != show_inline_diagnostics {
20284                self.show_inline_diagnostics = show_inline_diagnostics;
20285                self.refresh_inline_diagnostics(false, window, cx);
20286            }
20287
20288            if self.git_blame_inline_enabled != inline_blame_enabled {
20289                self.toggle_git_blame_inline_internal(false, window, cx);
20290            }
20291
20292            let minimap_settings = EditorSettings::get_global(cx).minimap;
20293            if self.minimap_visibility != MinimapVisibility::Disabled {
20294                if self.minimap_visibility.settings_visibility()
20295                    != minimap_settings.minimap_enabled()
20296                {
20297                    self.set_minimap_visibility(
20298                        MinimapVisibility::for_mode(self.mode(), cx),
20299                        window,
20300                        cx,
20301                    );
20302                } else if let Some(minimap_entity) = self.minimap.as_ref() {
20303                    minimap_entity.update(cx, |minimap_editor, cx| {
20304                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
20305                    })
20306                }
20307            }
20308        }
20309
20310        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
20311            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
20312        }) {
20313            if !inlay_splice.to_insert.is_empty() || !inlay_splice.to_remove.is_empty() {
20314                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
20315            }
20316            self.refresh_colors(false, None, window, cx);
20317        }
20318
20319        cx.notify();
20320    }
20321
20322    pub fn set_searchable(&mut self, searchable: bool) {
20323        self.searchable = searchable;
20324    }
20325
20326    pub fn searchable(&self) -> bool {
20327        self.searchable
20328    }
20329
20330    fn open_proposed_changes_editor(
20331        &mut self,
20332        _: &OpenProposedChangesEditor,
20333        window: &mut Window,
20334        cx: &mut Context<Self>,
20335    ) {
20336        let Some(workspace) = self.workspace() else {
20337            cx.propagate();
20338            return;
20339        };
20340
20341        let selections = self.selections.all::<usize>(cx);
20342        let multi_buffer = self.buffer.read(cx);
20343        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20344        let mut new_selections_by_buffer = HashMap::default();
20345        for selection in selections {
20346            for (buffer, range, _) in
20347                multi_buffer_snapshot.range_to_buffer_ranges(selection.start..selection.end)
20348            {
20349                let mut range = range.to_point(buffer);
20350                range.start.column = 0;
20351                range.end.column = buffer.line_len(range.end.row);
20352                new_selections_by_buffer
20353                    .entry(multi_buffer.buffer(buffer.remote_id()).unwrap())
20354                    .or_insert(Vec::new())
20355                    .push(range)
20356            }
20357        }
20358
20359        let proposed_changes_buffers = new_selections_by_buffer
20360            .into_iter()
20361            .map(|(buffer, ranges)| ProposedChangeLocation { buffer, ranges })
20362            .collect::<Vec<_>>();
20363        let proposed_changes_editor = cx.new(|cx| {
20364            ProposedChangesEditor::new(
20365                "Proposed changes",
20366                proposed_changes_buffers,
20367                self.project.clone(),
20368                window,
20369                cx,
20370            )
20371        });
20372
20373        window.defer(cx, move |window, cx| {
20374            workspace.update(cx, |workspace, cx| {
20375                workspace.active_pane().update(cx, |pane, cx| {
20376                    pane.add_item(
20377                        Box::new(proposed_changes_editor),
20378                        true,
20379                        true,
20380                        None,
20381                        window,
20382                        cx,
20383                    );
20384                });
20385            });
20386        });
20387    }
20388
20389    pub fn open_excerpts_in_split(
20390        &mut self,
20391        _: &OpenExcerptsSplit,
20392        window: &mut Window,
20393        cx: &mut Context<Self>,
20394    ) {
20395        self.open_excerpts_common(None, true, window, cx)
20396    }
20397
20398    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
20399        self.open_excerpts_common(None, false, window, cx)
20400    }
20401
20402    fn open_excerpts_common(
20403        &mut self,
20404        jump_data: Option<JumpData>,
20405        split: bool,
20406        window: &mut Window,
20407        cx: &mut Context<Self>,
20408    ) {
20409        let Some(workspace) = self.workspace() else {
20410            cx.propagate();
20411            return;
20412        };
20413
20414        if self.buffer.read(cx).is_singleton() {
20415            cx.propagate();
20416            return;
20417        }
20418
20419        let mut new_selections_by_buffer = HashMap::default();
20420        match &jump_data {
20421            Some(JumpData::MultiBufferPoint {
20422                excerpt_id,
20423                position,
20424                anchor,
20425                line_offset_from_top,
20426            }) => {
20427                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20428                if let Some(buffer) = multi_buffer_snapshot
20429                    .buffer_id_for_excerpt(*excerpt_id)
20430                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
20431                {
20432                    let buffer_snapshot = buffer.read(cx).snapshot();
20433                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
20434                        language::ToPoint::to_point(anchor, &buffer_snapshot)
20435                    } else {
20436                        buffer_snapshot.clip_point(*position, Bias::Left)
20437                    };
20438                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
20439                    new_selections_by_buffer.insert(
20440                        buffer,
20441                        (
20442                            vec![jump_to_offset..jump_to_offset],
20443                            Some(*line_offset_from_top),
20444                        ),
20445                    );
20446                }
20447            }
20448            Some(JumpData::MultiBufferRow {
20449                row,
20450                line_offset_from_top,
20451            }) => {
20452                let point = MultiBufferPoint::new(row.0, 0);
20453                if let Some((buffer, buffer_point, _)) =
20454                    self.buffer.read(cx).point_to_buffer_point(point, cx)
20455                {
20456                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
20457                    new_selections_by_buffer
20458                        .entry(buffer)
20459                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
20460                        .0
20461                        .push(buffer_offset..buffer_offset)
20462                }
20463            }
20464            None => {
20465                let selections = self.selections.all::<usize>(cx);
20466                let multi_buffer = self.buffer.read(cx);
20467                for selection in selections {
20468                    for (snapshot, range, _, anchor) in multi_buffer
20469                        .snapshot(cx)
20470                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
20471                    {
20472                        if let Some(anchor) = anchor {
20473                            // selection is in a deleted hunk
20474                            let Some(buffer_id) = anchor.buffer_id else {
20475                                continue;
20476                            };
20477                            let Some(buffer_handle) = multi_buffer.buffer(buffer_id) else {
20478                                continue;
20479                            };
20480                            let offset = text::ToOffset::to_offset(
20481                                &anchor.text_anchor,
20482                                &buffer_handle.read(cx).snapshot(),
20483                            );
20484                            let range = offset..offset;
20485                            new_selections_by_buffer
20486                                .entry(buffer_handle)
20487                                .or_insert((Vec::new(), None))
20488                                .0
20489                                .push(range)
20490                        } else {
20491                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
20492                            else {
20493                                continue;
20494                            };
20495                            new_selections_by_buffer
20496                                .entry(buffer_handle)
20497                                .or_insert((Vec::new(), None))
20498                                .0
20499                                .push(range)
20500                        }
20501                    }
20502                }
20503            }
20504        }
20505
20506        new_selections_by_buffer
20507            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
20508
20509        if new_selections_by_buffer.is_empty() {
20510            return;
20511        }
20512
20513        // We defer the pane interaction because we ourselves are a workspace item
20514        // and activating a new item causes the pane to call a method on us reentrantly,
20515        // which panics if we're on the stack.
20516        window.defer(cx, move |window, cx| {
20517            workspace.update(cx, |workspace, cx| {
20518                let pane = if split {
20519                    workspace.adjacent_pane(window, cx)
20520                } else {
20521                    workspace.active_pane().clone()
20522                };
20523
20524                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
20525                    let editor = buffer
20526                        .read(cx)
20527                        .file()
20528                        .is_none()
20529                        .then(|| {
20530                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
20531                            // so `workspace.open_project_item` will never find them, always opening a new editor.
20532                            // Instead, we try to activate the existing editor in the pane first.
20533                            let (editor, pane_item_index) =
20534                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
20535                                    let editor = item.downcast::<Editor>()?;
20536                                    let singleton_buffer =
20537                                        editor.read(cx).buffer().read(cx).as_singleton()?;
20538                                    if singleton_buffer == buffer {
20539                                        Some((editor, i))
20540                                    } else {
20541                                        None
20542                                    }
20543                                })?;
20544                            pane.update(cx, |pane, cx| {
20545                                pane.activate_item(pane_item_index, true, true, window, cx)
20546                            });
20547                            Some(editor)
20548                        })
20549                        .flatten()
20550                        .unwrap_or_else(|| {
20551                            workspace.open_project_item::<Self>(
20552                                pane.clone(),
20553                                buffer,
20554                                true,
20555                                true,
20556                                window,
20557                                cx,
20558                            )
20559                        });
20560
20561                    editor.update(cx, |editor, cx| {
20562                        let autoscroll = match scroll_offset {
20563                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
20564                            None => Autoscroll::newest(),
20565                        };
20566                        let nav_history = editor.nav_history.take();
20567                        editor.change_selections(
20568                            SelectionEffects::scroll(autoscroll),
20569                            window,
20570                            cx,
20571                            |s| {
20572                                s.select_ranges(ranges);
20573                            },
20574                        );
20575                        editor.nav_history = nav_history;
20576                    });
20577                }
20578            })
20579        });
20580    }
20581
20582    // For now, don't allow opening excerpts in buffers that aren't backed by
20583    // regular project files.
20584    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
20585        file.map_or(true, |file| project::File::from_dyn(Some(file)).is_some())
20586    }
20587
20588    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
20589        let snapshot = self.buffer.read(cx).read(cx);
20590        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
20591        Some(
20592            ranges
20593                .iter()
20594                .map(move |range| {
20595                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
20596                })
20597                .collect(),
20598        )
20599    }
20600
20601    fn selection_replacement_ranges(
20602        &self,
20603        range: Range<OffsetUtf16>,
20604        cx: &mut App,
20605    ) -> Vec<Range<OffsetUtf16>> {
20606        let selections = self.selections.all::<OffsetUtf16>(cx);
20607        let newest_selection = selections
20608            .iter()
20609            .max_by_key(|selection| selection.id)
20610            .unwrap();
20611        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
20612        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
20613        let snapshot = self.buffer.read(cx).read(cx);
20614        selections
20615            .into_iter()
20616            .map(|mut selection| {
20617                selection.start.0 =
20618                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
20619                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
20620                snapshot.clip_offset_utf16(selection.start, Bias::Left)
20621                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
20622            })
20623            .collect()
20624    }
20625
20626    fn report_editor_event(
20627        &self,
20628        reported_event: ReportEditorEvent,
20629        file_extension: Option<String>,
20630        cx: &App,
20631    ) {
20632        if cfg!(any(test, feature = "test-support")) {
20633            return;
20634        }
20635
20636        let Some(project) = &self.project else { return };
20637
20638        // If None, we are in a file without an extension
20639        let file = self
20640            .buffer
20641            .read(cx)
20642            .as_singleton()
20643            .and_then(|b| b.read(cx).file());
20644        let file_extension = file_extension.or(file
20645            .as_ref()
20646            .and_then(|file| Path::new(file.file_name(cx)).extension())
20647            .and_then(|e| e.to_str())
20648            .map(|a| a.to_string()));
20649
20650        let vim_mode = vim_enabled(cx);
20651
20652        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
20653        let copilot_enabled = edit_predictions_provider
20654            == language::language_settings::EditPredictionProvider::Copilot;
20655        let copilot_enabled_for_language = self
20656            .buffer
20657            .read(cx)
20658            .language_settings(cx)
20659            .show_edit_predictions;
20660
20661        let project = project.read(cx);
20662        let event_type = reported_event.event_type();
20663
20664        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
20665            telemetry::event!(
20666                event_type,
20667                type = if auto_saved {"autosave"} else {"manual"},
20668                file_extension,
20669                vim_mode,
20670                copilot_enabled,
20671                copilot_enabled_for_language,
20672                edit_predictions_provider,
20673                is_via_ssh = project.is_via_ssh(),
20674            );
20675        } else {
20676            telemetry::event!(
20677                event_type,
20678                file_extension,
20679                vim_mode,
20680                copilot_enabled,
20681                copilot_enabled_for_language,
20682                edit_predictions_provider,
20683                is_via_ssh = project.is_via_ssh(),
20684            );
20685        };
20686    }
20687
20688    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
20689    /// with each line being an array of {text, highlight} objects.
20690    fn copy_highlight_json(
20691        &mut self,
20692        _: &CopyHighlightJson,
20693        window: &mut Window,
20694        cx: &mut Context<Self>,
20695    ) {
20696        #[derive(Serialize)]
20697        struct Chunk<'a> {
20698            text: String,
20699            highlight: Option<&'a str>,
20700        }
20701
20702        let snapshot = self.buffer.read(cx).snapshot(cx);
20703        let range = self
20704            .selected_text_range(false, window, cx)
20705            .and_then(|selection| {
20706                if selection.range.is_empty() {
20707                    None
20708                } else {
20709                    Some(selection.range)
20710                }
20711            })
20712            .unwrap_or_else(|| 0..snapshot.len());
20713
20714        let chunks = snapshot.chunks(range, true);
20715        let mut lines = Vec::new();
20716        let mut line: VecDeque<Chunk> = VecDeque::new();
20717
20718        let Some(style) = self.style.as_ref() else {
20719            return;
20720        };
20721
20722        for chunk in chunks {
20723            let highlight = chunk
20724                .syntax_highlight_id
20725                .and_then(|id| id.name(&style.syntax));
20726            let mut chunk_lines = chunk.text.split('\n').peekable();
20727            while let Some(text) = chunk_lines.next() {
20728                let mut merged_with_last_token = false;
20729                if let Some(last_token) = line.back_mut()
20730                    && last_token.highlight == highlight
20731                {
20732                    last_token.text.push_str(text);
20733                    merged_with_last_token = true;
20734                }
20735
20736                if !merged_with_last_token {
20737                    line.push_back(Chunk {
20738                        text: text.into(),
20739                        highlight,
20740                    });
20741                }
20742
20743                if chunk_lines.peek().is_some() {
20744                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
20745                        line.pop_front();
20746                    }
20747                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
20748                        line.pop_back();
20749                    }
20750
20751                    lines.push(mem::take(&mut line));
20752                }
20753            }
20754        }
20755
20756        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
20757            return;
20758        };
20759        cx.write_to_clipboard(ClipboardItem::new_string(lines));
20760    }
20761
20762    pub fn open_context_menu(
20763        &mut self,
20764        _: &OpenContextMenu,
20765        window: &mut Window,
20766        cx: &mut Context<Self>,
20767    ) {
20768        self.request_autoscroll(Autoscroll::newest(), cx);
20769        let position = self.selections.newest_display(cx).start;
20770        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
20771    }
20772
20773    pub fn inlay_hint_cache(&self) -> &InlayHintCache {
20774        &self.inlay_hint_cache
20775    }
20776
20777    pub fn replay_insert_event(
20778        &mut self,
20779        text: &str,
20780        relative_utf16_range: Option<Range<isize>>,
20781        window: &mut Window,
20782        cx: &mut Context<Self>,
20783    ) {
20784        if !self.input_enabled {
20785            cx.emit(EditorEvent::InputIgnored { text: text.into() });
20786            return;
20787        }
20788        if let Some(relative_utf16_range) = relative_utf16_range {
20789            let selections = self.selections.all::<OffsetUtf16>(cx);
20790            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20791                let new_ranges = selections.into_iter().map(|range| {
20792                    let start = OffsetUtf16(
20793                        range
20794                            .head()
20795                            .0
20796                            .saturating_add_signed(relative_utf16_range.start),
20797                    );
20798                    let end = OffsetUtf16(
20799                        range
20800                            .head()
20801                            .0
20802                            .saturating_add_signed(relative_utf16_range.end),
20803                    );
20804                    start..end
20805                });
20806                s.select_ranges(new_ranges);
20807            });
20808        }
20809
20810        self.handle_input(text, window, cx);
20811    }
20812
20813    pub fn supports_inlay_hints(&self, cx: &mut App) -> bool {
20814        let Some(provider) = self.semantics_provider.as_ref() else {
20815            return false;
20816        };
20817
20818        let mut supports = false;
20819        self.buffer().update(cx, |this, cx| {
20820            this.for_each_buffer(|buffer| {
20821                supports |= provider.supports_inlay_hints(buffer, cx);
20822            });
20823        });
20824
20825        supports
20826    }
20827
20828    pub fn is_focused(&self, window: &Window) -> bool {
20829        self.focus_handle.is_focused(window)
20830    }
20831
20832    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20833        cx.emit(EditorEvent::Focused);
20834
20835        if let Some(descendant) = self
20836            .last_focused_descendant
20837            .take()
20838            .and_then(|descendant| descendant.upgrade())
20839        {
20840            window.focus(&descendant);
20841        } else {
20842            if let Some(blame) = self.blame.as_ref() {
20843                blame.update(cx, GitBlame::focus)
20844            }
20845
20846            self.blink_manager.update(cx, BlinkManager::enable);
20847            self.show_cursor_names(window, cx);
20848            self.buffer.update(cx, |buffer, cx| {
20849                buffer.finalize_last_transaction(cx);
20850                if self.leader_id.is_none() {
20851                    buffer.set_active_selections(
20852                        &self.selections.disjoint_anchors(),
20853                        self.selections.line_mode,
20854                        self.cursor_shape,
20855                        cx,
20856                    );
20857                }
20858            });
20859        }
20860    }
20861
20862    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
20863        cx.emit(EditorEvent::FocusedIn)
20864    }
20865
20866    fn handle_focus_out(
20867        &mut self,
20868        event: FocusOutEvent,
20869        _window: &mut Window,
20870        cx: &mut Context<Self>,
20871    ) {
20872        if event.blurred != self.focus_handle {
20873            self.last_focused_descendant = Some(event.blurred);
20874        }
20875        self.selection_drag_state = SelectionDragState::None;
20876        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
20877    }
20878
20879    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20880        self.blink_manager.update(cx, BlinkManager::disable);
20881        self.buffer
20882            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
20883
20884        if let Some(blame) = self.blame.as_ref() {
20885            blame.update(cx, GitBlame::blur)
20886        }
20887        if !self.hover_state.focused(window, cx) {
20888            hide_hover(self, cx);
20889        }
20890        if !self
20891            .context_menu
20892            .borrow()
20893            .as_ref()
20894            .is_some_and(|context_menu| context_menu.focused(window, cx))
20895        {
20896            self.hide_context_menu(window, cx);
20897        }
20898        self.discard_edit_prediction(false, cx);
20899        cx.emit(EditorEvent::Blurred);
20900        cx.notify();
20901    }
20902
20903    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20904        let mut pending: String = window
20905            .pending_input_keystrokes()
20906            .into_iter()
20907            .flatten()
20908            .filter_map(|keystroke| {
20909                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
20910                    keystroke.key_char.clone()
20911                } else {
20912                    None
20913                }
20914            })
20915            .collect();
20916
20917        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
20918            pending = "".to_string();
20919        }
20920
20921        let existing_pending = self
20922            .text_highlights::<PendingInput>(cx)
20923            .map(|(_, ranges)| ranges.to_vec());
20924        if existing_pending.is_none() && pending.is_empty() {
20925            return;
20926        }
20927        let transaction =
20928            self.transact(window, cx, |this, window, cx| {
20929                let selections = this.selections.all::<usize>(cx);
20930                let edits = selections
20931                    .iter()
20932                    .map(|selection| (selection.end..selection.end, pending.clone()));
20933                this.edit(edits, cx);
20934                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20935                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
20936                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
20937                    }));
20938                });
20939                if let Some(existing_ranges) = existing_pending {
20940                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
20941                    this.edit(edits, cx);
20942                }
20943            });
20944
20945        let snapshot = self.snapshot(window, cx);
20946        let ranges = self
20947            .selections
20948            .all::<usize>(cx)
20949            .into_iter()
20950            .map(|selection| {
20951                snapshot.buffer_snapshot.anchor_after(selection.end)
20952                    ..snapshot
20953                        .buffer_snapshot
20954                        .anchor_before(selection.end + pending.len())
20955            })
20956            .collect();
20957
20958        if pending.is_empty() {
20959            self.clear_highlights::<PendingInput>(cx);
20960        } else {
20961            self.highlight_text::<PendingInput>(
20962                ranges,
20963                HighlightStyle {
20964                    underline: Some(UnderlineStyle {
20965                        thickness: px(1.),
20966                        color: None,
20967                        wavy: false,
20968                    }),
20969                    ..Default::default()
20970                },
20971                cx,
20972            );
20973        }
20974
20975        self.ime_transaction = self.ime_transaction.or(transaction);
20976        if let Some(transaction) = self.ime_transaction {
20977            self.buffer.update(cx, |buffer, cx| {
20978                buffer.group_until_transaction(transaction, cx);
20979            });
20980        }
20981
20982        if self.text_highlights::<PendingInput>(cx).is_none() {
20983            self.ime_transaction.take();
20984        }
20985    }
20986
20987    pub fn register_action_renderer(
20988        &mut self,
20989        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
20990    ) -> Subscription {
20991        let id = self.next_editor_action_id.post_inc();
20992        self.editor_actions
20993            .borrow_mut()
20994            .insert(id, Box::new(listener));
20995
20996        let editor_actions = self.editor_actions.clone();
20997        Subscription::new(move || {
20998            editor_actions.borrow_mut().remove(&id);
20999        })
21000    }
21001
21002    pub fn register_action<A: Action>(
21003        &mut self,
21004        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21005    ) -> Subscription {
21006        let id = self.next_editor_action_id.post_inc();
21007        let listener = Arc::new(listener);
21008        self.editor_actions.borrow_mut().insert(
21009            id,
21010            Box::new(move |_, window, _| {
21011                let listener = listener.clone();
21012                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21013                    let action = action.downcast_ref().unwrap();
21014                    if phase == DispatchPhase::Bubble {
21015                        listener(action, window, cx)
21016                    }
21017                })
21018            }),
21019        );
21020
21021        let editor_actions = self.editor_actions.clone();
21022        Subscription::new(move || {
21023            editor_actions.borrow_mut().remove(&id);
21024        })
21025    }
21026
21027    pub fn file_header_size(&self) -> u32 {
21028        FILE_HEADER_HEIGHT
21029    }
21030
21031    pub fn restore(
21032        &mut self,
21033        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21034        window: &mut Window,
21035        cx: &mut Context<Self>,
21036    ) {
21037        let workspace = self.workspace();
21038        let project = self.project();
21039        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21040            let mut tasks = Vec::new();
21041            for (buffer_id, changes) in revert_changes {
21042                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21043                    buffer.update(cx, |buffer, cx| {
21044                        buffer.edit(
21045                            changes
21046                                .into_iter()
21047                                .map(|(range, text)| (range, text.to_string())),
21048                            None,
21049                            cx,
21050                        );
21051                    });
21052
21053                    if let Some(project) =
21054                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21055                    {
21056                        project.update(cx, |project, cx| {
21057                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21058                        })
21059                    }
21060                }
21061            }
21062            tasks
21063        });
21064        cx.spawn_in(window, async move |_, cx| {
21065            for (buffer, task) in save_tasks {
21066                let result = task.await;
21067                if result.is_err() {
21068                    let Some(path) = buffer
21069                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21070                        .ok()
21071                    else {
21072                        continue;
21073                    };
21074                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21075                        let Some(task) = cx
21076                            .update_window_entity(workspace, |workspace, window, cx| {
21077                                workspace
21078                                    .open_path_preview(path, None, false, false, false, window, cx)
21079                            })
21080                            .ok()
21081                        else {
21082                            continue;
21083                        };
21084                        task.await.log_err();
21085                    }
21086                }
21087            }
21088        })
21089        .detach();
21090        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21091            selections.refresh()
21092        });
21093    }
21094
21095    pub fn to_pixel_point(
21096        &self,
21097        source: multi_buffer::Anchor,
21098        editor_snapshot: &EditorSnapshot,
21099        window: &mut Window,
21100    ) -> Option<gpui::Point<Pixels>> {
21101        let source_point = source.to_display_point(editor_snapshot);
21102        self.display_to_pixel_point(source_point, editor_snapshot, window)
21103    }
21104
21105    pub fn display_to_pixel_point(
21106        &self,
21107        source: DisplayPoint,
21108        editor_snapshot: &EditorSnapshot,
21109        window: &mut Window,
21110    ) -> Option<gpui::Point<Pixels>> {
21111        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21112        let text_layout_details = self.text_layout_details(window);
21113        let scroll_top = text_layout_details
21114            .scroll_anchor
21115            .scroll_position(editor_snapshot)
21116            .y;
21117
21118        if source.row().as_f32() < scroll_top.floor() {
21119            return None;
21120        }
21121        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21122        let source_y = line_height * (source.row().as_f32() - scroll_top);
21123        Some(gpui::Point::new(source_x, source_y))
21124    }
21125
21126    pub fn has_visible_completions_menu(&self) -> bool {
21127        !self.edit_prediction_preview_is_active()
21128            && self.context_menu.borrow().as_ref().map_or(false, |menu| {
21129                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21130            })
21131    }
21132
21133    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21134        if self.mode.is_minimap() {
21135            return;
21136        }
21137        self.addons
21138            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21139    }
21140
21141    pub fn unregister_addon<T: Addon>(&mut self) {
21142        self.addons.remove(&std::any::TypeId::of::<T>());
21143    }
21144
21145    pub fn addon<T: Addon>(&self) -> Option<&T> {
21146        let type_id = std::any::TypeId::of::<T>();
21147        self.addons
21148            .get(&type_id)
21149            .and_then(|item| item.to_any().downcast_ref::<T>())
21150    }
21151
21152    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21153        let type_id = std::any::TypeId::of::<T>();
21154        self.addons
21155            .get_mut(&type_id)
21156            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21157    }
21158
21159    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21160        let text_layout_details = self.text_layout_details(window);
21161        let style = &text_layout_details.editor_style;
21162        let font_id = window.text_system().resolve_font(&style.text.font());
21163        let font_size = style.text.font_size.to_pixels(window.rem_size());
21164        let line_height = style.text.line_height_in_pixels(window.rem_size());
21165        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21166        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21167
21168        CharacterDimensions {
21169            em_width,
21170            em_advance,
21171            line_height,
21172        }
21173    }
21174
21175    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21176        self.load_diff_task.clone()
21177    }
21178
21179    fn read_metadata_from_db(
21180        &mut self,
21181        item_id: u64,
21182        workspace_id: WorkspaceId,
21183        window: &mut Window,
21184        cx: &mut Context<Editor>,
21185    ) {
21186        if self.is_singleton(cx)
21187            && !self.mode.is_minimap()
21188            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
21189        {
21190            let buffer_snapshot = OnceCell::new();
21191
21192            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
21193                && !folds.is_empty()
21194            {
21195                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21196                self.fold_ranges(
21197                    folds
21198                        .into_iter()
21199                        .map(|(start, end)| {
21200                            snapshot.clip_offset(start, Bias::Left)
21201                                ..snapshot.clip_offset(end, Bias::Right)
21202                        })
21203                        .collect(),
21204                    false,
21205                    window,
21206                    cx,
21207                );
21208            }
21209
21210            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
21211                && !selections.is_empty()
21212            {
21213                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
21214                // skip adding the initial selection to selection history
21215                self.selection_history.mode = SelectionHistoryMode::Skipping;
21216                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21217                    s.select_ranges(selections.into_iter().map(|(start, end)| {
21218                        snapshot.clip_offset(start, Bias::Left)
21219                            ..snapshot.clip_offset(end, Bias::Right)
21220                    }));
21221                });
21222                self.selection_history.mode = SelectionHistoryMode::Normal;
21223            };
21224        }
21225
21226        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
21227    }
21228
21229    fn update_lsp_data(
21230        &mut self,
21231        ignore_cache: bool,
21232        for_buffer: Option<BufferId>,
21233        window: &mut Window,
21234        cx: &mut Context<'_, Self>,
21235    ) {
21236        self.pull_diagnostics(for_buffer, window, cx);
21237        self.refresh_colors(ignore_cache, for_buffer, window, cx);
21238    }
21239}
21240
21241fn vim_enabled(cx: &App) -> bool {
21242    cx.global::<SettingsStore>()
21243        .raw_user_settings()
21244        .get("vim_mode")
21245        == Some(&serde_json::Value::Bool(true))
21246}
21247
21248fn process_completion_for_edit(
21249    completion: &Completion,
21250    intent: CompletionIntent,
21251    buffer: &Entity<Buffer>,
21252    cursor_position: &text::Anchor,
21253    cx: &mut Context<Editor>,
21254) -> CompletionEdit {
21255    let buffer = buffer.read(cx);
21256    let buffer_snapshot = buffer.snapshot();
21257    let (snippet, new_text) = if completion.is_snippet() {
21258        // Workaround for typescript language server issues so that methods don't expand within
21259        // strings and functions with type expressions. The previous point is used because the query
21260        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
21261        let mut snippet_source = completion.new_text.clone();
21262        let mut previous_point = text::ToPoint::to_point(cursor_position, buffer);
21263        previous_point.column = previous_point.column.saturating_sub(1);
21264        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
21265            && scope.prefers_label_for_snippet_in_completion()
21266            && let Some(label) = completion.label()
21267            && matches!(
21268                completion.kind(),
21269                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
21270            )
21271        {
21272            snippet_source = label;
21273        }
21274        match Snippet::parse(&snippet_source).log_err() {
21275            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
21276            None => (None, completion.new_text.clone()),
21277        }
21278    } else {
21279        (None, completion.new_text.clone())
21280    };
21281
21282    let mut range_to_replace = {
21283        let replace_range = &completion.replace_range;
21284        if let CompletionSource::Lsp {
21285            insert_range: Some(insert_range),
21286            ..
21287        } = &completion.source
21288        {
21289            debug_assert_eq!(
21290                insert_range.start, replace_range.start,
21291                "insert_range and replace_range should start at the same position"
21292            );
21293            debug_assert!(
21294                insert_range
21295                    .start
21296                    .cmp(cursor_position, &buffer_snapshot)
21297                    .is_le(),
21298                "insert_range should start before or at cursor position"
21299            );
21300            debug_assert!(
21301                replace_range
21302                    .start
21303                    .cmp(cursor_position, &buffer_snapshot)
21304                    .is_le(),
21305                "replace_range should start before or at cursor position"
21306            );
21307
21308            let should_replace = match intent {
21309                CompletionIntent::CompleteWithInsert => false,
21310                CompletionIntent::CompleteWithReplace => true,
21311                CompletionIntent::Complete | CompletionIntent::Compose => {
21312                    let insert_mode =
21313                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
21314                            .completions
21315                            .lsp_insert_mode;
21316                    match insert_mode {
21317                        LspInsertMode::Insert => false,
21318                        LspInsertMode::Replace => true,
21319                        LspInsertMode::ReplaceSubsequence => {
21320                            let mut text_to_replace = buffer.chars_for_range(
21321                                buffer.anchor_before(replace_range.start)
21322                                    ..buffer.anchor_after(replace_range.end),
21323                            );
21324                            let mut current_needle = text_to_replace.next();
21325                            for haystack_ch in completion.label.text.chars() {
21326                                if let Some(needle_ch) = current_needle
21327                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
21328                                {
21329                                    current_needle = text_to_replace.next();
21330                                }
21331                            }
21332                            current_needle.is_none()
21333                        }
21334                        LspInsertMode::ReplaceSuffix => {
21335                            if replace_range
21336                                .end
21337                                .cmp(cursor_position, &buffer_snapshot)
21338                                .is_gt()
21339                            {
21340                                let range_after_cursor = *cursor_position..replace_range.end;
21341                                let text_after_cursor = buffer
21342                                    .text_for_range(
21343                                        buffer.anchor_before(range_after_cursor.start)
21344                                            ..buffer.anchor_after(range_after_cursor.end),
21345                                    )
21346                                    .collect::<String>()
21347                                    .to_ascii_lowercase();
21348                                completion
21349                                    .label
21350                                    .text
21351                                    .to_ascii_lowercase()
21352                                    .ends_with(&text_after_cursor)
21353                            } else {
21354                                true
21355                            }
21356                        }
21357                    }
21358                }
21359            };
21360
21361            if should_replace {
21362                replace_range.clone()
21363            } else {
21364                insert_range.clone()
21365            }
21366        } else {
21367            replace_range.clone()
21368        }
21369    };
21370
21371    if range_to_replace
21372        .end
21373        .cmp(cursor_position, &buffer_snapshot)
21374        .is_lt()
21375    {
21376        range_to_replace.end = *cursor_position;
21377    }
21378
21379    CompletionEdit {
21380        new_text,
21381        replace_range: range_to_replace.to_offset(buffer),
21382        snippet,
21383    }
21384}
21385
21386struct CompletionEdit {
21387    new_text: String,
21388    replace_range: Range<usize>,
21389    snippet: Option<Snippet>,
21390}
21391
21392fn insert_extra_newline_brackets(
21393    buffer: &MultiBufferSnapshot,
21394    range: Range<usize>,
21395    language: &language::LanguageScope,
21396) -> bool {
21397    let leading_whitespace_len = buffer
21398        .reversed_chars_at(range.start)
21399        .take_while(|c| c.is_whitespace() && *c != '\n')
21400        .map(|c| c.len_utf8())
21401        .sum::<usize>();
21402    let trailing_whitespace_len = buffer
21403        .chars_at(range.end)
21404        .take_while(|c| c.is_whitespace() && *c != '\n')
21405        .map(|c| c.len_utf8())
21406        .sum::<usize>();
21407    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
21408
21409    language.brackets().any(|(pair, enabled)| {
21410        let pair_start = pair.start.trim_end();
21411        let pair_end = pair.end.trim_start();
21412
21413        enabled
21414            && pair.newline
21415            && buffer.contains_str_at(range.end, pair_end)
21416            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
21417    })
21418}
21419
21420fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
21421    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
21422        [(buffer, range, _)] => (*buffer, range.clone()),
21423        _ => return false,
21424    };
21425    let pair = {
21426        let mut result: Option<BracketMatch> = None;
21427
21428        for pair in buffer
21429            .all_bracket_ranges(range.clone())
21430            .filter(move |pair| {
21431                pair.open_range.start <= range.start && pair.close_range.end >= range.end
21432            })
21433        {
21434            let len = pair.close_range.end - pair.open_range.start;
21435
21436            if let Some(existing) = &result {
21437                let existing_len = existing.close_range.end - existing.open_range.start;
21438                if len > existing_len {
21439                    continue;
21440                }
21441            }
21442
21443            result = Some(pair);
21444        }
21445
21446        result
21447    };
21448    let Some(pair) = pair else {
21449        return false;
21450    };
21451    pair.newline_only
21452        && buffer
21453            .chars_for_range(pair.open_range.end..range.start)
21454            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
21455            .all(|c| c.is_whitespace() && c != '\n')
21456}
21457
21458fn update_uncommitted_diff_for_buffer(
21459    editor: Entity<Editor>,
21460    project: &Entity<Project>,
21461    buffers: impl IntoIterator<Item = Entity<Buffer>>,
21462    buffer: Entity<MultiBuffer>,
21463    cx: &mut App,
21464) -> Task<()> {
21465    let mut tasks = Vec::new();
21466    project.update(cx, |project, cx| {
21467        for buffer in buffers {
21468            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
21469                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
21470            }
21471        }
21472    });
21473    cx.spawn(async move |cx| {
21474        let diffs = future::join_all(tasks).await;
21475        if editor
21476            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
21477            .unwrap_or(false)
21478        {
21479            return;
21480        }
21481
21482        buffer
21483            .update(cx, |buffer, cx| {
21484                for diff in diffs.into_iter().flatten() {
21485                    buffer.add_diff(diff, cx);
21486                }
21487            })
21488            .ok();
21489    })
21490}
21491
21492fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
21493    let tab_size = tab_size.get() as usize;
21494    let mut width = offset;
21495
21496    for ch in text.chars() {
21497        width += if ch == '\t' {
21498            tab_size - (width % tab_size)
21499        } else {
21500            1
21501        };
21502    }
21503
21504    width - offset
21505}
21506
21507#[cfg(test)]
21508mod tests {
21509    use super::*;
21510
21511    #[test]
21512    fn test_string_size_with_expanded_tabs() {
21513        let nz = |val| NonZeroU32::new(val).unwrap();
21514        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
21515        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
21516        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
21517        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
21518        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
21519        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
21520        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
21521        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
21522    }
21523}
21524
21525/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
21526struct WordBreakingTokenizer<'a> {
21527    input: &'a str,
21528}
21529
21530impl<'a> WordBreakingTokenizer<'a> {
21531    fn new(input: &'a str) -> Self {
21532        Self { input }
21533    }
21534}
21535
21536fn is_char_ideographic(ch: char) -> bool {
21537    use unicode_script::Script::*;
21538    use unicode_script::UnicodeScript;
21539    matches!(ch.script(), Han | Tangut | Yi)
21540}
21541
21542fn is_grapheme_ideographic(text: &str) -> bool {
21543    text.chars().any(is_char_ideographic)
21544}
21545
21546fn is_grapheme_whitespace(text: &str) -> bool {
21547    text.chars().any(|x| x.is_whitespace())
21548}
21549
21550fn should_stay_with_preceding_ideograph(text: &str) -> bool {
21551    text.chars().next().map_or(false, |ch| {
21552        matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…')
21553    })
21554}
21555
21556#[derive(PartialEq, Eq, Debug, Clone, Copy)]
21557enum WordBreakToken<'a> {
21558    Word { token: &'a str, grapheme_len: usize },
21559    InlineWhitespace { token: &'a str, grapheme_len: usize },
21560    Newline,
21561}
21562
21563impl<'a> Iterator for WordBreakingTokenizer<'a> {
21564    /// Yields a span, the count of graphemes in the token, and whether it was
21565    /// whitespace. Note that it also breaks at word boundaries.
21566    type Item = WordBreakToken<'a>;
21567
21568    fn next(&mut self) -> Option<Self::Item> {
21569        use unicode_segmentation::UnicodeSegmentation;
21570        if self.input.is_empty() {
21571            return None;
21572        }
21573
21574        let mut iter = self.input.graphemes(true).peekable();
21575        let mut offset = 0;
21576        let mut grapheme_len = 0;
21577        if let Some(first_grapheme) = iter.next() {
21578            let is_newline = first_grapheme == "\n";
21579            let is_whitespace = is_grapheme_whitespace(first_grapheme);
21580            offset += first_grapheme.len();
21581            grapheme_len += 1;
21582            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
21583                if let Some(grapheme) = iter.peek().copied()
21584                    && should_stay_with_preceding_ideograph(grapheme)
21585                {
21586                    offset += grapheme.len();
21587                    grapheme_len += 1;
21588                }
21589            } else {
21590                let mut words = self.input[offset..].split_word_bound_indices().peekable();
21591                let mut next_word_bound = words.peek().copied();
21592                if next_word_bound.map_or(false, |(i, _)| i == 0) {
21593                    next_word_bound = words.next();
21594                }
21595                while let Some(grapheme) = iter.peek().copied() {
21596                    if next_word_bound.map_or(false, |(i, _)| i == offset) {
21597                        break;
21598                    };
21599                    if is_grapheme_whitespace(grapheme) != is_whitespace
21600                        || (grapheme == "\n") != is_newline
21601                    {
21602                        break;
21603                    };
21604                    offset += grapheme.len();
21605                    grapheme_len += 1;
21606                    iter.next();
21607                }
21608            }
21609            let token = &self.input[..offset];
21610            self.input = &self.input[offset..];
21611            if token == "\n" {
21612                Some(WordBreakToken::Newline)
21613            } else if is_whitespace {
21614                Some(WordBreakToken::InlineWhitespace {
21615                    token,
21616                    grapheme_len,
21617                })
21618            } else {
21619                Some(WordBreakToken::Word {
21620                    token,
21621                    grapheme_len,
21622                })
21623            }
21624        } else {
21625            None
21626        }
21627    }
21628}
21629
21630#[test]
21631fn test_word_breaking_tokenizer() {
21632    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
21633        ("", &[]),
21634        ("  ", &[whitespace("  ", 2)]),
21635        ("Ʒ", &[word("Ʒ", 1)]),
21636        ("Ǽ", &[word("Ǽ", 1)]),
21637        ("", &[word("", 1)]),
21638        ("⋑⋑", &[word("⋑⋑", 2)]),
21639        (
21640            "原理,进而",
21641            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
21642        ),
21643        (
21644            "hello world",
21645            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
21646        ),
21647        (
21648            "hello, world",
21649            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
21650        ),
21651        (
21652            "  hello world",
21653            &[
21654                whitespace("  ", 2),
21655                word("hello", 5),
21656                whitespace(" ", 1),
21657                word("world", 5),
21658            ],
21659        ),
21660        (
21661            "这是什么 \n 钢笔",
21662            &[
21663                word("", 1),
21664                word("", 1),
21665                word("", 1),
21666                word("", 1),
21667                whitespace(" ", 1),
21668                newline(),
21669                whitespace(" ", 1),
21670                word("", 1),
21671                word("", 1),
21672            ],
21673        ),
21674        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
21675    ];
21676
21677    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21678        WordBreakToken::Word {
21679            token,
21680            grapheme_len,
21681        }
21682    }
21683
21684    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
21685        WordBreakToken::InlineWhitespace {
21686            token,
21687            grapheme_len,
21688        }
21689    }
21690
21691    fn newline() -> WordBreakToken<'static> {
21692        WordBreakToken::Newline
21693    }
21694
21695    for (input, result) in tests {
21696        assert_eq!(
21697            WordBreakingTokenizer::new(input)
21698                .collect::<Vec<_>>()
21699                .as_slice(),
21700            *result,
21701        );
21702    }
21703}
21704
21705fn wrap_with_prefix(
21706    first_line_prefix: String,
21707    subsequent_lines_prefix: String,
21708    unwrapped_text: String,
21709    wrap_column: usize,
21710    tab_size: NonZeroU32,
21711    preserve_existing_whitespace: bool,
21712) -> String {
21713    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
21714    let subsequent_lines_prefix_len =
21715        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
21716    let mut wrapped_text = String::new();
21717    let mut current_line = first_line_prefix.clone();
21718    let mut is_first_line = true;
21719
21720    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
21721    let mut current_line_len = first_line_prefix_len;
21722    let mut in_whitespace = false;
21723    for token in tokenizer {
21724        let have_preceding_whitespace = in_whitespace;
21725        match token {
21726            WordBreakToken::Word {
21727                token,
21728                grapheme_len,
21729            } => {
21730                in_whitespace = false;
21731                let current_prefix_len = if is_first_line {
21732                    first_line_prefix_len
21733                } else {
21734                    subsequent_lines_prefix_len
21735                };
21736                if current_line_len + grapheme_len > wrap_column
21737                    && current_line_len != current_prefix_len
21738                {
21739                    wrapped_text.push_str(current_line.trim_end());
21740                    wrapped_text.push('\n');
21741                    is_first_line = false;
21742                    current_line = subsequent_lines_prefix.clone();
21743                    current_line_len = subsequent_lines_prefix_len;
21744                }
21745                current_line.push_str(token);
21746                current_line_len += grapheme_len;
21747            }
21748            WordBreakToken::InlineWhitespace {
21749                mut token,
21750                mut grapheme_len,
21751            } => {
21752                in_whitespace = true;
21753                if have_preceding_whitespace && !preserve_existing_whitespace {
21754                    continue;
21755                }
21756                if !preserve_existing_whitespace {
21757                    token = " ";
21758                    grapheme_len = 1;
21759                }
21760                let current_prefix_len = if is_first_line {
21761                    first_line_prefix_len
21762                } else {
21763                    subsequent_lines_prefix_len
21764                };
21765                if current_line_len + grapheme_len > wrap_column {
21766                    wrapped_text.push_str(current_line.trim_end());
21767                    wrapped_text.push('\n');
21768                    is_first_line = false;
21769                    current_line = subsequent_lines_prefix.clone();
21770                    current_line_len = subsequent_lines_prefix_len;
21771                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
21772                    current_line.push_str(token);
21773                    current_line_len += grapheme_len;
21774                }
21775            }
21776            WordBreakToken::Newline => {
21777                in_whitespace = true;
21778                let current_prefix_len = if is_first_line {
21779                    first_line_prefix_len
21780                } else {
21781                    subsequent_lines_prefix_len
21782                };
21783                if preserve_existing_whitespace {
21784                    wrapped_text.push_str(current_line.trim_end());
21785                    wrapped_text.push('\n');
21786                    is_first_line = false;
21787                    current_line = subsequent_lines_prefix.clone();
21788                    current_line_len = subsequent_lines_prefix_len;
21789                } else if have_preceding_whitespace {
21790                    continue;
21791                } else if current_line_len + 1 > wrap_column
21792                    && current_line_len != current_prefix_len
21793                {
21794                    wrapped_text.push_str(current_line.trim_end());
21795                    wrapped_text.push('\n');
21796                    is_first_line = false;
21797                    current_line = subsequent_lines_prefix.clone();
21798                    current_line_len = subsequent_lines_prefix_len;
21799                } else if current_line_len != current_prefix_len {
21800                    current_line.push(' ');
21801                    current_line_len += 1;
21802                }
21803            }
21804        }
21805    }
21806
21807    if !current_line.is_empty() {
21808        wrapped_text.push_str(&current_line);
21809    }
21810    wrapped_text
21811}
21812
21813#[test]
21814fn test_wrap_with_prefix() {
21815    assert_eq!(
21816        wrap_with_prefix(
21817            "# ".to_string(),
21818            "# ".to_string(),
21819            "abcdefg".to_string(),
21820            4,
21821            NonZeroU32::new(4).unwrap(),
21822            false,
21823        ),
21824        "# abcdefg"
21825    );
21826    assert_eq!(
21827        wrap_with_prefix(
21828            "".to_string(),
21829            "".to_string(),
21830            "\thello world".to_string(),
21831            8,
21832            NonZeroU32::new(4).unwrap(),
21833            false,
21834        ),
21835        "hello\nworld"
21836    );
21837    assert_eq!(
21838        wrap_with_prefix(
21839            "// ".to_string(),
21840            "// ".to_string(),
21841            "xx \nyy zz aa bb cc".to_string(),
21842            12,
21843            NonZeroU32::new(4).unwrap(),
21844            false,
21845        ),
21846        "// xx yy zz\n// aa bb cc"
21847    );
21848    assert_eq!(
21849        wrap_with_prefix(
21850            String::new(),
21851            String::new(),
21852            "这是什么 \n 钢笔".to_string(),
21853            3,
21854            NonZeroU32::new(4).unwrap(),
21855            false,
21856        ),
21857        "这是什\n么 钢\n"
21858    );
21859}
21860
21861pub trait CollaborationHub {
21862    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
21863    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
21864    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
21865}
21866
21867impl CollaborationHub for Entity<Project> {
21868    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
21869        self.read(cx).collaborators()
21870    }
21871
21872    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
21873        self.read(cx).user_store().read(cx).participant_indices()
21874    }
21875
21876    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
21877        let this = self.read(cx);
21878        let user_ids = this.collaborators().values().map(|c| c.user_id);
21879        this.user_store().read(cx).participant_names(user_ids, cx)
21880    }
21881}
21882
21883pub trait SemanticsProvider {
21884    fn hover(
21885        &self,
21886        buffer: &Entity<Buffer>,
21887        position: text::Anchor,
21888        cx: &mut App,
21889    ) -> Option<Task<Vec<project::Hover>>>;
21890
21891    fn inline_values(
21892        &self,
21893        buffer_handle: Entity<Buffer>,
21894        range: Range<text::Anchor>,
21895        cx: &mut App,
21896    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21897
21898    fn inlay_hints(
21899        &self,
21900        buffer_handle: Entity<Buffer>,
21901        range: Range<text::Anchor>,
21902        cx: &mut App,
21903    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
21904
21905    fn resolve_inlay_hint(
21906        &self,
21907        hint: InlayHint,
21908        buffer_handle: Entity<Buffer>,
21909        server_id: LanguageServerId,
21910        cx: &mut App,
21911    ) -> Option<Task<anyhow::Result<InlayHint>>>;
21912
21913    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
21914
21915    fn document_highlights(
21916        &self,
21917        buffer: &Entity<Buffer>,
21918        position: text::Anchor,
21919        cx: &mut App,
21920    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
21921
21922    fn definitions(
21923        &self,
21924        buffer: &Entity<Buffer>,
21925        position: text::Anchor,
21926        kind: GotoDefinitionKind,
21927        cx: &mut App,
21928    ) -> Option<Task<Result<Vec<LocationLink>>>>;
21929
21930    fn range_for_rename(
21931        &self,
21932        buffer: &Entity<Buffer>,
21933        position: text::Anchor,
21934        cx: &mut App,
21935    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
21936
21937    fn perform_rename(
21938        &self,
21939        buffer: &Entity<Buffer>,
21940        position: text::Anchor,
21941        new_name: String,
21942        cx: &mut App,
21943    ) -> Option<Task<Result<ProjectTransaction>>>;
21944}
21945
21946pub trait CompletionProvider {
21947    fn completions(
21948        &self,
21949        excerpt_id: ExcerptId,
21950        buffer: &Entity<Buffer>,
21951        buffer_position: text::Anchor,
21952        trigger: CompletionContext,
21953        window: &mut Window,
21954        cx: &mut Context<Editor>,
21955    ) -> Task<Result<Vec<CompletionResponse>>>;
21956
21957    fn resolve_completions(
21958        &self,
21959        _buffer: Entity<Buffer>,
21960        _completion_indices: Vec<usize>,
21961        _completions: Rc<RefCell<Box<[Completion]>>>,
21962        _cx: &mut Context<Editor>,
21963    ) -> Task<Result<bool>> {
21964        Task::ready(Ok(false))
21965    }
21966
21967    fn apply_additional_edits_for_completion(
21968        &self,
21969        _buffer: Entity<Buffer>,
21970        _completions: Rc<RefCell<Box<[Completion]>>>,
21971        _completion_index: usize,
21972        _push_to_history: bool,
21973        _cx: &mut Context<Editor>,
21974    ) -> Task<Result<Option<language::Transaction>>> {
21975        Task::ready(Ok(None))
21976    }
21977
21978    fn is_completion_trigger(
21979        &self,
21980        buffer: &Entity<Buffer>,
21981        position: language::Anchor,
21982        text: &str,
21983        trigger_in_words: bool,
21984        menu_is_open: bool,
21985        cx: &mut Context<Editor>,
21986    ) -> bool;
21987
21988    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
21989
21990    fn sort_completions(&self) -> bool {
21991        true
21992    }
21993
21994    fn filter_completions(&self) -> bool {
21995        true
21996    }
21997}
21998
21999pub trait CodeActionProvider {
22000    fn id(&self) -> Arc<str>;
22001
22002    fn code_actions(
22003        &self,
22004        buffer: &Entity<Buffer>,
22005        range: Range<text::Anchor>,
22006        window: &mut Window,
22007        cx: &mut App,
22008    ) -> Task<Result<Vec<CodeAction>>>;
22009
22010    fn apply_code_action(
22011        &self,
22012        buffer_handle: Entity<Buffer>,
22013        action: CodeAction,
22014        excerpt_id: ExcerptId,
22015        push_to_history: bool,
22016        window: &mut Window,
22017        cx: &mut App,
22018    ) -> Task<Result<ProjectTransaction>>;
22019}
22020
22021impl CodeActionProvider for Entity<Project> {
22022    fn id(&self) -> Arc<str> {
22023        "project".into()
22024    }
22025
22026    fn code_actions(
22027        &self,
22028        buffer: &Entity<Buffer>,
22029        range: Range<text::Anchor>,
22030        _window: &mut Window,
22031        cx: &mut App,
22032    ) -> Task<Result<Vec<CodeAction>>> {
22033        self.update(cx, |project, cx| {
22034            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22035            let code_actions = project.code_actions(buffer, range, None, cx);
22036            cx.background_spawn(async move {
22037                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22038                Ok(code_lens_actions
22039                    .context("code lens fetch")?
22040                    .into_iter()
22041                    .chain(code_actions.context("code action fetch")?)
22042                    .collect())
22043            })
22044        })
22045    }
22046
22047    fn apply_code_action(
22048        &self,
22049        buffer_handle: Entity<Buffer>,
22050        action: CodeAction,
22051        _excerpt_id: ExcerptId,
22052        push_to_history: bool,
22053        _window: &mut Window,
22054        cx: &mut App,
22055    ) -> Task<Result<ProjectTransaction>> {
22056        self.update(cx, |project, cx| {
22057            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22058        })
22059    }
22060}
22061
22062fn snippet_completions(
22063    project: &Project,
22064    buffer: &Entity<Buffer>,
22065    buffer_position: text::Anchor,
22066    cx: &mut App,
22067) -> Task<Result<CompletionResponse>> {
22068    let languages = buffer.read(cx).languages_at(buffer_position);
22069    let snippet_store = project.snippets().read(cx);
22070
22071    let scopes: Vec<_> = languages
22072        .iter()
22073        .filter_map(|language| {
22074            let language_name = language.lsp_id();
22075            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22076
22077            if snippets.is_empty() {
22078                None
22079            } else {
22080                Some((language.default_scope(), snippets))
22081            }
22082        })
22083        .collect();
22084
22085    if scopes.is_empty() {
22086        return Task::ready(Ok(CompletionResponse {
22087            completions: vec![],
22088            is_incomplete: false,
22089        }));
22090    }
22091
22092    let snapshot = buffer.read(cx).text_snapshot();
22093    let chars: String = snapshot
22094        .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
22095        .collect();
22096    let executor = cx.background_executor().clone();
22097
22098    cx.background_spawn(async move {
22099        let mut is_incomplete = false;
22100        let mut completions: Vec<Completion> = Vec::new();
22101        for (scope, snippets) in scopes.into_iter() {
22102            let classifier = CharClassifier::new(Some(scope)).for_completion(true);
22103            let mut last_word = chars
22104                .chars()
22105                .take_while(|c| classifier.is_word(*c))
22106                .collect::<String>();
22107            last_word = last_word.chars().rev().collect();
22108
22109            if last_word.is_empty() {
22110                return Ok(CompletionResponse {
22111                    completions: vec![],
22112                    is_incomplete: true,
22113                });
22114            }
22115
22116            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
22117            let to_lsp = |point: &text::Anchor| {
22118                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
22119                point_to_lsp(end)
22120            };
22121            let lsp_end = to_lsp(&buffer_position);
22122
22123            let candidates = snippets
22124                .iter()
22125                .enumerate()
22126                .flat_map(|(ix, snippet)| {
22127                    snippet
22128                        .prefix
22129                        .iter()
22130                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
22131                })
22132                .collect::<Vec<StringMatchCandidate>>();
22133
22134            const MAX_RESULTS: usize = 100;
22135            let mut matches = fuzzy::match_strings(
22136                &candidates,
22137                &last_word,
22138                last_word.chars().any(|c| c.is_uppercase()),
22139                true,
22140                MAX_RESULTS,
22141                &Default::default(),
22142                executor.clone(),
22143            )
22144            .await;
22145
22146            if matches.len() >= MAX_RESULTS {
22147                is_incomplete = true;
22148            }
22149
22150            // Remove all candidates where the query's start does not match the start of any word in the candidate
22151            if let Some(query_start) = last_word.chars().next() {
22152                matches.retain(|string_match| {
22153                    split_words(&string_match.string).any(|word| {
22154                        // Check that the first codepoint of the word as lowercase matches the first
22155                        // codepoint of the query as lowercase
22156                        word.chars()
22157                            .flat_map(|codepoint| codepoint.to_lowercase())
22158                            .zip(query_start.to_lowercase())
22159                            .all(|(word_cp, query_cp)| word_cp == query_cp)
22160                    })
22161                });
22162            }
22163
22164            let matched_strings = matches
22165                .into_iter()
22166                .map(|m| m.string)
22167                .collect::<HashSet<_>>();
22168
22169            completions.extend(snippets.iter().filter_map(|snippet| {
22170                let matching_prefix = snippet
22171                    .prefix
22172                    .iter()
22173                    .find(|prefix| matched_strings.contains(*prefix))?;
22174                let start = as_offset - last_word.len();
22175                let start = snapshot.anchor_before(start);
22176                let range = start..buffer_position;
22177                let lsp_start = to_lsp(&start);
22178                let lsp_range = lsp::Range {
22179                    start: lsp_start,
22180                    end: lsp_end,
22181                };
22182                Some(Completion {
22183                    replace_range: range,
22184                    new_text: snippet.body.clone(),
22185                    source: CompletionSource::Lsp {
22186                        insert_range: None,
22187                        server_id: LanguageServerId(usize::MAX),
22188                        resolved: true,
22189                        lsp_completion: Box::new(lsp::CompletionItem {
22190                            label: snippet.prefix.first().unwrap().clone(),
22191                            kind: Some(CompletionItemKind::SNIPPET),
22192                            label_details: snippet.description.as_ref().map(|description| {
22193                                lsp::CompletionItemLabelDetails {
22194                                    detail: Some(description.clone()),
22195                                    description: None,
22196                                }
22197                            }),
22198                            insert_text_format: Some(InsertTextFormat::SNIPPET),
22199                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
22200                                lsp::InsertReplaceEdit {
22201                                    new_text: snippet.body.clone(),
22202                                    insert: lsp_range,
22203                                    replace: lsp_range,
22204                                },
22205                            )),
22206                            filter_text: Some(snippet.body.clone()),
22207                            sort_text: Some(char::MAX.to_string()),
22208                            ..lsp::CompletionItem::default()
22209                        }),
22210                        lsp_defaults: None,
22211                    },
22212                    label: CodeLabel {
22213                        text: matching_prefix.clone(),
22214                        runs: Vec::new(),
22215                        filter_range: 0..matching_prefix.len(),
22216                    },
22217                    icon_path: None,
22218                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
22219                        single_line: snippet.name.clone().into(),
22220                        plain_text: snippet
22221                            .description
22222                            .clone()
22223                            .map(|description| description.into()),
22224                    }),
22225                    insert_text_mode: None,
22226                    confirm: None,
22227                })
22228            }))
22229        }
22230
22231        Ok(CompletionResponse {
22232            completions,
22233            is_incomplete,
22234        })
22235    })
22236}
22237
22238impl CompletionProvider for Entity<Project> {
22239    fn completions(
22240        &self,
22241        _excerpt_id: ExcerptId,
22242        buffer: &Entity<Buffer>,
22243        buffer_position: text::Anchor,
22244        options: CompletionContext,
22245        _window: &mut Window,
22246        cx: &mut Context<Editor>,
22247    ) -> Task<Result<Vec<CompletionResponse>>> {
22248        self.update(cx, |project, cx| {
22249            let snippets = snippet_completions(project, buffer, buffer_position, cx);
22250            let project_completions = project.completions(buffer, buffer_position, options, cx);
22251            cx.background_spawn(async move {
22252                let mut responses = project_completions.await?;
22253                let snippets = snippets.await?;
22254                if !snippets.completions.is_empty() {
22255                    responses.push(snippets);
22256                }
22257                Ok(responses)
22258            })
22259        })
22260    }
22261
22262    fn resolve_completions(
22263        &self,
22264        buffer: Entity<Buffer>,
22265        completion_indices: Vec<usize>,
22266        completions: Rc<RefCell<Box<[Completion]>>>,
22267        cx: &mut Context<Editor>,
22268    ) -> Task<Result<bool>> {
22269        self.update(cx, |project, cx| {
22270            project.lsp_store().update(cx, |lsp_store, cx| {
22271                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
22272            })
22273        })
22274    }
22275
22276    fn apply_additional_edits_for_completion(
22277        &self,
22278        buffer: Entity<Buffer>,
22279        completions: Rc<RefCell<Box<[Completion]>>>,
22280        completion_index: usize,
22281        push_to_history: bool,
22282        cx: &mut Context<Editor>,
22283    ) -> Task<Result<Option<language::Transaction>>> {
22284        self.update(cx, |project, cx| {
22285            project.lsp_store().update(cx, |lsp_store, cx| {
22286                lsp_store.apply_additional_edits_for_completion(
22287                    buffer,
22288                    completions,
22289                    completion_index,
22290                    push_to_history,
22291                    cx,
22292                )
22293            })
22294        })
22295    }
22296
22297    fn is_completion_trigger(
22298        &self,
22299        buffer: &Entity<Buffer>,
22300        position: language::Anchor,
22301        text: &str,
22302        trigger_in_words: bool,
22303        menu_is_open: bool,
22304        cx: &mut Context<Editor>,
22305    ) -> bool {
22306        let mut chars = text.chars();
22307        let char = if let Some(char) = chars.next() {
22308            char
22309        } else {
22310            return false;
22311        };
22312        if chars.next().is_some() {
22313            return false;
22314        }
22315
22316        let buffer = buffer.read(cx);
22317        let snapshot = buffer.snapshot();
22318        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
22319            return false;
22320        }
22321        let classifier = snapshot.char_classifier_at(position).for_completion(true);
22322        if trigger_in_words && classifier.is_word(char) {
22323            return true;
22324        }
22325
22326        buffer.completion_triggers().contains(text)
22327    }
22328}
22329
22330impl SemanticsProvider for Entity<Project> {
22331    fn hover(
22332        &self,
22333        buffer: &Entity<Buffer>,
22334        position: text::Anchor,
22335        cx: &mut App,
22336    ) -> Option<Task<Vec<project::Hover>>> {
22337        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
22338    }
22339
22340    fn document_highlights(
22341        &self,
22342        buffer: &Entity<Buffer>,
22343        position: text::Anchor,
22344        cx: &mut App,
22345    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
22346        Some(self.update(cx, |project, cx| {
22347            project.document_highlights(buffer, position, cx)
22348        }))
22349    }
22350
22351    fn definitions(
22352        &self,
22353        buffer: &Entity<Buffer>,
22354        position: text::Anchor,
22355        kind: GotoDefinitionKind,
22356        cx: &mut App,
22357    ) -> Option<Task<Result<Vec<LocationLink>>>> {
22358        Some(self.update(cx, |project, cx| match kind {
22359            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
22360            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
22361            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
22362            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
22363        }))
22364    }
22365
22366    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
22367        self.update(cx, |project, cx| {
22368            if project
22369                .active_debug_session(cx)
22370                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
22371            {
22372                return true;
22373            }
22374
22375            buffer.update(cx, |buffer, cx| {
22376                project.any_language_server_supports_inlay_hints(buffer, cx)
22377            })
22378        })
22379    }
22380
22381    fn inline_values(
22382        &self,
22383        buffer_handle: Entity<Buffer>,
22384        range: Range<text::Anchor>,
22385        cx: &mut App,
22386    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22387        self.update(cx, |project, cx| {
22388            let (session, active_stack_frame) = project.active_debug_session(cx)?;
22389
22390            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
22391        })
22392    }
22393
22394    fn inlay_hints(
22395        &self,
22396        buffer_handle: Entity<Buffer>,
22397        range: Range<text::Anchor>,
22398        cx: &mut App,
22399    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
22400        Some(self.update(cx, |project, cx| {
22401            project.inlay_hints(buffer_handle, range, cx)
22402        }))
22403    }
22404
22405    fn resolve_inlay_hint(
22406        &self,
22407        hint: InlayHint,
22408        buffer_handle: Entity<Buffer>,
22409        server_id: LanguageServerId,
22410        cx: &mut App,
22411    ) -> Option<Task<anyhow::Result<InlayHint>>> {
22412        Some(self.update(cx, |project, cx| {
22413            project.resolve_inlay_hint(hint, buffer_handle, server_id, cx)
22414        }))
22415    }
22416
22417    fn range_for_rename(
22418        &self,
22419        buffer: &Entity<Buffer>,
22420        position: text::Anchor,
22421        cx: &mut App,
22422    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
22423        Some(self.update(cx, |project, cx| {
22424            let buffer = buffer.clone();
22425            let task = project.prepare_rename(buffer.clone(), position, cx);
22426            cx.spawn(async move |_, cx| {
22427                Ok(match task.await? {
22428                    PrepareRenameResponse::Success(range) => Some(range),
22429                    PrepareRenameResponse::InvalidPosition => None,
22430                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
22431                        // Fallback on using TreeSitter info to determine identifier range
22432                        buffer.read_with(cx, |buffer, _| {
22433                            let snapshot = buffer.snapshot();
22434                            let (range, kind) = snapshot.surrounding_word(position, false);
22435                            if kind != Some(CharKind::Word) {
22436                                return None;
22437                            }
22438                            Some(
22439                                snapshot.anchor_before(range.start)
22440                                    ..snapshot.anchor_after(range.end),
22441                            )
22442                        })?
22443                    }
22444                })
22445            })
22446        }))
22447    }
22448
22449    fn perform_rename(
22450        &self,
22451        buffer: &Entity<Buffer>,
22452        position: text::Anchor,
22453        new_name: String,
22454        cx: &mut App,
22455    ) -> Option<Task<Result<ProjectTransaction>>> {
22456        Some(self.update(cx, |project, cx| {
22457            project.perform_rename(buffer.clone(), position, new_name, cx)
22458        }))
22459    }
22460}
22461
22462fn inlay_hint_settings(
22463    location: Anchor,
22464    snapshot: &MultiBufferSnapshot,
22465    cx: &mut Context<Editor>,
22466) -> InlayHintSettings {
22467    let file = snapshot.file_at(location);
22468    let language = snapshot.language_at(location).map(|l| l.name());
22469    language_settings(language, file, cx).inlay_hints
22470}
22471
22472fn consume_contiguous_rows(
22473    contiguous_row_selections: &mut Vec<Selection<Point>>,
22474    selection: &Selection<Point>,
22475    display_map: &DisplaySnapshot,
22476    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
22477) -> (MultiBufferRow, MultiBufferRow) {
22478    contiguous_row_selections.push(selection.clone());
22479    let start_row = starting_row(selection, display_map);
22480    let mut end_row = ending_row(selection, display_map);
22481
22482    while let Some(next_selection) = selections.peek() {
22483        if next_selection.start.row <= end_row.0 {
22484            end_row = ending_row(next_selection, display_map);
22485            contiguous_row_selections.push(selections.next().unwrap().clone());
22486        } else {
22487            break;
22488        }
22489    }
22490    (start_row, end_row)
22491}
22492
22493fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22494    if selection.start.column > 0 {
22495        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
22496    } else {
22497        MultiBufferRow(selection.start.row)
22498    }
22499}
22500
22501fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
22502    if next_selection.end.column > 0 || next_selection.is_empty() {
22503        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
22504    } else {
22505        MultiBufferRow(next_selection.end.row)
22506    }
22507}
22508
22509impl EditorSnapshot {
22510    pub fn remote_selections_in_range<'a>(
22511        &'a self,
22512        range: &'a Range<Anchor>,
22513        collaboration_hub: &dyn CollaborationHub,
22514        cx: &'a App,
22515    ) -> impl 'a + Iterator<Item = RemoteSelection> {
22516        let participant_names = collaboration_hub.user_names(cx);
22517        let participant_indices = collaboration_hub.user_participant_indices(cx);
22518        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
22519        let collaborators_by_replica_id = collaborators_by_peer_id
22520            .values()
22521            .map(|collaborator| (collaborator.replica_id, collaborator))
22522            .collect::<HashMap<_, _>>();
22523        self.buffer_snapshot
22524            .selections_in_range(range, false)
22525            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
22526                if replica_id == AGENT_REPLICA_ID {
22527                    Some(RemoteSelection {
22528                        replica_id,
22529                        selection,
22530                        cursor_shape,
22531                        line_mode,
22532                        collaborator_id: CollaboratorId::Agent,
22533                        user_name: Some("Agent".into()),
22534                        color: cx.theme().players().agent(),
22535                    })
22536                } else {
22537                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
22538                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
22539                    let user_name = participant_names.get(&collaborator.user_id).cloned();
22540                    Some(RemoteSelection {
22541                        replica_id,
22542                        selection,
22543                        cursor_shape,
22544                        line_mode,
22545                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
22546                        user_name,
22547                        color: if let Some(index) = participant_index {
22548                            cx.theme().players().color_for_participant(index.0)
22549                        } else {
22550                            cx.theme().players().absent()
22551                        },
22552                    })
22553                }
22554            })
22555    }
22556
22557    pub fn hunks_for_ranges(
22558        &self,
22559        ranges: impl IntoIterator<Item = Range<Point>>,
22560    ) -> Vec<MultiBufferDiffHunk> {
22561        let mut hunks = Vec::new();
22562        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
22563            HashMap::default();
22564        for query_range in ranges {
22565            let query_rows =
22566                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
22567            for hunk in self.buffer_snapshot.diff_hunks_in_range(
22568                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
22569            ) {
22570                // Include deleted hunks that are adjacent to the query range, because
22571                // otherwise they would be missed.
22572                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
22573                if hunk.status().is_deleted() {
22574                    intersects_range |= hunk.row_range.start == query_rows.end;
22575                    intersects_range |= hunk.row_range.end == query_rows.start;
22576                }
22577                if intersects_range {
22578                    if !processed_buffer_rows
22579                        .entry(hunk.buffer_id)
22580                        .or_default()
22581                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
22582                    {
22583                        continue;
22584                    }
22585                    hunks.push(hunk);
22586                }
22587            }
22588        }
22589
22590        hunks
22591    }
22592
22593    fn display_diff_hunks_for_rows<'a>(
22594        &'a self,
22595        display_rows: Range<DisplayRow>,
22596        folded_buffers: &'a HashSet<BufferId>,
22597    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
22598        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
22599        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
22600
22601        self.buffer_snapshot
22602            .diff_hunks_in_range(buffer_start..buffer_end)
22603            .filter_map(|hunk| {
22604                if folded_buffers.contains(&hunk.buffer_id) {
22605                    return None;
22606                }
22607
22608                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
22609                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
22610
22611                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
22612                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
22613
22614                let display_hunk = if hunk_display_start.column() != 0 {
22615                    DisplayDiffHunk::Folded {
22616                        display_row: hunk_display_start.row(),
22617                    }
22618                } else {
22619                    let mut end_row = hunk_display_end.row();
22620                    if hunk_display_end.column() > 0 {
22621                        end_row.0 += 1;
22622                    }
22623                    let is_created_file = hunk.is_created_file();
22624                    DisplayDiffHunk::Unfolded {
22625                        status: hunk.status(),
22626                        diff_base_byte_range: hunk.diff_base_byte_range,
22627                        display_row_range: hunk_display_start.row()..end_row,
22628                        multi_buffer_range: Anchor::range_in_buffer(
22629                            hunk.excerpt_id,
22630                            hunk.buffer_id,
22631                            hunk.buffer_range,
22632                        ),
22633                        is_created_file,
22634                    }
22635                };
22636
22637                Some(display_hunk)
22638            })
22639    }
22640
22641    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
22642        self.display_snapshot.buffer_snapshot.language_at(position)
22643    }
22644
22645    pub fn is_focused(&self) -> bool {
22646        self.is_focused
22647    }
22648
22649    pub fn placeholder_text(&self) -> Option<&Arc<str>> {
22650        self.placeholder_text.as_ref()
22651    }
22652
22653    pub fn scroll_position(&self) -> gpui::Point<f32> {
22654        self.scroll_anchor.scroll_position(&self.display_snapshot)
22655    }
22656
22657    fn gutter_dimensions(
22658        &self,
22659        font_id: FontId,
22660        font_size: Pixels,
22661        max_line_number_width: Pixels,
22662        cx: &App,
22663    ) -> Option<GutterDimensions> {
22664        if !self.show_gutter {
22665            return None;
22666        }
22667
22668        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
22669        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
22670
22671        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
22672            matches!(
22673                ProjectSettings::get_global(cx).git.git_gutter,
22674                Some(GitGutterSetting::TrackedFiles)
22675            )
22676        });
22677        let gutter_settings = EditorSettings::get_global(cx).gutter;
22678        let show_line_numbers = self
22679            .show_line_numbers
22680            .unwrap_or(gutter_settings.line_numbers);
22681        let line_gutter_width = if show_line_numbers {
22682            // Avoid flicker-like gutter resizes when the line number gains another digit by
22683            // only resizing the gutter on files with > 10**min_line_number_digits lines.
22684            let min_width_for_number_on_gutter =
22685                ch_advance * gutter_settings.min_line_number_digits as f32;
22686            max_line_number_width.max(min_width_for_number_on_gutter)
22687        } else {
22688            0.0.into()
22689        };
22690
22691        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
22692        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
22693
22694        let git_blame_entries_width =
22695            self.git_blame_gutter_max_author_length
22696                .map(|max_author_length| {
22697                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22698                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
22699
22700                    /// The number of characters to dedicate to gaps and margins.
22701                    const SPACING_WIDTH: usize = 4;
22702
22703                    let max_char_count = max_author_length.min(renderer.max_author_length())
22704                        + ::git::SHORT_SHA_LENGTH
22705                        + MAX_RELATIVE_TIMESTAMP.len()
22706                        + SPACING_WIDTH;
22707
22708                    ch_advance * max_char_count
22709                });
22710
22711        let is_singleton = self.buffer_snapshot.is_singleton();
22712
22713        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
22714        left_padding += if !is_singleton {
22715            ch_width * 4.0
22716        } else if show_runnables || show_breakpoints {
22717            ch_width * 3.0
22718        } else if show_git_gutter && show_line_numbers {
22719            ch_width * 2.0
22720        } else if show_git_gutter || show_line_numbers {
22721            ch_width
22722        } else {
22723            px(0.)
22724        };
22725
22726        let shows_folds = is_singleton && gutter_settings.folds;
22727
22728        let right_padding = if shows_folds && show_line_numbers {
22729            ch_width * 4.0
22730        } else if shows_folds || (!is_singleton && show_line_numbers) {
22731            ch_width * 3.0
22732        } else if show_line_numbers {
22733            ch_width
22734        } else {
22735            px(0.)
22736        };
22737
22738        Some(GutterDimensions {
22739            left_padding,
22740            right_padding,
22741            width: line_gutter_width + left_padding + right_padding,
22742            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
22743            git_blame_entries_width,
22744        })
22745    }
22746
22747    pub fn render_crease_toggle(
22748        &self,
22749        buffer_row: MultiBufferRow,
22750        row_contains_cursor: bool,
22751        editor: Entity<Editor>,
22752        window: &mut Window,
22753        cx: &mut App,
22754    ) -> Option<AnyElement> {
22755        let folded = self.is_line_folded(buffer_row);
22756        let mut is_foldable = false;
22757
22758        if let Some(crease) = self
22759            .crease_snapshot
22760            .query_row(buffer_row, &self.buffer_snapshot)
22761        {
22762            is_foldable = true;
22763            match crease {
22764                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
22765                    if let Some(render_toggle) = render_toggle {
22766                        let toggle_callback =
22767                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
22768                                if folded {
22769                                    editor.update(cx, |editor, cx| {
22770                                        editor.fold_at(buffer_row, window, cx)
22771                                    });
22772                                } else {
22773                                    editor.update(cx, |editor, cx| {
22774                                        editor.unfold_at(buffer_row, window, cx)
22775                                    });
22776                                }
22777                            });
22778                        return Some((render_toggle)(
22779                            buffer_row,
22780                            folded,
22781                            toggle_callback,
22782                            window,
22783                            cx,
22784                        ));
22785                    }
22786                }
22787            }
22788        }
22789
22790        is_foldable |= self.starts_indent(buffer_row);
22791
22792        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
22793            Some(
22794                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
22795                    .toggle_state(folded)
22796                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
22797                        if folded {
22798                            this.unfold_at(buffer_row, window, cx);
22799                        } else {
22800                            this.fold_at(buffer_row, window, cx);
22801                        }
22802                    }))
22803                    .into_any_element(),
22804            )
22805        } else {
22806            None
22807        }
22808    }
22809
22810    pub fn render_crease_trailer(
22811        &self,
22812        buffer_row: MultiBufferRow,
22813        window: &mut Window,
22814        cx: &mut App,
22815    ) -> Option<AnyElement> {
22816        let folded = self.is_line_folded(buffer_row);
22817        if let Crease::Inline { render_trailer, .. } = self
22818            .crease_snapshot
22819            .query_row(buffer_row, &self.buffer_snapshot)?
22820        {
22821            let render_trailer = render_trailer.as_ref()?;
22822            Some(render_trailer(buffer_row, folded, window, cx))
22823        } else {
22824            None
22825        }
22826    }
22827}
22828
22829impl Deref for EditorSnapshot {
22830    type Target = DisplaySnapshot;
22831
22832    fn deref(&self) -> &Self::Target {
22833        &self.display_snapshot
22834    }
22835}
22836
22837#[derive(Clone, Debug, PartialEq, Eq)]
22838pub enum EditorEvent {
22839    InputIgnored {
22840        text: Arc<str>,
22841    },
22842    InputHandled {
22843        utf16_range_to_replace: Option<Range<isize>>,
22844        text: Arc<str>,
22845    },
22846    ExcerptsAdded {
22847        buffer: Entity<Buffer>,
22848        predecessor: ExcerptId,
22849        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
22850    },
22851    ExcerptsRemoved {
22852        ids: Vec<ExcerptId>,
22853        removed_buffer_ids: Vec<BufferId>,
22854    },
22855    BufferFoldToggled {
22856        ids: Vec<ExcerptId>,
22857        folded: bool,
22858    },
22859    ExcerptsEdited {
22860        ids: Vec<ExcerptId>,
22861    },
22862    ExcerptsExpanded {
22863        ids: Vec<ExcerptId>,
22864    },
22865    BufferEdited,
22866    Edited {
22867        transaction_id: clock::Lamport,
22868    },
22869    Reparsed(BufferId),
22870    Focused,
22871    FocusedIn,
22872    Blurred,
22873    DirtyChanged,
22874    Saved,
22875    TitleChanged,
22876    DiffBaseChanged,
22877    SelectionsChanged {
22878        local: bool,
22879    },
22880    ScrollPositionChanged {
22881        local: bool,
22882        autoscroll: bool,
22883    },
22884    Closed,
22885    TransactionUndone {
22886        transaction_id: clock::Lamport,
22887    },
22888    TransactionBegun {
22889        transaction_id: clock::Lamport,
22890    },
22891    Reloaded,
22892    CursorShapeChanged,
22893    BreadcrumbsChanged,
22894    PushedToNavHistory {
22895        anchor: Anchor,
22896        is_deactivate: bool,
22897    },
22898}
22899
22900impl EventEmitter<EditorEvent> for Editor {}
22901
22902impl Focusable for Editor {
22903    fn focus_handle(&self, _cx: &App) -> FocusHandle {
22904        self.focus_handle.clone()
22905    }
22906}
22907
22908impl Render for Editor {
22909    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
22910        let settings = ThemeSettings::get_global(cx);
22911
22912        let mut text_style = match self.mode {
22913            EditorMode::SingleLine { .. } | EditorMode::AutoHeight { .. } => TextStyle {
22914                color: cx.theme().colors().editor_foreground,
22915                font_family: settings.ui_font.family.clone(),
22916                font_features: settings.ui_font.features.clone(),
22917                font_fallbacks: settings.ui_font.fallbacks.clone(),
22918                font_size: rems(0.875).into(),
22919                font_weight: settings.ui_font.weight,
22920                line_height: relative(settings.buffer_line_height.value()),
22921                ..Default::default()
22922            },
22923            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
22924                color: cx.theme().colors().editor_foreground,
22925                font_family: settings.buffer_font.family.clone(),
22926                font_features: settings.buffer_font.features.clone(),
22927                font_fallbacks: settings.buffer_font.fallbacks.clone(),
22928                font_size: settings.buffer_font_size(cx).into(),
22929                font_weight: settings.buffer_font.weight,
22930                line_height: relative(settings.buffer_line_height.value()),
22931                ..Default::default()
22932            },
22933        };
22934        if let Some(text_style_refinement) = &self.text_style_refinement {
22935            text_style.refine(text_style_refinement)
22936        }
22937
22938        let background = match self.mode {
22939            EditorMode::SingleLine { .. } => cx.theme().system().transparent,
22940            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
22941            EditorMode::Full { .. } => cx.theme().colors().editor_background,
22942            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
22943        };
22944
22945        EditorElement::new(
22946            &cx.entity(),
22947            EditorStyle {
22948                background,
22949                border: cx.theme().colors().border,
22950                local_player: cx.theme().players().local(),
22951                text: text_style,
22952                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
22953                syntax: cx.theme().syntax().clone(),
22954                status: cx.theme().status().clone(),
22955                inlay_hints_style: make_inlay_hints_style(cx),
22956                edit_prediction_styles: make_suggestion_styles(cx),
22957                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
22958                show_underlines: self.diagnostics_enabled(),
22959            },
22960        )
22961    }
22962}
22963
22964impl EntityInputHandler for Editor {
22965    fn text_for_range(
22966        &mut self,
22967        range_utf16: Range<usize>,
22968        adjusted_range: &mut Option<Range<usize>>,
22969        _: &mut Window,
22970        cx: &mut Context<Self>,
22971    ) -> Option<String> {
22972        let snapshot = self.buffer.read(cx).read(cx);
22973        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
22974        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
22975        if (start.0..end.0) != range_utf16 {
22976            adjusted_range.replace(start.0..end.0);
22977        }
22978        Some(snapshot.text_for_range(start..end).collect())
22979    }
22980
22981    fn selected_text_range(
22982        &mut self,
22983        ignore_disabled_input: bool,
22984        _: &mut Window,
22985        cx: &mut Context<Self>,
22986    ) -> Option<UTF16Selection> {
22987        // Prevent the IME menu from appearing when holding down an alphabetic key
22988        // while input is disabled.
22989        if !ignore_disabled_input && !self.input_enabled {
22990            return None;
22991        }
22992
22993        let selection = self.selections.newest::<OffsetUtf16>(cx);
22994        let range = selection.range();
22995
22996        Some(UTF16Selection {
22997            range: range.start.0..range.end.0,
22998            reversed: selection.reversed,
22999        })
23000    }
23001
23002    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23003        let snapshot = self.buffer.read(cx).read(cx);
23004        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23005        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23006    }
23007
23008    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23009        self.clear_highlights::<InputComposition>(cx);
23010        self.ime_transaction.take();
23011    }
23012
23013    fn replace_text_in_range(
23014        &mut self,
23015        range_utf16: Option<Range<usize>>,
23016        text: &str,
23017        window: &mut Window,
23018        cx: &mut Context<Self>,
23019    ) {
23020        if !self.input_enabled {
23021            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23022            return;
23023        }
23024
23025        self.transact(window, cx, |this, window, cx| {
23026            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23027                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23028                Some(this.selection_replacement_ranges(range_utf16, cx))
23029            } else {
23030                this.marked_text_ranges(cx)
23031            };
23032
23033            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23034                let newest_selection_id = this.selections.newest_anchor().id;
23035                this.selections
23036                    .all::<OffsetUtf16>(cx)
23037                    .iter()
23038                    .zip(ranges_to_replace.iter())
23039                    .find_map(|(selection, range)| {
23040                        if selection.id == newest_selection_id {
23041                            Some(
23042                                (range.start.0 as isize - selection.head().0 as isize)
23043                                    ..(range.end.0 as isize - selection.head().0 as isize),
23044                            )
23045                        } else {
23046                            None
23047                        }
23048                    })
23049            });
23050
23051            cx.emit(EditorEvent::InputHandled {
23052                utf16_range_to_replace: range_to_replace,
23053                text: text.into(),
23054            });
23055
23056            if let Some(new_selected_ranges) = new_selected_ranges {
23057                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23058                    selections.select_ranges(new_selected_ranges)
23059                });
23060                this.backspace(&Default::default(), window, cx);
23061            }
23062
23063            this.handle_input(text, window, cx);
23064        });
23065
23066        if let Some(transaction) = self.ime_transaction {
23067            self.buffer.update(cx, |buffer, cx| {
23068                buffer.group_until_transaction(transaction, cx);
23069            });
23070        }
23071
23072        self.unmark_text(window, cx);
23073    }
23074
23075    fn replace_and_mark_text_in_range(
23076        &mut self,
23077        range_utf16: Option<Range<usize>>,
23078        text: &str,
23079        new_selected_range_utf16: Option<Range<usize>>,
23080        window: &mut Window,
23081        cx: &mut Context<Self>,
23082    ) {
23083        if !self.input_enabled {
23084            return;
23085        }
23086
23087        let transaction = self.transact(window, cx, |this, window, cx| {
23088            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
23089                let snapshot = this.buffer.read(cx).read(cx);
23090                if let Some(relative_range_utf16) = range_utf16.as_ref() {
23091                    for marked_range in &mut marked_ranges {
23092                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
23093                        marked_range.start.0 += relative_range_utf16.start;
23094                        marked_range.start =
23095                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
23096                        marked_range.end =
23097                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
23098                    }
23099                }
23100                Some(marked_ranges)
23101            } else if let Some(range_utf16) = range_utf16 {
23102                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23103                Some(this.selection_replacement_ranges(range_utf16, cx))
23104            } else {
23105                None
23106            };
23107
23108            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
23109                let newest_selection_id = this.selections.newest_anchor().id;
23110                this.selections
23111                    .all::<OffsetUtf16>(cx)
23112                    .iter()
23113                    .zip(ranges_to_replace.iter())
23114                    .find_map(|(selection, range)| {
23115                        if selection.id == newest_selection_id {
23116                            Some(
23117                                (range.start.0 as isize - selection.head().0 as isize)
23118                                    ..(range.end.0 as isize - selection.head().0 as isize),
23119                            )
23120                        } else {
23121                            None
23122                        }
23123                    })
23124            });
23125
23126            cx.emit(EditorEvent::InputHandled {
23127                utf16_range_to_replace: range_to_replace,
23128                text: text.into(),
23129            });
23130
23131            if let Some(ranges) = ranges_to_replace {
23132                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23133                    s.select_ranges(ranges)
23134                });
23135            }
23136
23137            let marked_ranges = {
23138                let snapshot = this.buffer.read(cx).read(cx);
23139                this.selections
23140                    .disjoint_anchors()
23141                    .iter()
23142                    .map(|selection| {
23143                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
23144                    })
23145                    .collect::<Vec<_>>()
23146            };
23147
23148            if text.is_empty() {
23149                this.unmark_text(window, cx);
23150            } else {
23151                this.highlight_text::<InputComposition>(
23152                    marked_ranges.clone(),
23153                    HighlightStyle {
23154                        underline: Some(UnderlineStyle {
23155                            thickness: px(1.),
23156                            color: None,
23157                            wavy: false,
23158                        }),
23159                        ..Default::default()
23160                    },
23161                    cx,
23162                );
23163            }
23164
23165            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
23166            let use_autoclose = this.use_autoclose;
23167            let use_auto_surround = this.use_auto_surround;
23168            this.set_use_autoclose(false);
23169            this.set_use_auto_surround(false);
23170            this.handle_input(text, window, cx);
23171            this.set_use_autoclose(use_autoclose);
23172            this.set_use_auto_surround(use_auto_surround);
23173
23174            if let Some(new_selected_range) = new_selected_range_utf16 {
23175                let snapshot = this.buffer.read(cx).read(cx);
23176                let new_selected_ranges = marked_ranges
23177                    .into_iter()
23178                    .map(|marked_range| {
23179                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
23180                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
23181                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
23182                        snapshot.clip_offset_utf16(new_start, Bias::Left)
23183                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
23184                    })
23185                    .collect::<Vec<_>>();
23186
23187                drop(snapshot);
23188                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23189                    selections.select_ranges(new_selected_ranges)
23190                });
23191            }
23192        });
23193
23194        self.ime_transaction = self.ime_transaction.or(transaction);
23195        if let Some(transaction) = self.ime_transaction {
23196            self.buffer.update(cx, |buffer, cx| {
23197                buffer.group_until_transaction(transaction, cx);
23198            });
23199        }
23200
23201        if self.text_highlights::<InputComposition>(cx).is_none() {
23202            self.ime_transaction.take();
23203        }
23204    }
23205
23206    fn bounds_for_range(
23207        &mut self,
23208        range_utf16: Range<usize>,
23209        element_bounds: gpui::Bounds<Pixels>,
23210        window: &mut Window,
23211        cx: &mut Context<Self>,
23212    ) -> Option<gpui::Bounds<Pixels>> {
23213        let text_layout_details = self.text_layout_details(window);
23214        let CharacterDimensions {
23215            em_width,
23216            em_advance,
23217            line_height,
23218        } = self.character_dimensions(window);
23219
23220        let snapshot = self.snapshot(window, cx);
23221        let scroll_position = snapshot.scroll_position();
23222        let scroll_left = scroll_position.x * em_advance;
23223
23224        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
23225        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
23226            + self.gutter_dimensions.full_width();
23227        let y = line_height * (start.row().as_f32() - scroll_position.y);
23228
23229        Some(Bounds {
23230            origin: element_bounds.origin + point(x, y),
23231            size: size(em_width, line_height),
23232        })
23233    }
23234
23235    fn character_index_for_point(
23236        &mut self,
23237        point: gpui::Point<Pixels>,
23238        _window: &mut Window,
23239        _cx: &mut Context<Self>,
23240    ) -> Option<usize> {
23241        let position_map = self.last_position_map.as_ref()?;
23242        if !position_map.text_hitbox.contains(&point) {
23243            return None;
23244        }
23245        let display_point = position_map.point_for_position(point).previous_valid;
23246        let anchor = position_map
23247            .snapshot
23248            .display_point_to_anchor(display_point, Bias::Left);
23249        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot);
23250        Some(utf16_offset.0)
23251    }
23252}
23253
23254trait SelectionExt {
23255    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
23256    fn spanned_rows(
23257        &self,
23258        include_end_if_at_line_start: bool,
23259        map: &DisplaySnapshot,
23260    ) -> Range<MultiBufferRow>;
23261}
23262
23263impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
23264    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
23265        let start = self
23266            .start
23267            .to_point(&map.buffer_snapshot)
23268            .to_display_point(map);
23269        let end = self
23270            .end
23271            .to_point(&map.buffer_snapshot)
23272            .to_display_point(map);
23273        if self.reversed {
23274            end..start
23275        } else {
23276            start..end
23277        }
23278    }
23279
23280    fn spanned_rows(
23281        &self,
23282        include_end_if_at_line_start: bool,
23283        map: &DisplaySnapshot,
23284    ) -> Range<MultiBufferRow> {
23285        let start = self.start.to_point(&map.buffer_snapshot);
23286        let mut end = self.end.to_point(&map.buffer_snapshot);
23287        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
23288            end.row -= 1;
23289        }
23290
23291        let buffer_start = map.prev_line_boundary(start).0;
23292        let buffer_end = map.next_line_boundary(end).0;
23293        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
23294    }
23295}
23296
23297impl<T: InvalidationRegion> InvalidationStack<T> {
23298    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
23299    where
23300        S: Clone + ToOffset,
23301    {
23302        while let Some(region) = self.last() {
23303            let all_selections_inside_invalidation_ranges =
23304                if selections.len() == region.ranges().len() {
23305                    selections
23306                        .iter()
23307                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
23308                        .all(|(selection, invalidation_range)| {
23309                            let head = selection.head().to_offset(buffer);
23310                            invalidation_range.start <= head && invalidation_range.end >= head
23311                        })
23312                } else {
23313                    false
23314                };
23315
23316            if all_selections_inside_invalidation_ranges {
23317                break;
23318            } else {
23319                self.pop();
23320            }
23321        }
23322    }
23323}
23324
23325impl<T> Default for InvalidationStack<T> {
23326    fn default() -> Self {
23327        Self(Default::default())
23328    }
23329}
23330
23331impl<T> Deref for InvalidationStack<T> {
23332    type Target = Vec<T>;
23333
23334    fn deref(&self) -> &Self::Target {
23335        &self.0
23336    }
23337}
23338
23339impl<T> DerefMut for InvalidationStack<T> {
23340    fn deref_mut(&mut self) -> &mut Self::Target {
23341        &mut self.0
23342    }
23343}
23344
23345impl InvalidationRegion for SnippetState {
23346    fn ranges(&self) -> &[Range<Anchor>] {
23347        &self.ranges[self.active_index]
23348    }
23349}
23350
23351fn edit_prediction_edit_text(
23352    current_snapshot: &BufferSnapshot,
23353    edits: &[(Range<Anchor>, String)],
23354    edit_preview: &EditPreview,
23355    include_deletions: bool,
23356    cx: &App,
23357) -> HighlightedText {
23358    let edits = edits
23359        .iter()
23360        .map(|(anchor, text)| {
23361            (
23362                anchor.start.text_anchor..anchor.end.text_anchor,
23363                text.clone(),
23364            )
23365        })
23366        .collect::<Vec<_>>();
23367
23368    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
23369}
23370
23371fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
23372    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
23373    // Just show the raw edit text with basic styling
23374    let mut text = String::new();
23375    let mut highlights = Vec::new();
23376
23377    let insertion_highlight_style = HighlightStyle {
23378        color: Some(cx.theme().colors().text),
23379        ..Default::default()
23380    };
23381
23382    for (_, edit_text) in edits {
23383        let start_offset = text.len();
23384        text.push_str(edit_text);
23385        let end_offset = text.len();
23386
23387        if start_offset < end_offset {
23388            highlights.push((start_offset..end_offset, insertion_highlight_style));
23389        }
23390    }
23391
23392    HighlightedText {
23393        text: text.into(),
23394        highlights,
23395    }
23396}
23397
23398pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
23399    match severity {
23400        lsp::DiagnosticSeverity::ERROR => colors.error,
23401        lsp::DiagnosticSeverity::WARNING => colors.warning,
23402        lsp::DiagnosticSeverity::INFORMATION => colors.info,
23403        lsp::DiagnosticSeverity::HINT => colors.info,
23404        _ => colors.ignored,
23405    }
23406}
23407
23408pub fn styled_runs_for_code_label<'a>(
23409    label: &'a CodeLabel,
23410    syntax_theme: &'a theme::SyntaxTheme,
23411) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
23412    let fade_out = HighlightStyle {
23413        fade_out: Some(0.35),
23414        ..Default::default()
23415    };
23416
23417    let mut prev_end = label.filter_range.end;
23418    label
23419        .runs
23420        .iter()
23421        .enumerate()
23422        .flat_map(move |(ix, (range, highlight_id))| {
23423            let style = if let Some(style) = highlight_id.style(syntax_theme) {
23424                style
23425            } else {
23426                return Default::default();
23427            };
23428            let mut muted_style = style;
23429            muted_style.highlight(fade_out);
23430
23431            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
23432            if range.start >= label.filter_range.end {
23433                if range.start > prev_end {
23434                    runs.push((prev_end..range.start, fade_out));
23435                }
23436                runs.push((range.clone(), muted_style));
23437            } else if range.end <= label.filter_range.end {
23438                runs.push((range.clone(), style));
23439            } else {
23440                runs.push((range.start..label.filter_range.end, style));
23441                runs.push((label.filter_range.end..range.end, muted_style));
23442            }
23443            prev_end = cmp::max(prev_end, range.end);
23444
23445            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
23446                runs.push((prev_end..label.text.len(), fade_out));
23447            }
23448
23449            runs
23450        })
23451}
23452
23453pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
23454    let mut prev_index = 0;
23455    let mut prev_codepoint: Option<char> = None;
23456    text.char_indices()
23457        .chain([(text.len(), '\0')])
23458        .filter_map(move |(index, codepoint)| {
23459            let prev_codepoint = prev_codepoint.replace(codepoint)?;
23460            let is_boundary = index == text.len()
23461                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
23462                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
23463            if is_boundary {
23464                let chunk = &text[prev_index..index];
23465                prev_index = index;
23466                Some(chunk)
23467            } else {
23468                None
23469            }
23470        })
23471}
23472
23473pub trait RangeToAnchorExt: Sized {
23474    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
23475
23476    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
23477        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot);
23478        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
23479    }
23480}
23481
23482impl<T: ToOffset> RangeToAnchorExt for Range<T> {
23483    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
23484        let start_offset = self.start.to_offset(snapshot);
23485        let end_offset = self.end.to_offset(snapshot);
23486        if start_offset == end_offset {
23487            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
23488        } else {
23489            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
23490        }
23491    }
23492}
23493
23494pub trait RowExt {
23495    fn as_f32(&self) -> f32;
23496
23497    fn next_row(&self) -> Self;
23498
23499    fn previous_row(&self) -> Self;
23500
23501    fn minus(&self, other: Self) -> u32;
23502}
23503
23504impl RowExt for DisplayRow {
23505    fn as_f32(&self) -> f32 {
23506        self.0 as f32
23507    }
23508
23509    fn next_row(&self) -> Self {
23510        Self(self.0 + 1)
23511    }
23512
23513    fn previous_row(&self) -> Self {
23514        Self(self.0.saturating_sub(1))
23515    }
23516
23517    fn minus(&self, other: Self) -> u32 {
23518        self.0 - other.0
23519    }
23520}
23521
23522impl RowExt for MultiBufferRow {
23523    fn as_f32(&self) -> f32 {
23524        self.0 as f32
23525    }
23526
23527    fn next_row(&self) -> Self {
23528        Self(self.0 + 1)
23529    }
23530
23531    fn previous_row(&self) -> Self {
23532        Self(self.0.saturating_sub(1))
23533    }
23534
23535    fn minus(&self, other: Self) -> u32 {
23536        self.0 - other.0
23537    }
23538}
23539
23540trait RowRangeExt {
23541    type Row;
23542
23543    fn len(&self) -> usize;
23544
23545    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
23546}
23547
23548impl RowRangeExt for Range<MultiBufferRow> {
23549    type Row = MultiBufferRow;
23550
23551    fn len(&self) -> usize {
23552        (self.end.0 - self.start.0) as usize
23553    }
23554
23555    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
23556        (self.start.0..self.end.0).map(MultiBufferRow)
23557    }
23558}
23559
23560impl RowRangeExt for Range<DisplayRow> {
23561    type Row = DisplayRow;
23562
23563    fn len(&self) -> usize {
23564        (self.end.0 - self.start.0) as usize
23565    }
23566
23567    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
23568        (self.start.0..self.end.0).map(DisplayRow)
23569    }
23570}
23571
23572/// If select range has more than one line, we
23573/// just point the cursor to range.start.
23574fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
23575    if range.start.row == range.end.row {
23576        range
23577    } else {
23578        range.start..range.start
23579    }
23580}
23581pub struct KillRing(ClipboardItem);
23582impl Global for KillRing {}
23583
23584const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
23585
23586enum BreakpointPromptEditAction {
23587    Log,
23588    Condition,
23589    HitCondition,
23590}
23591
23592struct BreakpointPromptEditor {
23593    pub(crate) prompt: Entity<Editor>,
23594    editor: WeakEntity<Editor>,
23595    breakpoint_anchor: Anchor,
23596    breakpoint: Breakpoint,
23597    edit_action: BreakpointPromptEditAction,
23598    block_ids: HashSet<CustomBlockId>,
23599    editor_margins: Arc<Mutex<EditorMargins>>,
23600    _subscriptions: Vec<Subscription>,
23601}
23602
23603impl BreakpointPromptEditor {
23604    const MAX_LINES: u8 = 4;
23605
23606    fn new(
23607        editor: WeakEntity<Editor>,
23608        breakpoint_anchor: Anchor,
23609        breakpoint: Breakpoint,
23610        edit_action: BreakpointPromptEditAction,
23611        window: &mut Window,
23612        cx: &mut Context<Self>,
23613    ) -> Self {
23614        let base_text = match edit_action {
23615            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
23616            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
23617            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
23618        }
23619        .map(|msg| msg.to_string())
23620        .unwrap_or_default();
23621
23622        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
23623        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
23624
23625        let prompt = cx.new(|cx| {
23626            let mut prompt = Editor::new(
23627                EditorMode::AutoHeight {
23628                    min_lines: 1,
23629                    max_lines: Some(Self::MAX_LINES as usize),
23630                },
23631                buffer,
23632                None,
23633                window,
23634                cx,
23635            );
23636            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
23637            prompt.set_show_cursor_when_unfocused(false, cx);
23638            prompt.set_placeholder_text(
23639                match edit_action {
23640                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
23641                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
23642                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
23643                },
23644                cx,
23645            );
23646
23647            prompt
23648        });
23649
23650        Self {
23651            prompt,
23652            editor,
23653            breakpoint_anchor,
23654            breakpoint,
23655            edit_action,
23656            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
23657            block_ids: Default::default(),
23658            _subscriptions: vec![],
23659        }
23660    }
23661
23662    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
23663        self.block_ids.extend(block_ids)
23664    }
23665
23666    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
23667        if let Some(editor) = self.editor.upgrade() {
23668            let message = self
23669                .prompt
23670                .read(cx)
23671                .buffer
23672                .read(cx)
23673                .as_singleton()
23674                .expect("A multi buffer in breakpoint prompt isn't possible")
23675                .read(cx)
23676                .as_rope()
23677                .to_string();
23678
23679            editor.update(cx, |editor, cx| {
23680                editor.edit_breakpoint_at_anchor(
23681                    self.breakpoint_anchor,
23682                    self.breakpoint.clone(),
23683                    match self.edit_action {
23684                        BreakpointPromptEditAction::Log => {
23685                            BreakpointEditAction::EditLogMessage(message.into())
23686                        }
23687                        BreakpointPromptEditAction::Condition => {
23688                            BreakpointEditAction::EditCondition(message.into())
23689                        }
23690                        BreakpointPromptEditAction::HitCondition => {
23691                            BreakpointEditAction::EditHitCondition(message.into())
23692                        }
23693                    },
23694                    cx,
23695                );
23696
23697                editor.remove_blocks(self.block_ids.clone(), None, cx);
23698                cx.focus_self(window);
23699            });
23700        }
23701    }
23702
23703    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
23704        self.editor
23705            .update(cx, |editor, cx| {
23706                editor.remove_blocks(self.block_ids.clone(), None, cx);
23707                window.focus(&editor.focus_handle);
23708            })
23709            .log_err();
23710    }
23711
23712    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
23713        let settings = ThemeSettings::get_global(cx);
23714        let text_style = TextStyle {
23715            color: if self.prompt.read(cx).read_only(cx) {
23716                cx.theme().colors().text_disabled
23717            } else {
23718                cx.theme().colors().text
23719            },
23720            font_family: settings.buffer_font.family.clone(),
23721            font_fallbacks: settings.buffer_font.fallbacks.clone(),
23722            font_size: settings.buffer_font_size(cx).into(),
23723            font_weight: settings.buffer_font.weight,
23724            line_height: relative(settings.buffer_line_height.value()),
23725            ..Default::default()
23726        };
23727        EditorElement::new(
23728            &self.prompt,
23729            EditorStyle {
23730                background: cx.theme().colors().editor_background,
23731                local_player: cx.theme().players().local(),
23732                text: text_style,
23733                ..Default::default()
23734            },
23735        )
23736    }
23737}
23738
23739impl Render for BreakpointPromptEditor {
23740    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23741        let editor_margins = *self.editor_margins.lock();
23742        let gutter_dimensions = editor_margins.gutter;
23743        h_flex()
23744            .key_context("Editor")
23745            .bg(cx.theme().colors().editor_background)
23746            .border_y_1()
23747            .border_color(cx.theme().status().info_border)
23748            .size_full()
23749            .py(window.line_height() / 2.5)
23750            .on_action(cx.listener(Self::confirm))
23751            .on_action(cx.listener(Self::cancel))
23752            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
23753            .child(div().flex_1().child(self.render_prompt_editor(cx)))
23754    }
23755}
23756
23757impl Focusable for BreakpointPromptEditor {
23758    fn focus_handle(&self, cx: &App) -> FocusHandle {
23759        self.prompt.focus_handle(cx)
23760    }
23761}
23762
23763fn all_edits_insertions_or_deletions(
23764    edits: &Vec<(Range<Anchor>, String)>,
23765    snapshot: &MultiBufferSnapshot,
23766) -> bool {
23767    let mut all_insertions = true;
23768    let mut all_deletions = true;
23769
23770    for (range, new_text) in edits.iter() {
23771        let range_is_empty = range.to_offset(snapshot).is_empty();
23772        let text_is_empty = new_text.is_empty();
23773
23774        if range_is_empty != text_is_empty {
23775            if range_is_empty {
23776                all_deletions = false;
23777            } else {
23778                all_insertions = false;
23779            }
23780        } else {
23781            return false;
23782        }
23783
23784        if !all_insertions && !all_deletions {
23785            return false;
23786        }
23787    }
23788    all_insertions || all_deletions
23789}
23790
23791struct MissingEditPredictionKeybindingTooltip;
23792
23793impl Render for MissingEditPredictionKeybindingTooltip {
23794    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23795        ui::tooltip_container(window, cx, |container, _, cx| {
23796            container
23797                .flex_shrink_0()
23798                .max_w_80()
23799                .min_h(rems_from_px(124.))
23800                .justify_between()
23801                .child(
23802                    v_flex()
23803                        .flex_1()
23804                        .text_ui_sm(cx)
23805                        .child(Label::new("Conflict with Accept Keybinding"))
23806                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
23807                )
23808                .child(
23809                    h_flex()
23810                        .pb_1()
23811                        .gap_1()
23812                        .items_end()
23813                        .w_full()
23814                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
23815                            window.dispatch_action(zed_actions::OpenKeymap.boxed_clone(), cx)
23816                        }))
23817                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
23818                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
23819                        })),
23820                )
23821        })
23822    }
23823}
23824
23825#[derive(Debug, Clone, Copy, PartialEq)]
23826pub struct LineHighlight {
23827    pub background: Background,
23828    pub border: Option<gpui::Hsla>,
23829    pub include_gutter: bool,
23830    pub type_id: Option<TypeId>,
23831}
23832
23833struct LineManipulationResult {
23834    pub new_text: String,
23835    pub line_count_before: usize,
23836    pub line_count_after: usize,
23837}
23838
23839fn render_diff_hunk_controls(
23840    row: u32,
23841    status: &DiffHunkStatus,
23842    hunk_range: Range<Anchor>,
23843    is_created_file: bool,
23844    line_height: Pixels,
23845    editor: &Entity<Editor>,
23846    _window: &mut Window,
23847    cx: &mut App,
23848) -> AnyElement {
23849    h_flex()
23850        .h(line_height)
23851        .mr_1()
23852        .gap_1()
23853        .px_0p5()
23854        .pb_1()
23855        .border_x_1()
23856        .border_b_1()
23857        .border_color(cx.theme().colors().border_variant)
23858        .rounded_b_lg()
23859        .bg(cx.theme().colors().editor_background)
23860        .gap_1()
23861        .block_mouse_except_scroll()
23862        .shadow_md()
23863        .child(if status.has_secondary_hunk() {
23864            Button::new(("stage", row as u64), "Stage")
23865                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23866                .tooltip({
23867                    let focus_handle = editor.focus_handle(cx);
23868                    move |window, cx| {
23869                        Tooltip::for_action_in(
23870                            "Stage Hunk",
23871                            &::git::ToggleStaged,
23872                            &focus_handle,
23873                            window,
23874                            cx,
23875                        )
23876                    }
23877                })
23878                .on_click({
23879                    let editor = editor.clone();
23880                    move |_event, _window, cx| {
23881                        editor.update(cx, |editor, cx| {
23882                            editor.stage_or_unstage_diff_hunks(
23883                                true,
23884                                vec![hunk_range.start..hunk_range.start],
23885                                cx,
23886                            );
23887                        });
23888                    }
23889                })
23890        } else {
23891            Button::new(("unstage", row as u64), "Unstage")
23892                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
23893                .tooltip({
23894                    let focus_handle = editor.focus_handle(cx);
23895                    move |window, cx| {
23896                        Tooltip::for_action_in(
23897                            "Unstage Hunk",
23898                            &::git::ToggleStaged,
23899                            &focus_handle,
23900                            window,
23901                            cx,
23902                        )
23903                    }
23904                })
23905                .on_click({
23906                    let editor = editor.clone();
23907                    move |_event, _window, cx| {
23908                        editor.update(cx, |editor, cx| {
23909                            editor.stage_or_unstage_diff_hunks(
23910                                false,
23911                                vec![hunk_range.start..hunk_range.start],
23912                                cx,
23913                            );
23914                        });
23915                    }
23916                })
23917        })
23918        .child(
23919            Button::new(("restore", row as u64), "Restore")
23920                .tooltip({
23921                    let focus_handle = editor.focus_handle(cx);
23922                    move |window, cx| {
23923                        Tooltip::for_action_in(
23924                            "Restore Hunk",
23925                            &::git::Restore,
23926                            &focus_handle,
23927                            window,
23928                            cx,
23929                        )
23930                    }
23931                })
23932                .on_click({
23933                    let editor = editor.clone();
23934                    move |_event, window, cx| {
23935                        editor.update(cx, |editor, cx| {
23936                            let snapshot = editor.snapshot(window, cx);
23937                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot);
23938                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
23939                        });
23940                    }
23941                })
23942                .disabled(is_created_file),
23943        )
23944        .when(
23945            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
23946            |el| {
23947                el.child(
23948                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
23949                        .shape(IconButtonShape::Square)
23950                        .icon_size(IconSize::Small)
23951                        // .disabled(!has_multiple_hunks)
23952                        .tooltip({
23953                            let focus_handle = editor.focus_handle(cx);
23954                            move |window, cx| {
23955                                Tooltip::for_action_in(
23956                                    "Next Hunk",
23957                                    &GoToHunk,
23958                                    &focus_handle,
23959                                    window,
23960                                    cx,
23961                                )
23962                            }
23963                        })
23964                        .on_click({
23965                            let editor = editor.clone();
23966                            move |_event, window, cx| {
23967                                editor.update(cx, |editor, cx| {
23968                                    let snapshot = editor.snapshot(window, cx);
23969                                    let position =
23970                                        hunk_range.end.to_point(&snapshot.buffer_snapshot);
23971                                    editor.go_to_hunk_before_or_after_position(
23972                                        &snapshot,
23973                                        position,
23974                                        Direction::Next,
23975                                        window,
23976                                        cx,
23977                                    );
23978                                    editor.expand_selected_diff_hunks(cx);
23979                                });
23980                            }
23981                        }),
23982                )
23983                .child(
23984                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
23985                        .shape(IconButtonShape::Square)
23986                        .icon_size(IconSize::Small)
23987                        // .disabled(!has_multiple_hunks)
23988                        .tooltip({
23989                            let focus_handle = editor.focus_handle(cx);
23990                            move |window, cx| {
23991                                Tooltip::for_action_in(
23992                                    "Previous Hunk",
23993                                    &GoToPreviousHunk,
23994                                    &focus_handle,
23995                                    window,
23996                                    cx,
23997                                )
23998                            }
23999                        })
24000                        .on_click({
24001                            let editor = editor.clone();
24002                            move |_event, window, cx| {
24003                                editor.update(cx, |editor, cx| {
24004                                    let snapshot = editor.snapshot(window, cx);
24005                                    let point =
24006                                        hunk_range.start.to_point(&snapshot.buffer_snapshot);
24007                                    editor.go_to_hunk_before_or_after_position(
24008                                        &snapshot,
24009                                        point,
24010                                        Direction::Prev,
24011                                        window,
24012                                        cx,
24013                                    );
24014                                    editor.expand_selected_diff_hunks(cx);
24015                                });
24016                            }
24017                        }),
24018                )
24019            },
24020        )
24021        .into_any_element()
24022}